我在试着删除课文中重复的单词。在这些文章中描述的相同问题:Remove duplicate words in a line with sed和me:Removing duplicate strings with SED,但是这些变体对我不起作用。可能是因为我用的是GnuWin32
例如,我需要什么样的结果:
输入
One two three bird animal two bird输出
One two three bird animal发布于 2019-12-22 16:15:42
工具sed并不是为这项工作而设计的。sed只有两种形式的内存,模式空间和保持空间,这只不过是两个简单的字符串,它可以记住。每次对这样的内存块执行操作时,都必须重写整个内存块并对其进行重新分析。另一方面,Awk在这里具有更大的灵活性,并且可以更容易地操作所涉及的行。
awk '{delete s}
{for(i=1;i<=NF;++i) if(!(s[$i]++)) printf (i==1?"":OFS)"%s",$i}
{printf ORS}' file但既然你在windows机器上工作,这也意味着你有CRLF的终端机。这可能会给最后一个条目带来轻微的问题。如果这一行是:
foo bar fooawk会把它解读为
foo bar foo\r因此,由于CR,最后一个foo将与第一个foo不匹配。
现在更正如下:
awk 'BEGIN{RS=ORS="\r\n"}
{delete s}
{for(i=1;i<=NF;++i) if(!(s[$i]++)) printf (i==1?"":OFS)"%s",$i}
{printf ORS}' file这可以使用,因为您使用的是CygWin,它是在GNU的末尾,所以我们可以使用RS的扩展作为正则值或多字符值。
如果您想要区分大小写,可以用s[$i]替换s[tolower($i)]。
像这样的句子还是有问题的
"There was a horse in the bar, it ran out of the bar."单词bar在这里可以匹配,但是,和.使得它不匹配。解决这一问题的办法是:
awk 'BEGIN{RS=ORS="\r\n"; ere="[,.?:;\042\047]"}
{delete s}
{for(i=1;i<=NF;++i) {
key=tolower($i); sub("^" ere,"",key); sub(ere "$","",key)
if(!(s[key]++)) printf (i==1?"":OFS)"%s",$i
}
}
{printf ORS}' file这在本质上也是如此,但是去掉了单词开头和结尾处的标点符号。标点符号在ere中列出
发布于 2019-12-18 18:07:12
我认为这在awk中会快得多。
这应该适用于任何平台,但我还没有在Windows上验证它:
awk '{
sp = "";
delete seen;
for (i=1; i<=NF; i++) if (!seen[$i]++) { printf "%s%s", sp, $i; sp = " "; }
printf "\n";
}' file(你可以把它压缩到一条线上,这样就行了。)
AWK在柱状数据方面非常出色。默认情况下,它将每一行的文本划分为由连续空格分隔的字段(因此,给定hello world,我们得到了$1 = "hello"和$2 = "world")。特殊的NF变量是它找到的字段数,因此for (i=1; i<=NF; i++)在每个字段(word)上迭代为值为$i的i。
这里我使用的是关联数组(也称为字典或散列)。索引seen (当前单词)处的$i数组开始为零(未初始化)。我们增加它,但是就像C一样,awk使用x++来增量x,但返回它的原始值(与++x不同,++x增加并返回增量的值)。因此,当我们还没有在这个词中增加数组时,!seen[$i]++就是真(!0) --这对我们来说是新的。seen在每一行都被清除,所以我们每一行都有唯一的单词,而不是整个文件。
我们知道我们还没看过,所以我们得把它打印出来。注意,单词之间的原始空格丢失了(它没有存储在任何地方)。我们只打印一个空格(但不是在新行的开头,因此是sp变量),然后再打印新单词。
在for循环之后,我们完成行。永远不会有任何尾随的空间。(另外,实际的行尾也丢失了,所以我们假设它是\n。如果您想要DOS行的结尾,请使用\r\n。)
发布于 2019-12-09 12:04:31
这可能对您有用(GNU sed):
sed -E ':a;s/\<((\S+)\>.*)\s\<\2\>/\1/gi;ta' file匹配任何单词并删除前面的空白及其副本。重复一遍。
注:雷杰普不考虑情况而移除重复项。如果要将One单独处理为one,请使用:
sed -E ':a;s/\<((\S+)\>.*)\s\<\2\>/\1/g;ta' filehttps://stackoverflow.com/questions/59245359
复制相似问题