web-dev-qa-db-ja.com

Linuxコマンドを使用してプレーンテキストファイルから重複する単語を削除する方法

たとえば、コンマで区切られた単語を含むプレーンテキストファイルがあります。

Word1, Word2, Word3, Word2, Word4, Word5, Word 3, Word6, Word7, Word3

重複を削除して次のようになりたい:

Word1, Word2, Word3, Word4, Word5, Word6, Word7

何か案は? egrepが役立つと思いますが、正確に使用する方法はわかりません。

21
cupakob

単語が1行に1つあり、ファイルがすでにソートされていると仮定します。

uniq filename

ファイルがソートされていない場合:

sort filename | uniq

1行に1つではなく、1行に1つでも構わない場合:

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

ただし、句読点が削除されるわけではないので、必要な場合があります。

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

ただし、ハイフン付きの単語からハイフンが削除されます。その他のオプションについては、「man tr」。

32
Randy Orrison

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

2種類の引用は醜いと認めます。

3
Oliver N.

一意のリストの作成はuniqのおかげで非常に簡単ですが、ほとんどのUnixコマンドは、コンマ区切りのリストではなく、1行に1つのエントリを入力するので、まず次のように変換する必要があります。

$ sed 's/, /\n/g' filename | sort | uniq
Word1
Word2
Word3
Word4
Word5
Word6
Word7

難しいのは、これを改行記号としてターミネーターではなくコンマを付けて1行に配置することです。私はこれを行うためにPerlワンライナーを使用しましたが、誰かがもっと慣用的なものを持っている場合は、私を編集してください。 :)

$ sed 's/, /\n/g' filename | sort | uniq | Perl -e '@a = <>; chomp @a; print((join ", ", @a), "\n")'
Word1, Word2, Word3, Word4, Word5, Word6, Word7
2
Ryan Bright

次のawkスクリプトは、各行をそのままにして、重複する単語のみを削除します。

BEGIN { 
     FS=", " 
} 
{ 
    for (i=1; i <= NF; i++) 
        used[$i] = 1
    for (x in used)
        printf "%s, ",x
    printf "\n"
    split("", used)
} 
2
mamboking

今日も同じ問題がありました。238,000語の単語リストですが、そのうちの約4万語が重複しています。私はすでに個別のラインでそれらを持っていました

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

重複を削除するために、私は単にしました

cat filename | uniq > newfilename .

エラーはまったく発生せず、ファイルは1.45MBから1.01MBに減少しました

2
Biffinum

ファイル全体ではなく、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 (){}ループの外に移動するだけです。

1
Beano

ほぼ同じ問題を解決しようとしているときに、このスレッドに出くわしました。私はパスワードを含むいくつかのファイルを連結したので、当然のことながら多くのダブルスがありました。また、多くの非標準文字。私は本当にそれらをソートする必要はありませんでしたが、それは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 /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

また、大文字小文字のみが異なる単語も保存されました。リストを並べ替える必要がなかったので、並べ替えなくても問題ありませんでした。

1
sudon't

スペースを改行に置き換え、 niq コマンドを使用して一意の行を検索し、改行をスペースに再度置き換えたいと思います。

1
Paul Sonier

また、単語の数も取得したい場合は、uniqユーティリティの-cオプションを忘れないでください。

0
Rob Wells

vim(vim filename)と一意のフラグ(:sort u)。

0
meysam