• ベストアンサー

改行を正規表現での置換のあとで元に戻す。

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

  • Perl
  • 回答数9
  • ありがとう数4

質問者が選んだベストアンサー

  • ベストアンサー
  • vsba23895
  • ベストアンサー率58% (18/31)
回答No.8

>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 に揃えるとか、あらかじめ注意しておくことです。

jukimoto
質問者

補足

返答が遅れて申し訳ありません。 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 は大丈夫でした。 どつぼです。出来るのと出来ないのが混在して、何が原因か特定ができません。

その他の回答 (8)

  • vsba23895
  • ベストアンサー率58% (18/31)
回答No.9

>mecab lisk.txt -o out.txt >は大丈夫でした。 それなら、その各行の最左端の語を空白で切って連ね、EOS が来たら改行すれば、空白で分かち書きしたテキストができるわけですから、後は英語などと同じようにして処理できるかと思います。 mecab は、エラーを起こした場合の原因が探りにくいときがあるので、それなりの規模のテキストの処理をしているのであれば、windows より Linux などの環境をおすすめしますが。

  • vsba23895
  • ベストアンサー率58% (18/31)
回答No.7

>日本語の単語を抽出してタグ付きの単語に置換する作業を行っています。 それでしたら、回答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/
jukimoto
質問者

補足

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

  • to_kyo
  • ベストアンサー率41% (7/17)
回答No.6

改行を無視して置換したいってことですよね? 「test」を「a_test_b」に変換 $body = "testtes\ntte\nst\n"; $body =~ s/(t[\n]*e[\n]*s[\n]*t)/a_$1_b/; でいいんじゃないですか? chompが具体的にどうやって正規表現でおきかえることができるか確認してないので、そのへんは調整必要ですが。

  • vsba23895
  • ベストアンサー率58% (18/31)
回答No.5

改行を削除したものと削除しないものの両方に置換を掛け、双方の差が生じた場合に改行削除の方を使って出力する、という方法でいいと思います。 ただ、仕様に不明な点が多い。一番の問題は、改行部分に置換が生じたとき、元の改行位置をどこまで保存したいかです。例えば、「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 などで単語切りをしてやらないといけません。

jukimoto
質問者

補足

詳しい内容ありがとうございました。 残念ながら日本語の置換なので空白の分かち書きはされていません。 詳しく書くと、日本語の単語を抽出してタグ付きの単語に置換する作業を行っています。 置換前:日本語 置換後:<FONT color=\"#FF0000\">日本語</FONT> といった感じです。改行は置換された単語の直後にされる仕様で問題ありません。

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.4

元データの整形(されているのなら)のルールというのは決まっていないんですか? もし決まっているなら、改行を取り除いて置換を行った後、再度そのルールに 従って整形してやるのが一番手っ取り早いと思うんですが。 また、置換の結果文字数が変わりうるのであれば「元データと同じ改行位置」 というのはちょっと無理があると思います。

  • pipipi523
  • ベストアンサー率40% (148/365)
回答No.3

置き換えで文字数が変わってしまうとダメと言うことは・・・ 置き換えで文字数が変わらないようにすればOKですよね 置き換え前:いろはにほへと 置き換え後:ABC の場合はABCをあらかじめ"ABC@@@@@@"と補完して置き換え後、@を消す(@にはめったに使わない文字や記号を使用します) 置き換え前:ABC 置き換え後:いろはにほへと の場合は、"いろはにほへと"を"@1****"などとタグ+長さ補完の値で置き換え、後で1つずつ置き換えていく・・・ ・・・面倒そうですがどうでしょうか?

  • pipipi523
  • ベストアンサー率40% (148/365)
回答No.2

1行毎に読み込む際、行の文字数を配列で保存して分割する際にそれを利用する (置き換えで文字数が変わってしまうと駄目ですが)

jukimoto
質問者

補足

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

  • garouz
  • ベストアンサー率19% (178/917)
回答No.1

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

jukimoto
質問者

補足

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

関連するQ&A

  • 正規表現による改行の置換

    Windowsで正規表現ができるテキストエディタ(NoEditer)を使っており、次のような改行で区切られた文を最後のピリオッドまでをつなげたいと思っています。例文ではX,Y,Z.の直後には改行が入っており、目的はAaaaXBbbbYCcccZ.と一文につなげることです。 [例文] AaaaX BbbbY CcccZ. 正規表現で \n[^(\.\n)] としてを空欄に置換すると2行目以降の頭が消えてしまいます。---> AaaaXbbbYcccZ.  文頭の文字が消えずつなげる方法を教えて下さい。

  • 正規表現で置換

    正規表現の初心者です。 テキストエディタを使って、「@:」で始まる以外の行の先頭に「//」を挿入してコメントアウトしたいのですが、正規表現がうまく書けません。 検索対象: ^[^(@:)] 置換文字列: // でいいのかなと思ったのですが、[]の中ではグルーピング用の()も文字として認識されてしまうのですね。 どのように書いたら正しく置換されるでしょうか。 どうかご教示ください。

  • 正規表現を使用した置換(サクラエディタ)

    正規表現を使用して(7桁の数値)のみを残す置換をしようとしましたが上手くいきません、上手い方法はありませんでしょうか。 (7桁の数値)がなくても改行は残す置換を行いたいです 例 1行:12345(1000000)1145 2行:231(1234567)231(8901234)235 3行:235677433 4行:(1111111)(2222222)333 ↓ 置換 1行:(1000000) 2行:(1234567)(8991234) 3行: 4行:(1111111)(2222222)

  • サクラエディタの正規表現での置換

    サクラエディタの正規表現での置換の方法について教えて下さい。 行の末尾が数字で終わらない行の改行コードを削除したいと考えています。 ---------- 元ファイル ---------- 000abc123 777def 456 333ghi789 222jk+ 111 ---------- ---------- 加工後 ---------- 000abc123 777def456 333ghi789 222jk+111 ---------- 「置換前」は『[^0-9]\n』を入力することで検索できましたが、 「置換後」に何を設定すれば良いのかわかりません。(または「検索対象」の設定を変える必要があるのかなど) 例えば置換後に何も設定しないと「777de456」とfが消えてしまうため、”f”を残した上で改行コードを削除したいのですが その方法がわかりません。 よろしくお願いいたします。

  • 正規表現で改行が3個続いてたら、それを削除する書き

    検索とか置換えで、正規表現で、改行が3回続いていたら、それを削除する書き方ってあるでしょうか? 試して見てるのですが、改行が全部消えてしまい、うまく思い通りにいきません。 検索:^\n 置換: とかだと、改行が全部なくなってしまいます。 ^\n\n\n$ だと、ヒットしません。 改行が続いていて、それを3行だけ取り除くなんていうのは、できないもんでしょうか。 文章の中にあります。 行頭に半角空白,改行と続くのもありますが、それはヒットしないように。      

  • Excelの置換で改行

    Excelの置換で、 ある言葉のあとに改行を入れる方法を教えてください。 「AAA」という言葉を指定したら、AAAのあとに必ず改行(セル内での改行)を入れる方法です。 正規表現のようなもので改行が指定できたら、それでできると思うのですが、やり方がわかりません。 (そもそも置換で正規表現が使えるかどうかも知りません) Excel2000です。 (ただ、申し訳ないのですが、VBAなど難しいことはよくわかりません。)

  • 正規表現で一括置換

    現在、数多くの長文データを、テキストエディタの置換機能で一括置換しています。 jeditX(または秀丸エディタ)の正規表現をもちいた複数一括置換について質問させていただきます。 私は正規表現やPC言語の初心者です。どうぞよろしくお願いいたします。 かなり困り果てております。どうぞ、正規表現にくわしいかた、よろしくお願いします。 一二三『一二三にそれぞれ♪マーク』 という文章に対して 一♪二♪三♪ という一括置換をすることには成功しました。 こう書いています。 ■検索文字列 (.{1,1})(.{1,1})(.{1,1})『(.{1,1})(.{1,1})(.{1,1})にそれぞれ♪マーク』 ■置換文字列 \1♪\2♪\3♪ これでぶじ、以下のように一括置換できました。 一♪二♪三♪ 現実には傍点や圏点をふっているんですが、判りやすく♪マークにしています。 この調子で長い文章も変換できていて満足していたのですが…… しかし代入文字が10個以上になったとたんに、まったく動きません。 ■置換したい文章 一二三四五六七八九十『一二三四五六七八九十にそれぞれ♪マーク』 ■検索文字列 (.{1,1})(.{1,1})(.{1,1})(.{1,1})(.{1,1})(.{1,1})(.{1,1})(.{1,1})(.{1,1})(.{1,1})『(.{1,1})(.{1,1})(.{1,1})(.{1,1})(.{1,1})(.{1,1})(.{1,1})(.{1,1})(.{1,1})(.{1,1})にそれぞれ♪マーク』 ■置換文字列 \1♪\2♪\3♪\4♪\5♪\6♪\7♪\8♪\9♪\10♪ こうやると、置換後の文章は以下のようになってしまいます。 一♪二♪三♪四♪五♪六♪七♪八♪九♪一0♪ 10個目以降の数字が、正しく機能してくれません。 \10  という正規表現の書き方は 「一番目の値を参照して、それから数字の0を記入しなさい」 という意味になってしまうようです。 わたしは十番目の値を代入してほしいだけなんです。 \1 や \2 や \3 といった代入文字のように \10 や \11 を機能させる、正しい表記をご教授ください。よろしくお願いいたします。 ちなみに以下のように書いてもダメでした……。 \1\0 グーグルで1日中検索しても判りませんでした。jeditXの複数一括置換でこれをなんとかしたいのです。ご存じの方、どうぞ教えてください。よろしくおねがいします! 秀丸エディタをご利用で、正規表現にくわしい方も、ぜひヒントを出していただければと思います。

  • 正規表現で検索するときのパターンについて

    VBScriptの正規表現で、100行くらいのテキストファイルを対象に検索を行いたいのですが、その中の一行に単語1と単語2と単語3の3つの単語が全て含まれるそういう行があるかないかを調べるには、どういうパターンにすればいいでしょうか? (単語1と単語2と単語3の順番は問いません。) ご教授のほどよろしくお願いいたします。

  • 正規表現置換

    はじめまして。 現在、テキストエディタで kami987koroです。(漢字、かな、英数字、半角記号、全角記号、改行、スペースを含む文字列)ありがとうございました。 という文字列を正規表現で拾いだして、置換したいと考えています。 ただ、私がその方面の知識に疎く、どう表記すればよいのか分かりません。 そこで、この分野にお詳しい方、ご教授願えませんでしょうか? よろしくお願い致します。

  • 改行を含む場合の置換。

    内容が文章のテキストファイルがあります。 その中のある一部分を置換したいのですが、 例) おはようございます。→こんばんは。 FileReaderで一行づつ読み込んで、その中から「おはようございます。」を 探して「こんばんは。」に置換することはできたのですが、 文章なので途中で改行が入っている場合があります。 例) おはようご(↓改行)    ざいます。 こういう場合だと、探し出すことができません。 一度ファイルの内容を全部ひとつのStringに入れて 置換するという手も考えたんですが、 書き出すときに文章のズレが出てきてしまいます。 何かいい手はあるんでしょうか? わかりにくくてスイマセン。

    • ベストアンサー
    • Java

専門家に質問してみよう