スペースで区切られたカタカナの抽出。


次のような1行1用語が並んだファイルから、「スペースで区切られたカタカナ」を抽出する方法を考えてください。次に例を示します。

<ファイルの例>
インターネット Web サイト<改行>
ソーシャル ネットーワーキング サイト<改行>
ソーシャル Q&A サイト<改行>
トイザらス ギフト キャンペーン<改行>
</ファイルの例>

<抽出結果>
ソーシャル ネットワーキング サイト
ソーシャル ネットワーキング
ネットワーキング サイト
ス ギフト キャンペーン
ス ギフト
ギフト キャンペーン
</抽出結果>

文字で説明すると長くなりますが、上の例と結果を見るとどんな動きがほしいのか分かってもらえると思います。抽出結果はできれば別ファイルに出力できればモア ベターです。
質問などはコメントにお願いします。

環境
Windows XP Home (推奨)
Windows 7 Pro
Mac OS X Snow Leopard

実現するツールなど:
・ レジストリを書き換えないフリーソフト
・ MS Word 2003/2007 (VBA 可)
・ MS Excel 2007 (VBA 可)
・ 秀丸、TeraPad、その他エディター
・ PHP 5.3 (ローカルに環境があります)
・ Perl はできれば避けたい

質問はコメント欄にどうぞ

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2010/12/11 20:29:44
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:SALINGER No.3

回答回数3454ベストアンサー獲得回数969

ポイント550pt

vbsです。ファイルをドロップしてください。

同じ場所にResult.txtを作ります。

 

正規表現でスマートに出来なかったので最長一致で抜き出して分割という泥臭いことをしています。


Option Explicit
On Error Resume Next

Dim objFSO
Dim objFile,objFile2
Dim fullName,fileName,foldName
Dim objRegExp       
Dim objMatches      
Dim objMatch        
Dim strMessage      
Dim str

fullName=WScript.ScriptFullName
fileName=Wscript.ScriptName
foldName=left(fullName,len(fullName)-len(fileName))

Set objRegExp = New RegExp
objRegExp.Pattern = "[ァ-ヶー]+( [ァ-ヶー]+)+"
objRegExp.IgnoreCase = True
objRegExp.Global = True

Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
If Err.Number = 0 Then
    Set objFile = objFSO.OpenTextFile(WScript.Arguments.Item(0),1)
    Set objFile2 = objFSO.OpenTextFile(foldName & "\Result.txt",2,True)
    If Err.Number = 0 Then
        Do While objFile.AtEndOfStream <> True
            Set objMatches = objRegExp.Execute(objFile.ReadLine)
            For Each objMatch In objMatches
		str = objMatch.Value
		    Do
		        Call test(str)
		        If UBound(Split(str, " ")) >= 2 Then
		            str = Mid(str, InStr(1, str, " ") + 1)
		        Else
		            Exit Do
		        End If
		    Loop
            Next
	loop
        objFile.Close
    Else
        WScript.Echo "ファイルオープンエラー: " & Err.Description
    End If
Else
    WScript.Echo "エラー: " & Err.Description
End If

Set objMatches = Nothing
Set objRegExp = Nothing
Set objFile2 = Nothing
Set objFile = Nothing
Set objFSO = Nothing

Sub test(s)
    Dim s1
    
    objFile2.WriteLine s
    
    s1 = Left(s, InStrRev(s, " ") - 1)

    If UBound(Split(s1, " ")) >= 1 Then
        Call test(s1)
    End If
End Sub

http://q.hatena.ne.jp/

id:Nigitama

ばっちりです!

ありがとうございました!

2010/12/11 20:28:32

その他の回答2件)

id:y-kawaz No.1

回答回数1422ベストアンサー獲得回数226

秀丸の「検索→置換(Ctr+R)」で以下の設定で全置換を実行。

  • 検索: [^ァ-ヶー\n]+
  • 置換: (半角スペース)
  • 正規表現にチェック

解説:

カタカナ以外の文字の連続」を半角スペースに置換してます、結果としてスペース区切りのカタカナのだけが残ります。

改行も不要なら [^ァ-ヶー]+ を検索に使えば良いです。

id:Nigitama

質問文の <ファイルの例> を秀丸にコピペしましたが、質問文の <抽出結果> は得られませんでした。

これは単に、カタカナ以外を半角スペースに変換するだけではないでしょうか。

2010/12/09 15:33:19
id:deflation No.2

回答回数1036ベストアンサー獲得回数126

ポイント150pt

コメントにて確認をいただきありがとうございました。

与えられた条件に合うようなものをPHPで書いてみました。


この他にも条件があるようでしたらご指摘ください。

<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<?php
$myself = basename($_SERVER['SCRIPT_NAME']);
$infname = isset($_FILES['file']['tmp_name']) ? $_FILES['file']['tmp_name'] : '';
if ($infname == '') {
?>
<form method="post" action="<?= $myself ?>" enctype="multipart/form-data">
元ファイル:<input name="file" type="file" />
<input type="submit" name="submit" value="抽出" />
</form>
<?php
} else {
    $dest = array();
    $infp = fopen($infname, 'r');
    $str = fgets($infp);
    while (! feof($infp)) {
        $words = array();
        $sour = mb_convert_encoding($str, 'UTF-8', 'auto'); //ここは適当に変更して
        //スペース区切り以外の部分文字列を除去
        $sour = preg_replace("/[ァ-ヶー]*[ ]+[^ァ-ヶー ]+[ ]+/mu", '', $sour);
        if (preg_match_all("/[ァ-ヶー]+[ \n\r]+/mu", $sour, $words, PREG_PATTERN_ORDER) != 0) {
            $arr = array();
            $n = count($words[0]);
            //2単語以上で抽出
            if ($n >= 2) {
                $s = '';
                for ($i = 0; $i < $n; $i++)     $s .= $words[0][$i];
                $arr[0] = $s;
                //3単語以上は組み合わせを作成
                if ($n >= 3) {
                    $s = '';
                    for ($i = 0; $i < $n - 1; $i++)     $s .= $words[0][$i];
                    $arr[1] = $s;
                    $s = '';
                    for ($i = 1; $i < $n; $i++)     $s .= $words[0][$i];
                    $arr[2] = $s;
                }
                $dest = array_merge($dest, $arr);
            }
            unset($arr);
        }
        unset($words);
        $str = fgets($infp);
    }
    foreach ($dest as $str)     echo trim($str) . "<br />\n";   //抽出結果の表示
}
?>
</form>
</body>
</html>
id:Nigitama

ありがとうございます。

質問文にある元のテキストを使ったところ、質問文の抽出結果とまったく同じものが出力されました。

しかし、カタカナ複合語を 4 ワードにしてみたところ問題発生です。

・ハイパー テキスト マークアップ ランゲージ

上記の用語を入れて抽出にかけてみたところ

・ハイパー テキスト マークアップ ランゲージ

・ハイパー テキスト マークアップ

・テキスト マークアップ ランゲージ

出力結果は上記の通りになりました。

・ハイパー テキスト

・テキスト マークアップ

・マークアップ ランゲージ

上記の 3 つが漏れています。

連続するカタカナ語が 4 ワードを超えることはあまりないのですが、これでは漏れてしまいます。

回答上限を 2 に上げておきました。とりあえず私は本業に戻ります。

かなり泥臭い手法ですが、1 つのスクリプトで全部に対応せず、「2 ワードからなるものだけ」「3おからなるものだけ」のように対象を絞って抽出する方法なら自力でできそうなので、回答が集まらなかった場合は、その方法で対処してみます。

2010/12/09 16:16:41
id:SALINGER No.3

回答回数3454ベストアンサー獲得回数969ここでベストアンサー

ポイント550pt

vbsです。ファイルをドロップしてください。

同じ場所にResult.txtを作ります。

 

正規表現でスマートに出来なかったので最長一致で抜き出して分割という泥臭いことをしています。


Option Explicit
On Error Resume Next

Dim objFSO
Dim objFile,objFile2
Dim fullName,fileName,foldName
Dim objRegExp       
Dim objMatches      
Dim objMatch        
Dim strMessage      
Dim str

fullName=WScript.ScriptFullName
fileName=Wscript.ScriptName
foldName=left(fullName,len(fullName)-len(fileName))

Set objRegExp = New RegExp
objRegExp.Pattern = "[ァ-ヶー]+( [ァ-ヶー]+)+"
objRegExp.IgnoreCase = True
objRegExp.Global = True

Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
If Err.Number = 0 Then
    Set objFile = objFSO.OpenTextFile(WScript.Arguments.Item(0),1)
    Set objFile2 = objFSO.OpenTextFile(foldName & "\Result.txt",2,True)
    If Err.Number = 0 Then
        Do While objFile.AtEndOfStream <> True
            Set objMatches = objRegExp.Execute(objFile.ReadLine)
            For Each objMatch In objMatches
		str = objMatch.Value
		    Do
		        Call test(str)
		        If UBound(Split(str, " ")) >= 2 Then
		            str = Mid(str, InStr(1, str, " ") + 1)
		        Else
		            Exit Do
		        End If
		    Loop
            Next
	loop
        objFile.Close
    Else
        WScript.Echo "ファイルオープンエラー: " & Err.Description
    End If
Else
    WScript.Echo "エラー: " & Err.Description
End If

Set objMatches = Nothing
Set objRegExp = Nothing
Set objFile2 = Nothing
Set objFile = Nothing
Set objFSO = Nothing

Sub test(s)
    Dim s1
    
    objFile2.WriteLine s
    
    s1 = Left(s, InStrRev(s, " ") - 1)

    If UBound(Split(s1, " ")) >= 1 Then
        Call test(s1)
    End If
End Sub

http://q.hatena.ne.jp/

id:Nigitama

ばっちりです!

ありがとうございました!

2010/12/11 20:28:32
  • id:deflation
    元のテキストが

    ギフト キャンペーン トイザらス

    だった場合は、抽出後は

    ギフト キャンペーン トイザ
    ギフト キャンペーン
    キャンペーン トイザ

    の3つで良いですか?
  • id:Nigitama
    deflationさん

    さっそくのコメントありがとうございます。

    > ギフト キャンペーン トイザ
    > ギフト キャンペーン
    > キャンペーン トイザ
    >
    > の3つで良いですか?

    はい。その通りです。
  • id:deflation
    スペースで区切られたワードは常に3つですか。

    もし区切られたワードが4つ以上のこともあり、たとえば
     インターネット Web セキュリティ サイト
    の場合、どのように抽出すればよいですか?
  • id:Nigitama
    > スペースで区切られたワードは常に3つですか。
    いいえ、その時によって違います。
    (スペースからスペースまでをワードと呼ぶなら) 1ワードのものも多くあります。
    最大でも 4、5 ワードくらいだと思います。平均的には 2 ワードくらいだと思います。

    > もし区切られたワードが4つ以上のこともあり、たとえば
    >  インターネット Web セキュリティ サイト
    > の場合、どのように抽出すればよいですか?
    この場合は
    「セキュリティ サイト」のみが抽出されます。

    web というアルファベットが入っているので、
    「スペースで区切られたカタカナ」の条件から外れます。
  • id:Nigitama
    id:y-kawaz さん

    回答ありがとうございました。
    ここでいう「スペースで区切られたカタカナ」とは、
    「区切りに半角スペースを使用する連続する 2 語以上から成るカタカナ複合語」のことです。

    「インターネット Web サイト」という行の中には、対象となる複合語はありません。

    たとえば、秀丸で次の正規表現を使うと
    (?<![ァ-ヶー\n])[ァ-ヶー]+ [ァ-ヶー]+(?=[^ァ-ヶー])

    マッチする単語は次の通りです。
    ・ソーシャル ネットーワーキング サイト
    ・ネットーワーキング サイト
    ・ス ギフト
    ・ギフト キャンペーン

    もう一声なんですね。ほかにもマッチしてほしいのは
    ・ソーシャル ネットワーキング サイト
    ・ス ギフト キャンペーン

    ただいま試行錯誤中です。
    (秀丸でマッチした後も、ほかのファイルに出力する問題も残っていますが)
  • id:deflation
    お手上げです。ごめんなさい <(_ _)>

    スペースで区切られたワードの組み合わせの生成を考えてみたのですが、単純な組み合わせにはならないので、良い計算方法が思いつきませんでした。
  • id:Nigitama
    deflation さんもありがとうございました!

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

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

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

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