我在试着删除文本中的重复单词。这些文章中描述的相同问题:Remove duplicate words in a line with sed和:Removing duplicate strings with SED但是这些变体对我不起作用。可能是因为我使用GnuWin32
例如我需要的结果:
输入
One two three bird animal two bird
输出
One two three bird animal
我在试着删除文本中的重复单词。这些文章中描述的相同问题:Remove duplicate words in a line with sed和:Removing duplicate strings with SED但是这些变体对我不起作用。可能是因为我使用GnuWin32
例如我需要的结果:
输入
One two three bird animal two bird
输出
One two three bird animal
4条答案
按热度按时间nr9pn0ug1#
我认为这将是 * 远 * 更快的awk。
这应该可以在任何平台上工作,但我没有在Windows上验证过:
(Feel自由地将其压缩到一条线上,它会工作得很好。)
AWK在列式数据方面非常出色。默认情况下,它将每行的文本划分为由白色分隔的字段(因此给定
hello world
,我们得到$1 = "hello"
和$2 = "world"
)。特殊的NF
变量是它找到的字段的数量,所以for (i=1; i<=NF; i++)
迭代每个字段(单词),作为值为$i
的i
。我在这里使用了一个关联数组(也称为字典或哈希)。索引
$i
(当前字)处的seen
数组从零开始(未初始化)。我们递增它,但就像C一样,awk使用x++
递增x
,但返回其原始值(与++x
相反,它递增并返回递增后的值)。因此,!seen[$i]++
是true(!0
),当我们还没有在这个字处递增数组时,它对我们来说是新的。seen
在每一行都被清除,所以我们每行都有唯一的字,而不是整个文件。既然我们还没看过,我们就得印出来。注意,单词之间的原始白色将丢失(它不会存储在任何地方)。我们只打印一个空格(但不是在新行的开头,因此是
sp
变量),然后是新单词。在for循环之后,我们完成了行。永远不会有任何尾随空格。(另外,实际的行尾丢失了,所以我们假设它是
\n
。如果你想要DOS行结束符,使用\r\n
。nbewdwxp2#
工具
sed
并不是为这项工作而设计的。sed只有两种形式的内存,模式空间和保持空间,它们只不过是它可以记住的两个简单字符串。每次你在这样的内存块上做一个操作,你必须重写整个内存块并重新分析它。另一方面,Awk在这里有更大的灵活性,可以更容易地操作有问题的行。但由于你在windows机器上工作,这也意味着你有CRLF行结束符。这可能会对最后一个条目产生轻微的问题。如果该行为:
awk会把它读成
因此由于CR,最后的foo将不匹配第一个foo。
更正如下:
这可以使用,因为你使用CygWin,它在最后的GNU中,所以我们可以使用
RS
的扩展名作为正则表达式或多字符值。如果你想区分大小写,你可以用
s[tolower($i)]
代替s[$i]
。还有一些句子
单词
bar
可以在这里匹配,但是,
和.
使它不匹配。这可以通过以下方式解决:这基本上是相同的,但删除了单词开头和结尾的标点符号。标点符号列在
ere
中efzxgjgh3#
这可能对你有用(GNU sed):
匹配任何单词并删除前面白色及其重复项。重复。
注意:正则表达式删除重复项时不考虑大小写。如果要将
One
与one
分开处理,请用途:y1aodyip4#
对于可能包含- / '等的唯一单词(其中
\<
和\>
将打断' word ',例如内核命令行中的选项):1.在输入字符串前后填充空格,
" $string "
如下string=$(sed -E ':a;s/(\s(\S+)\s.*)\2\s/\1/;ta' <<< " $string ")
1.拆下衬垫
string=${string# }; string=${string% }