具有部分模式空间隐藏的非分词方法:

具有部分模式空间隐藏的非分词方法:

我正在尝试替换模式并清理包含多个单词的文件以获得每行一个单词。

使用以下命令行可以获得结果:

sed -e '/^[[:space:]]*$/ d' \             # remove empty line
    -e 's/^[[:space:]]*//' \              # remove white space at the beginning
    -e 's/[[:space:]]*$//' \              # remove white space at the ending (EOL)
    -e 's/[[:space:]][[:space:]]*/\n/g' \ # convert blanks between words to newline
    -e '$a\'                              # add a newline if missing at EOF
    -e .....                              # replace other patterns.

(最后一个表达式出现在如何在文件末尾添加换行符?

这个想法是只用一个小的 sed 程序来处理文件(例如替换某些模式)并同时格式化文件。

我确信可以使用其他 sed 功能来减少表达式。

问候

答案1

您可以使用tr

tr -s "[[:blank:]]" "\n" < file | grep .

字符[:blank:]类包括所有水平空白。将出现的多个字符压缩-s或减少为一个。

删除grep空行(如果存在)。

答案2

尝试这个

sed -e 's/[[:space:]]/\n/g' | grep -v '^$'

它同时使用grepsed,但我希望它没问题(如果您有sed系统,通常grep也有)

答案3

不是 sed,但是:

gawk length RS='[[:space:]]+' file

它将任何空白序列视为记录分隔符,并打印每个非空记录。

答案4

由于 OP 似乎坚持使用 的“单次调用” sed,因此以下是一个:

具有部分模式空间隐藏的非分词方法:

sed -n -e 's/^\W*//' -e 's/\(\W\+\)/\n/gp' words.txt

编辑:请注意,正如 @don_crissti 所指出的,这个解决方案并不完整,因为它无法首先打印出单独出现在一行中的单词,也无法在输出的最后插入换行符,如果文件缺少终止换行符。要解决此问题,请参阅以下极其丑陋的解决方案。

主要问题sed是每个表达式运行的模式空间-e总是由线定义。如果插入换行符,从而更改第一个表达式和下一个表达式之间的行结构,则下一个表达式将无法在处理后的数据上运行。

解释:

  • 首先,每行处理前导空格(如果有)。那些完全由它组成的行将变成空行,同时仍然保持模式空间的行长度。

  • 第二部分的关键是-n选项和p(打印)命令的组合,有些人喜欢称之为sed“grep 模式”,基本上效果是只打印匹配和/或更改的行。 -n防止打印任何输出,并p强制打印匹配和/或更改的行。这样,您就可以避免打印完全空白的行。既然\W\+预计最后一个非单词字符,空行被排除。本来可以与表达式匹配的前导空格之前已变成空行。

  • 编辑:我忘了解释缺少第一个表达式中命令的p含义也是关键。在每个表达式上,模式空间通常都会被打印,这使得我们看到每行的次数与打印它的表达式的次数一样多,如果这些表达式中的任何一个也更改了给定的行,则会出现变化。然而,即使没有打印模式空间,它也会以更改后的形式传递到后续表达式,从而允许我们链接在源自一个输入行的单个管道上运行的表达式,同时只能看到最后一个表达式的输出。

如果您喜欢将单词视为非空白字符的序列,那么......它们是,但该定义包含的内容远不止单词。这些不是单词,而是非空白序列。但是,如果您想匹配这些并将它们打印在单独的行而不是单词上,请使用:

sed -n -e 's/^\s*//' -e 's/\(\s\+\)/\n/gp' words.txt

零字节替换方法

编辑:@don_crissti 指出的带有单个单词的行和 EOF 上缺少换行符的问题可以通过以下命令解决。虽然不是太长,但除了它是可笑的 hacky 之外,它至少有一个我知道的缺陷:即它不适用于只有一行的文件,如果该行有多个单词。解决这个问题的一个想法是添加分支来检查最后一行是否是第一行,这使程序更加复杂(并且花费了我更多的时间:D)。这是命令:

sed -rn 's/(\b|\W)+/\x0/g; s/^\x0//; s/\x0$//; s/\x0/\n/g; /^$/d; $! p; $ { s/$/\n/; P }'

解释:

该命令在以下过程中起作用:

  • 首先,非单词字符以及单词边界(例如行的结尾和开头)(它们是零宽度断言,而不是字符)将被零字节替换。这还包括单词边界及其相邻的非单词字符序列(它们出现在这些位置)。

  • 然后,从每行的开头和结尾删除零字节。

  • 然后,每个中间的零字节都被换行符替换。

  • 任何生成的空行都会从模式空间中删除。此时不存在纯空白行。

  • 如果当前模式空间的地址不是最后一个地址(即,我们不在最后一行),我们只需打印该行。

  • 在数据结束时,我们执行 2 个命令:

    • 我们在当前模式空间的末尾添加一个换行符,以至少有 1 个终止换行符,即使原始数据没有以一个换行符结尾。

    • 我们只打印当前模式空间中的第一个嵌入换行符,该空间最多有 2 个换行符。

顺便说一句,我见过的这个问题最简单的解决方案是:

grep -o '\w\+' words.txt

或者,如果您不需要处理以空格开头的行:

fmt -1 words.txt

相关内容