アプリ版:「スタンプのみでお礼する」機能のリリースについて

あるテキストデータを一行ごとに読み込んで、chompで改行をはずして結合し、一つの長い行にしてから、正規表現で文章中の単語を(かなり多く)置換したとします。置換したあとのデータを、元データと同じ改行位置で改行をしたいのですが、なにか簡単な方法がありましたら教えて下さい。

A 回答 (9件)

>MeCabモジュールは入ったみたいですが、関数を使用するとエラーが出てしまいます。



my $mecab= new MeCab::Tagger();
のところで、本当に $mecab オブジェクトができたか (undef ではないか)確かめて下さい。もし undef なら、(Windows 環境では)いろいろと原因が考えられ、調べるのも厄介である可能性があります。

どの程度の規模の仕事なのかにもよりますが、こうした作業には Linux をおすすめします。

Windows しか使えない状況でも、mecab 単体なら動くと期待されますので、
mecab -O wakati in.txt > out.txt
として mecab で空白で分かち書きし、その結果を回答5のようにして(あたかも英文のように扱って)処理すればいいかと思います。但し、元ファイルに既に空白があり、且つその有無が有意味の場合は厄介ですが。

もう一つ、mecab は、文字コードに関して余り融通がきかないので、全部 EUC-JP に揃えるとか、あらかじめ注意しておくことです。

この回答への補足

返答が遅れて申し訳ありません。
Windows用mecabをインストールしなおしたらエラーは出なくなったのですが、今度は出力結果が駄目です(通常の形態素解析結果すらうまく出力されない)。

また、
mecab -O wakati lisk.txt > out.txt
も試したのですが、
tagger.cpp(146) [writer_.open(param)] writer.cpp(62) [! std::string(param.getProfileString(nfk.c_str())).empty()] unknown format type [lisk.txt]
といったエラーが出てしました。
ちなみに、
mecab lisk.txt -o out.txt
は大丈夫でした。

どつぼです。出来るのと出来ないのが混在して、何が原因か特定ができません。

補足日時:2006/07/24 11:17
    • good
    • 0

>mecab lisk.txt -o out.txt


>は大丈夫でした。

それなら、その各行の最左端の語を空白で切って連ね、EOS が来たら改行すれば、空白で分かち書きしたテキストができるわけですから、後は英語などと同じようにして処理できるかと思います。

mecab は、エラーを起こした場合の原因が探りにくいときがあるので、それなりの規模のテキストの処理をしているのであれば、windows より Linux などの環境をおすすめしますが。
    • good
    • 0

>日本語の単語を抽出してタグ付きの単語に置換する作業を行っています。



それでしたら、回答5の最後に書いたように
>元のデータが分かち書きされていないのであれば、mecab などで単語切りをしてやらないといけません

ということになります。具体的には、まず MeCab で単語を取り出しておいて、それぞれの単語に置換を掛ければいいかと。

--------------------------
use strict;
use MeCab;

my @word_list= get_word();
foreach my $word (@word_list) {
$word=~ s/FROM/TO/;
...
print $word;
}

sub get_word {
my @rec_list= map { chomp($_); $_; } <>;
my @len_list= map { length($_) } @rec_list; # keep original length

my @out_word_list;
my $out_len= 0;
my $in_len= shift(@len_list);

my $mecab= new MeCab::Tagger();
my $token= $mecab->parseToNode(join('',@rec_list));
while($token) {
my $word= $token->{surface};
push(@out_word_list,$word);
if ($out_len + length($word) >= $in_len) {
push(@out_word_list,"\n");
$in_len+= shift(@len_list);
}
$out_len+= length($word);
$token= $token->{next};
}
shift(@out_word_list); #cut BOS
pop(@out_word_list); #cut EOS
return @out_word_list;
}
----------
なお、置換リスト中の「置換前」の語を MeCab の辞書に登録しておかないと、MeCab が誤認したり切り過ぎてしまって失敗します。
たとえば「年末謝恩大売出し」を置換対象にしたいなら、それを辞書に登録しておかないと、MeCab が「年末/謝恩/大/売出し」のように切ってしまうかもしれません。

参考URL:http://mecab.sourceforge.jp/

この回答への補足

細かい説明ありがとうございます。
実はperlにあるまじきWindows環境なのですが、以下の参考URLの通りしたのですがMeCabモジュールは入ったみたいですが、関数を使用するとエラーが出てしまいます。
参考URL:http://namazu.asablo.jp/blog/2006/04/04/315580

補足日時:2006/07/21 14:32
    • good
    • 0

改行を無視して置換したいってことですよね?



「test」を「a_test_b」に変換
$body = "testtes\ntte\nst\n";

$body =~ s/(t[\n]*e[\n]*s[\n]*t)/a_$1_b/;

でいいんじゃないですか?

chompが具体的にどうやって正規表現でおきかえることができるか確認してないので、そのへんは調整必要ですが。
    • good
    • 0

改行を削除したものと削除しないものの両方に置換を掛け、双方の差が生じた場合に改行削除の方を使って出力する、という方法でいいと思います。



ただ、仕様に不明な点が多い。一番の問題は、改行部分に置換が生じたとき、元の改行位置をどこまで保存したいかです。例えば、「abc」→「ABC」という置換ルールのとき、「ab[改行]c」は「AB[改行]C」に、「a[改行]bc」は「A[改行]BC」にしたい、とかになると結構厄介。なぜなら、「longlongword」→「SHORT」というルールで、「longlong[改行]word」が入力されたとき、「SHORT」のどこで改行するのが正しいか分りませんので。

こうした問題はなく、改行を含む置換では置換した語の直後に改行すればよし、というのであれば、次のような形かと。
--------
use strict;
my $WORD_DIVIDER= ' ';

my $rec= join('',<>);
my $outrec= split_word($rec);
print join($WORD_DIVIDER,@$outrec);

sub split_word {
my($rec)= @_;
my $outarray= [];
foreach my $word (split(/[ ]/o,$rec)) {
my $word_strip= $word;
$word_strip=~ s/\-?[\r\n]//go;
my $x_word= change_word($word);
my $x_word_strip= change_word($word_strip);
if ($x_word_strip eq $word_strip) {# no change
push(@$outarray,$word);
} elsif ($x_word_strip eq $x_word) {# change not affected by LF
push(@$outarray,$x_word);
} else {
push(@$outarray,$x_word_strip . "\n");
}
}
return $outarray;
}

sub change_word {
my($word)= @_;
# just testing
$word=~ s/abc/ABC/g;
$word=~ s/hij/HIJ/g;
$word=~ s/rst/RST/g;
$word=~ s/xyz/XYZ/g;
$word=~ s/Supercalifragilisticexpialidocious/LONG/g;
return $word;
}
---------
test data
test a-
bc def hij
klm Super-
califragilistic-
expialidoc-
ious opq rs-
t uvw x-
yz done
-------------
出力
test ABC
def HIJ
klm LONG
opq RST
uvw XYZ
done
---------
元のデータが分かち書きされていないのであれば、mecab などで単語切りをしてやらないといけません。

この回答への補足

詳しい内容ありがとうございました。
残念ながら日本語の置換なので空白の分かち書きはされていません。

詳しく書くと、日本語の単語を抽出してタグ付きの単語に置換する作業を行っています。

置換前:日本語
置換後:<FONT color=\"#FF0000\">日本語</FONT>

といった感じです。改行は置換された単語の直後にされる仕様で問題ありません。

補足日時:2006/07/20 09:35
    • good
    • 0

元データの整形(されているのなら)のルールというのは決まっていないんですか?


もし決まっているなら、改行を取り除いて置換を行った後、再度そのルールに
従って整形してやるのが一番手っ取り早いと思うんですが。

また、置換の結果文字数が変わりうるのであれば「元データと同じ改行位置」
というのはちょっと無理があると思います。
    • good
    • 0

置き換えで文字数が変わってしまうとダメと言うことは・・・


置き換えで文字数が変わらないようにすればOKですよね

置き換え前:いろはにほへと
置き換え後:ABC
の場合はABCをあらかじめ"ABC@@@@@@"と補完して置き換え後、@を消す(@にはめったに使わない文字や記号を使用します)

置き換え前:ABC
置き換え後:いろはにほへと
の場合は、"いろはにほへと"を"@1****"などとタグ+長さ補完の値で置き換え、後で1つずつ置き換えていく・・・
・・・面倒そうですがどうでしょうか?
    • good
    • 0

1行毎に読み込む際、行の文字数を配列で保存して分割する際にそれを利用する


(置き換えで文字数が変わってしまうと駄目ですが)

この回答への補足

すいません、説明がたりませんでした。
重要なのは改行にまたがった単語を正規表現で検出したいので一度改行を外す必要がある訳です。ついでに置換後は文字数は変化する仕様になっています。

補足日時:2006/07/19 18:33
    • good
    • 0

最初に改行を「トル」のではなく,めったに使わない文字や記号に変換しておき,最後に改行に置換するといいです.


〃や仝など.

この回答への補足

すいません、説明がたりませんでした。
重要なのは改行にまたがった単語を検出したいので一度改行を外す必要がある訳です。ですから違う記号にしおくと単語が検出できません・・・。

補足日時:2006/07/19 18:37
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!