このテキストの中に含まれる単語を何らかの方法で集計し
リンゴ
スイカ
カモメ
メダカ
カモメ
メジロ
ロジック
クリスマス
スイカ カジキ
キンメダイ
イカ カモメ
メダカ
カジキ
↓
リンゴ→1
スイカ→1
カモメ→2
メダカ→2
メジロ→1
ロジック→1
クリスマス→1
スイカ カジキ→1
キンメダイ→1
イカ カモメ→1
カジキ→1
というふうに、同じ単語が何個あったのかを把握したいと考えています。
ただしこれを実現する際の必須条件として、
「リンゴ」や「スイカ」など、こちらでひとつづつ単語を指定して集計することなく、
自動的に同じ単語を集計し、一覧として出力出来るものであって下さい。
なお可能であれば
・出力される結果は同じ単語が多い順に並べる。
・「スイカ カジキ」というスペースで区切られた単語を「スイカ」「カジキ」と個別の単語として認識し集計する。
などが出来ればうれしいです。
こちらの環境はOS:Vista、エクセル所有、レンタルサーバcoreserverが使えます。
結果が出力される形式は問いませんが、あまり複雑な手順でないことを望んでおります。
WSH である JavaScript での例です。
(1)下記を WordCount.js(ファイル名は自由:拡張子はjs) というファイル名で保存してください。
(2)計測するデータを data.txt(ファイル名は自由:拡張子はtxt) というファイル名で保存してください。
(3)data.txt を WordCount.js にドラッグ&ドロップしてください。
これで結果が表示されると共に data.csv が作成されますので、EXCEL 等で開いてください。
var fso = new ActiveXObject("Scripting.FileSystemObject"); var dic = new ActiveXObject("Scripting.Dictionary"); var infile = fso.OpenTextFile( WScript.Arguments(0) ); var c = 0; var lines = new Array(); while( !infile.AtEndOfStream ) lines[c++] = infile.ReadLine(); for( var line in lines ) { var words = lines[line].split( " " ); for( var word in words ) { if ( dic.Exists( words[word] ) == false ) dic.Add( words[word], 1 ); else dic.Item(words[word]) = dic.Item(words[word]) + 1; } } var keys = ( new VBArray( dic.Keys())).toArray(); var cnts = new Array(); for ( key in keys ) { cnts[key] = dic( keys[key]); } var tmp; for( var i=0 ; i<keys.length ; i++ ) { for( var j=i+1 ; j< keys.length ; j++ ) { if ( cnts[i] < cnts[j] ) { tmp = keys[i]; keys[i] = keys[j]; keys[j] = tmp; tmp = cnts[i]; cnts[i] = cnts[j]; cnts[j] = tmp; } } } var res = ""; var outfile = fso.CreateTextFile( WScript.Arguments(0).replace( ".txt", ".csv" ) ); for( var i=0 ; i<keys.length ; i++ ) { res += keys[i] + "\t" + cnts[i] + "\n"; outfile.WriteLine( keys[i] + "," + cnts[i] ); } outfile.Close(); WScript.Echo( res );
不明な点がありましたらコメントにて対応いたしますので、有効にお願いします。
【並べ替えを優先するとこんな感じ】
例えばデータファイルを aaa.txt という名前でサーバにアップして、下記シェルスクリプトを同じディレクトリに配置して countsort.sh という名前で保存して実行権を付けたとします
./countsort.sh aaa.txt
のように実行すると result.csv というファイルが出来上がります。
result.csv をWindowsに持ってきてEXCELで個数を基準にソートすれば目標を達成できると思います。
#!/bin/sh
cat $1|sed -e "s/ /\n/g"> b
cat b|sort -u > c
rm -f result.csv
FILE=c
while read d
do
echo -n $d\t >> result.csv
cat b|grep $d|wc -l >> result.csv
done < $FILE
rm -f b c
※シェルへのパスはお使いのサーバに合わせて適宜修正してください。
---
【見た感じを優先するとこんな感じ】
出現個数順に並び替えはしません。
画面に表示しておしまいです。
#!/bin/sh
cat $1|sed -e "s/ /\n/g"> b
cat b|sort -u > c
FILE=c
while read d
do
echo -n $d →
cat b|grep $d|wc -l
done < $FILE
rm -f b c
回答5と併せて返信させて頂きます。
こちらが望んでいた動き方を、問題なく実現出来ました。
テキストファイルをUTFではなくEUCでエンコードしていたため、
初回起動時に一瞬震えましたが、無事結果を出力できました。
本当にありがとうございました。
1.以下のサイトからActivePerlをインストール
http://www.activestate.com/activeperl/
2.以下の内容をwordcount.plという名前のテキストで適当な場所へ保存
#---wordcount.pl----
while(<>)
{
while(/(\S+)\s/gi){
$word{$1}++;
}
}
foreach $key(sort keys(%word)){
print "$key→$word{$key}\n";
}
3.単語はglossary.txtに保存して、同じディレクトリに置いておく
4.コマンドラインを開いて、保存場所に移動
5.コマンドラインから以下のように打ち込む
perl wordcount.pl glossary.txt
補足
・perl wordcount.pl glossary.txt > output.txt とすると、output.txtに書き出されます
・スクリプトはベタベタですみません・・・
「ActivePerlをインストール」の文字を見た瞬間震えましたが、
お古のXPに無事Perlインスコし動作を確認いたしました。
こちらが例に出しました「→」部分まで再現して頂きありがとうございます。
Perlインスコになぜか10分もかかり、途中で泣きそうになりながら「動け!動け!」と声援を送ったのは良い思い出です。
本当にありがとうございました。
エクセルのVBAで作成してみました。
・テキストファイルはEXCELと同じフォルダーにあるとしました。
ファイル名は「単語.txt」
・集計結果はEXCELシートに表示しました。
・最後に件数の多い順で並べました。
※変数宣言は省略しています。
Sub 単語集計処理() Dim dicT As Object Set dicT = CreateObject("Scripting.Dictionary") '--- 集計 Open ThisWorkbook.Path & "\単語.txt" For Input As #1 Do While Not (EOF(1)) Line Input #1, 単語 dicT(単語) = dicT(単語) + 1 Loop Close '--- 結果表示 For Each 単語 In dicT.Keys Range("A1").Offset(I, 0) = 単語 Range("A1").Offset(I, 1) = dicT(単語) I = I + 1 Next '--- 並び替え Range("A1:B65536").Sort Key1:=Range("B1"), Order1:=xlDescending End Sub
VBAというものを初めて使ったのですが、これすごく便利ですね。
こちらも問題なく、希望条件に沿う形でファイルを出力できました。
質問時に書いていなかったことなのでこちらが完全に悪いのですが、
実はテキスト行が5万行ほどあり、その処理に対して結構な負荷が掛かるらしく、
エクセルのセルやらフレームやらが激しく点滅しながら一生懸命処理をしている姿に震えました。
落ちるな!落ちるな!と祈りながら処理を眺めたのはいい思い出です。
本当に、ありがとうございまいした。
WSH である JavaScript での例です。
(1)下記を WordCount.js(ファイル名は自由:拡張子はjs) というファイル名で保存してください。
(2)計測するデータを data.txt(ファイル名は自由:拡張子はtxt) というファイル名で保存してください。
(3)data.txt を WordCount.js にドラッグ&ドロップしてください。
これで結果が表示されると共に data.csv が作成されますので、EXCEL 等で開いてください。
var fso = new ActiveXObject("Scripting.FileSystemObject"); var dic = new ActiveXObject("Scripting.Dictionary"); var infile = fso.OpenTextFile( WScript.Arguments(0) ); var c = 0; var lines = new Array(); while( !infile.AtEndOfStream ) lines[c++] = infile.ReadLine(); for( var line in lines ) { var words = lines[line].split( " " ); for( var word in words ) { if ( dic.Exists( words[word] ) == false ) dic.Add( words[word], 1 ); else dic.Item(words[word]) = dic.Item(words[word]) + 1; } } var keys = ( new VBArray( dic.Keys())).toArray(); var cnts = new Array(); for ( key in keys ) { cnts[key] = dic( keys[key]); } var tmp; for( var i=0 ; i<keys.length ; i++ ) { for( var j=i+1 ; j< keys.length ; j++ ) { if ( cnts[i] < cnts[j] ) { tmp = keys[i]; keys[i] = keys[j]; keys[j] = tmp; tmp = cnts[i]; cnts[i] = cnts[j]; cnts[j] = tmp; } } } var res = ""; var outfile = fso.CreateTextFile( WScript.Arguments(0).replace( ".txt", ".csv" ) ); for( var i=0 ; i<keys.length ; i++ ) { res += keys[i] + "\t" + cnts[i] + "\n"; outfile.WriteLine( keys[i] + "," + cnts[i] ); } outfile.Close(); WScript.Echo( res );
不明な点がありましたらコメントにて対応いたしますので、有効にお願いします。
手軽さと出力結果においてベストであると判断しベストアンサーとさせていただきます。
バックグラウンドで処理をし、出力結果がcsvという扱いやすい形式、
またスペースで区切られた単語も個別の単語として集計して下さる点に涙しました。
テキストファイルのエンコード種類にも左右されないようなものありがたいです。
回答ので、唯一震える瞬間がなかったのが残念ですが、今後末永く使わせていただきます。
本当に、ありがとうございました。
ちょっと追加
これならEXCEL使わなくても要望どおりの動きになると思います。
ファイルに落としたい場合はリダイレクトしてください。
#!/bin/sh
cat $1|sed -e "s/ /\n/g"> b
cat b|sort -u > c
rm -f e
FILE=c
while read d
do
echo -n "$d → " >> e
cat b|grep $d|wc -l >> e
done < $FILE
cat e|sort -k 2 -r
rm -f b c e
手軽さと出力結果においてベストであると判断しベストアンサーとさせていただきます。
バックグラウンドで処理をし、出力結果がcsvという扱いやすい形式、
またスペースで区切られた単語も個別の単語として集計して下さる点に涙しました。
テキストファイルのエンコード種類にも左右されないようなものありがたいです。
回答ので、唯一震える瞬間がなかったのが残念ですが、今後末永く使わせていただきます。
本当に、ありがとうございました。