一行ごとにひとつの単語、または複数の単語が並んでいるテキストファイルがあります。

このテキストの中に含まれる単語を何らかの方法で集計し

リンゴ
スイカ
カモメ
メダカ
カモメ
メジロ
ロジック
クリスマス
スイカ カジキ
キンメダイ
イカ カモメ
メダカ
カジキ

リンゴ→1
スイカ→1
カモメ→2
メダカ→2
メジロ→1
ロジック→1
クリスマス→1
スイカ カジキ→1
キンメダイ→1
イカ カモメ→1
カジキ→1

というふうに、同じ単語が何個あったのかを把握したいと考えています。

ただしこれを実現する際の必須条件として、
「リンゴ」や「スイカ」など、こちらでひとつづつ単語を指定して集計することなく、
自動的に同じ単語を集計し、一覧として出力出来るものであって下さい。

なお可能であれば
・出力される結果は同じ単語が多い順に並べる。
・「スイカ カジキ」というスペースで区切られた単語を「スイカ」「カジキ」と個別の単語として認識し集計する。
などが出来ればうれしいです。

こちらの環境はOS:Vista、エクセル所有、レンタルサーバcoreserverが使えます。
結果が出力される形式は問いませんが、あまり複雑な手順でないことを望んでおります。

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2009/05/26 17:31:53
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:Mook No.4

回答回数1314ベストアンサー獲得回数393

ポイント100pt

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 );

不明な点がありましたらコメントにて対応いたしますので、有効にお願いします。

id:matukoi

手軽さと出力結果においてベストであると判断しベストアンサーとさせていただきます。

バックグラウンドで処理をし、出力結果がcsvという扱いやすい形式、

またスペースで区切られた単語も個別の単語として集計して下さる点に涙しました。

テキストファイルのエンコード種類にも左右されないようなものありがたいです。

回答ので、唯一震える瞬間がなかったのが残念ですが、今後末永く使わせていただきます。

本当に、ありがとうございました。

2009/05/26 17:29:27

その他の回答4件)

id:standard_one No.1

回答回数252ベストアンサー獲得回数23

ポイント25pt

【並べ替えを優先するとこんな感じ】

例えばデータファイルを 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

id:matukoi

回答5と併せて返信させて頂きます。

こちらが望んでいた動き方を、問題なく実現出来ました。

テキストファイルをUTFではなくEUCでエンコードしていたため、

初回起動時に一瞬震えましたが、無事結果を出力できました。

本当にありがとうございました。

2009/05/26 17:16:31
id:pigment No.2

回答回数95ベストアンサー獲得回数2

ポイント50pt

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に書き出されます

・スクリプトはベタベタですみません・・・

id:matukoi

「ActivePerlをインストール」の文字を見た瞬間震えましたが、

お古のXPに無事Perlインスコし動作を確認いたしました。

こちらが例に出しました「→」部分まで再現して頂きありがとうございます。

Perlインスコになぜか10分もかかり、途中で泣きそうになりながら「動け!動け!」と声援を送ったのは良い思い出です。

本当にありがとうございました。

2009/05/26 17:20:26
id:jccrh1 No.3

回答回数111ベストアンサー獲得回数19

ポイント50pt

エクセルの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
id:matukoi

VBAというものを初めて使ったのですが、これすごく便利ですね。

こちらも問題なく、希望条件に沿う形でファイルを出力できました。

質問時に書いていなかったことなのでこちらが完全に悪いのですが、

実はテキスト行が5万行ほどあり、その処理に対して結構な負荷が掛かるらしく、

エクセルのセルやらフレームやらが激しく点滅しながら一生懸命処理をしている姿に震えました。

落ちるな!落ちるな!と祈りながら処理を眺めたのはいい思い出です。

本当に、ありがとうございまいした。

2009/05/26 17:25:51
id:Mook No.4

回答回数1314ベストアンサー獲得回数393ここでベストアンサー

ポイント100pt

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 );

不明な点がありましたらコメントにて対応いたしますので、有効にお願いします。

id:matukoi

手軽さと出力結果においてベストであると判断しベストアンサーとさせていただきます。

バックグラウンドで処理をし、出力結果がcsvという扱いやすい形式、

またスペースで区切られた単語も個別の単語として集計して下さる点に涙しました。

テキストファイルのエンコード種類にも左右されないようなものありがたいです。

回答ので、唯一震える瞬間がなかったのが残念ですが、今後末永く使わせていただきます。

本当に、ありがとうございました。

2009/05/26 17:29:27
id:standard_one No.5

回答回数252ベストアンサー獲得回数23

ポイント25pt

ちょっと追加

これなら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

  • id:pigment
    これだけ回答があって、みなさんやり方が重複してない事に感動しました。
  • id:jak-san
    バッチファイルでも出来ますよ。締め切りに間に合わなくて残念。
    list.txt が対象となるテキストファイルとします。


    echo off
    :------------------------------------------------------------ sample.bat
    for /F "delims=" %%a in (list.txt) do call :sub %%a
    for /F "tokens=2,3 delims=[]=" %%a in ('set count[') do echo %%a→%%b
    exit /b

    :sub
    if "%1"=="" goto :EOF
    set /a count[%1] += 1
    shift
    goto sub


    結果をファイルに残すなら、sample.bat>kekka.txt とすればファイルに残ります。
    echo %%a→%%b を echo %%a,%%b とすれば csv 形式になります。

  • id:airplant
    単語が1行に1つの場合は、単純にExcelのピボットテーブルで単語毎の件数が出ます。
    多い順の並べは、ピボットテーブルで出てきた件数の欄でソートをクリックすればできます。
    1行に複数個の場合は、少し工夫がいりますね。
  • id:standard_one
    >これだけ回答があって、みなさんやり方が重複してない事に感動しました。
    確かに驚きです。
    バッチファイルもエントリされたし、あとは「秀丸マクロならこう」って人が現れたら、ありがちな手段は一通り網羅したことになりますかね?w
  • id:matukoi
    いろんな方法あるんですねぇ。もう凄いの一言だと思います。
    質問してからはじめてstandard_oneさんに回答頂くまで、わずか1時間くらいですし…
    おそるべしはてなって感じです。こちらが1日頭を痛めたことがこうもあっさりやられると泣きたくなりますがorz
    みなさん、ありがとうございました。

この質問への反応(ブックマークコメント)

トラックバック

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません