kakakakakku blog

Weekly Tech Blog: Keep on Learning!

PHPで正規表現を使ってニュースから発言を抽出する_3(否定の先読み表現)

以前のエントリーでは,ニュース記事本文(1行)から「 」で囲まれた発言とその発言をした人物名を抽出するという正規表現に関して勉強してまとめた.

しかしニュース記事本文(複数行)を入力とした場合に,期待する結果が得られないという問題に遭遇した.(入力から複数の出力が得られる場合)

どうしても自分では解決できず,天才プログラマーと呼ばれている先輩の知恵を借りて解決を試みた.
そのときの話をこのエントリーでは書くよ.

  • -

先輩からまず受けたアドバイスは「preg_matchじゃなくてpreg_match_allを使えば」という内容だった.

preg_match_allは繰り返し正規表現検索を行う関数であり,これで解決できると思った.
でも後々この関数は1行ずつ正規表現をかけていくものであり,もともとの入力文(ニュース記事)に改行コードが入ってなく複数文が結合して1文となっていることが問題だとわかった.

  • -

入力文の例を出す.

太郎は「今日は良い天気だし散歩にでも行こう。」と言った。
次郎は「今日は宿題があるから僕は散歩には行けないよ。」言った。
  ※プログラム上は2文が繋がって1文になっている

という文があったとしよう.

この入力に対して,単純に

preg_replace("/。/","。\n",$text);

と置換したくなるのだが,これだと

太郎は「今日は良い天気だし散歩にでも行こう。 ←ここかよ!

で改行コードが挿入されてしまう.
そこで,「」で囲まれている。はスルーして改行コードを挿入することが必要だとわかった.

  • -

正直僕はお手上げ状態で飽和してたんだけど,そしたら先輩が

否定の先読み表現を使えばいいね♪
preg_replace("/。(?!」)/","。\n",$text);

と神語を発してきて,正直(゚Д゚)???だった.

  • -

この否定の先読み表現とは,「指定した文字列の含まない文字列だけに一致する正規表現である.
PHPでの書き方は

(?!パターン)

である.

例えば

(?!computer)com

と書くと
"computer"以外の"com"で始まる文字列にマッチする.


そう考えると

。(?!」)

"。」"ではない"。"にのみマッチする

と読める.完璧である.


こんな感じで,否定の先読み表現という知的すぎる書き方を知って,正規表現の凄さを改めて感じました.
天才プログラマーは伊達じゃない.
先輩ありがとうございました.

  • -

おまけ

先輩に「改行コードを入れればいいじゃん!」と言われたときに
僕は馬鹿なので真面目に

「ああ! 。<br /> ですね!」

と言ったら

「ないわwww」

って言われてクソワロタ.いやちょっと泣いたw
言い方が先輩らしくて懐かしくなってしまったぜ!