22

我有一个带有单词的纯文本文件,用逗号分隔,例如:

word1, word2, word3, word2, word4, word5, word 3, word6, word7, word3

我想删除重复项并成为:

word1, word2, word3, word4, word5, word6, word7

有任何想法吗?我认为, egrep 可以帮助我,但我不确定,如何准确地使用它......

4

10 回答 10

33

假设单词是每行一个,并且文件已经排序:

uniq filename

如果文件未排序:

sort filename | uniq

如果它们不是每行一个,并且您不介意它们是每行一个:

tr -s [:space:] \\n < filename | sort | uniq

但是,这并没有删除标点符号,所以也许你想要:

tr -s [:space:][:punct:] \\n < filename | sort | uniq

但这会从带连字符的单词中删除连字符。“man tr”获取更多选项。

于 2009-06-04T18:30:04.270 回答
3

ruby -pi.bak -e '$_.split(",").uniq.join(",")' filename?

我承认这两种引用是丑陋的。

于 2009-06-04T18:33:44.513 回答
2

这是一个 awk 脚本,它将保留每一行,只删除重复的单词:

BEGIN { 
     FS=", " 
} 
{ 
    for (i=1; i <= NF; i++) 
        used[$i] = 1
    for (x in used)
        printf "%s, ",x
    printf "\n"
    split("", used)
} 
于 2009-06-04T19:09:30.603 回答
2

多亏了 ,创建一个唯一的列表非常容易uniq,尽管大多数 Unix 命令喜欢每行一个条目而不是逗号分隔的列表,所以我们必须首先将其转换为:

$ sed 's/, /\n/g' filename | sort | uniq
word1
word2
word3
word4
word5
word6
word7

更难的部分是用逗号作为分隔符而不是终止符再次将其放在一行中。我使用 perl one-liner 来做到这一点,但如果有人有更惯用的东西,请编辑我。:)

$ sed 's/, /\n/g' filename | sort | uniq | perl -e '@a = <>; chomp @a; print((join ", ", @a), "\n")'
word1, word2, word3, word4, word5, word6, word7
于 2009-06-04T18:49:56.320 回答
2

我今天遇到了同样的问题.. 一个包含 238,000 个单词的单词列表,但其中大约 40,000 个是重复的。我已经通过这样做将它们放在单独的行中

cat filename | tr " " "\n" | sort 

删除我只是做的重复项

cat filename | uniq > newfilename .

完美无误,现在我的文件从 1.45MB 减少到 1.01MB

于 2012-05-21T13:28:01.527 回答
1

我想你会想用换行符替换空格,使用uniq命令查找唯一行,然后再次用空格替换换行符。

于 2009-06-04T18:29:54.613 回答
1

我假设您希望单词在一行上是唯一的,而不是在整个文件中。如果是这种情况,那么下面的 Perl 脚本就可以解决问题。

while (<DATA>)
{
    chomp;
    my %seen = ();
    my @words = split(m!,\s*!);
    @words = grep { $seen{$_} ? 0 : ($seen{$_} = 1) } @words;
    print join(", ", @words), "\n";
}

__DATA__
word1, word2, word3, word2, word4, word5, word3, word6, word7, word3

如果您想要整个文件的唯一性,您可以将%seen散列移到while (){}循环之外。

于 2009-06-04T18:45:02.180 回答
1

在尝试解决几乎相同的问题时遇到了这个线程。我已经连接了几个包含密码的文件,所以自然有很多双打。此外,许多非标准字符。我真的不需要对它们进行排序,但似乎这对于 uniq 来说是必要的。

我试过了:

sort /Users/me/Documents/file.txt | uniq -u
sort: string comparison failed: Illegal byte sequence
sort: Set LC_ALL='C' to work around the problem.
sort: The strings compared were `t\203tonnement' and `t\203tonner'

试过:

sort -u /Users/me/Documents/file.txt >> /Users/me/Documents/file2.txt
sort: string comparison failed: Illegal byte sequence
sort: Set LC_ALL='C' to work around the problem.
sort: The strings compared were `t\203tonnement' and `t\203tonner'.

甚至尝试先通过 cat 传递它,这样我才能看看我们是否得到了正确的输入。

cat /Users/me/Documents/file.txt | sort | uniq -u > /Users/me/Documents/file2.txt
sort: string comparison failed: Illegal byte sequence
sort: Set LC_ALL='C' to work around the problem.
sort: The strings compared were `zon\351s' and `zoologie'.

我不确定发生了什么。在文件中找不到字符串“t\203tonnement”和“t\203tonner”,但找到了“t/203”和“tonnement”,但在单独的、不相邻的行上。与“zon\351s”相同。

最终对我有用的是:

awk '!x[$0]++' /Users/me/Documents/file.txt > /Users/me/Documents/file2.txt

它还保留了唯一不同是大小写的单词,这正是我想要的。我不需要对列表进行排序,所以它不是很好。

于 2011-07-19T00:39:09.783 回答
0

如果您也有兴趣计算单词数,请不要忘记实用程序的-c选项。uniq

于 2009-06-04T18:54:56.997 回答
0

使用 vim ( ) 打开文件vim filename并使用唯一标志 ( :sort u) 运行排序命令。

于 2017-05-24T07:30:43.203 回答