秀丸とPHPの正規表現の違いについて - PHPプロ!Q&A掲示板

1343

  • 0P

秀丸とPHPの正規表現の違いについて

質問日時 / 2008年7月29日 11:49    回答数 / 4件

Questioner:  torres23  このエントリーをはてなブックマークに追加 

キーワード / 正規表現    $pattern    表記方法   

  1. $file = file("Log.txt");
  2.  
  3. foreach($file as $line){
  4.    if(preg_match('/(?<=^\x20{0,3}[0-9]{1,5}:Thread\x2d[0-9]{1,3}\x20{0,6}:XXXX:\x5bDEBUG\x5d Output_ \x3d )[0-9]{1,3}/', $line, $array)){
  5.     echo $array[0];
  6.    }

上記のプログラム(抜粋)でログファイル内の特定の文字列(値)を検索し、ログファイルにはかれた設定値
を表示したいと考えていますが、このプログラムでは下記のエラーが発生してしまいます。

Warning: preg_match() [function.preg-match]: Compilation failed: lookbehind assertion is not fixed length at offset 90 in
C:\xampp\htdocs\XXXXX.php on line 18

line 18はif(preg_match(~ の行です。

エラー内容について検索、和訳してみましたが
意味がよくわかりませんでした。

ちなみに事前に秀丸で上記の正規表現を使用して検索をかけると
期待した文字列がヒットし正常に動作しています。

そこでお聞きしたいのですが、秀丸とPHPの正規表現に違いが存在しますでしょうか?
また上記プログラムに問題があれば教えて頂けないでしょうか。

この質問への意見の募集は締め切られ、ポイントは既に配分されました。
意見を投稿することはできますが、ポイントを受け取ることはできません。



ツリー一覧

┣A01kaitauこんにちは。 秀丸で使われている正規表現エンジン
┃┗A01-1torres23詳しい説明ありがとうございます。 マニュアルに戻り
┗A02NurseAngel?<=は戻り読みですが、 PHPの正規表現は戻り読みは固
 ┗A02-1torres23ご回答ありがとうございます。 リンク先の説明はシン

回答一覧

並び替え:

A01 満足
answererkaitau [7月29日 13:03] (最終編集:7月29日 13:05)

こんにちは。

秀丸で使われている正規表現エンジンはJRE32.dllの派生で、
一方PHPのpreg_match系はPerl互換となっています。

元が何であるにせよ同じ動作であるに越したことはないのですが、
今回のようなケースだと、異なる場合があるようです。

さて、プログラムの問題についてですが、
PHPの公式のマニュアルの正規表現の構文の説明によると、
言明の項目(http://jp2.php.net/manual/ja/regexp.reference.php#regexp.reference.assertions)
の5番目あたりのブロックに、
「戻り読み言明内のパターンは、それがマッチし得る文字列の長さが 固定でなければなりません〔繰り返しを指定できません〕。」
とあります。(これの一つ上のブロックに戻り読み言明(lookbehind assertion)の記述があります。 )

すなわち、本題のパターンでは、(?<= )内部において、{}の回数マッチを行っているため、これがPerl互換正規表現では機能しないのでしょう。(実際に手持ちのperl 5.8.5 でもエラーになりました。)

対処法についてですが、言明を用いた正規表現は、(xmlタグなどで)意識して特定のパターンに続く後方を抜き出したい場合や、preg_replaceで置換を施す場合などに特に有効ではあるものの、今回は一行ごとにマッチを抜き出すだけなので、特に言明に拘らずにサブパターンで抜き出せば良いのではないでしょうか。

サンプル
  1. <?php
  2.  
  3. $line = '  12345:Thread-6:XXXX:[DEBUG] Output_ = 789';
  4. //パターン中、後方の二番目のカッコ「([0-9]{1,3})」が、拾いたい値
  5. if(preg_match('/(^\x20{0,3}[0-9]{1,5}:Thread\x2d[0-9]{1,3}\x20{0,6}:XXXX:\x5bDEBUG\x5d Output_ \x3d )([0-9]{1,3})/'$line$array)) {
  6.   //二番目を表示
  7.   echo "MATCH:$array[2]\n";
  8.   var_dump($array);
  9. } else {
  10.   echo "NO match.\n";
  11. }
  12. ?>

結果:
  1. MATCH:789
  2. array(3) {
  3.   [0]=>
  4.   string(43) "  12345:Thread-6:XXXX:[DEBUG] Output_ = 789"
  5.   [1]=>
  6.   string(40) "  12345:Thread-6:XXXX:[DEBUG] Output_ = "
  7.   [2]=>
  8.   string(3) "789"
  9. }

この意見に回答する

ツリーへ TOPへ

A01-1
replyertorres23 [7月29日 17:08]

詳しい説明ありがとうございます。
マニュアルに戻り読みが使用できない事が明記されていたのですね。チェック不足でした。
kaitauさんがおっしゃる通り、今回は一行ごとにマッチを検索するだけですので
kaitauさんにご提示頂いたサンプルのように実装する事で解決致しました。
また何かありましたらよろしくお願い致します。

この意見に回答する

ツリーへ TOPへ

A02 参考になった
answererNurseAngel [7月29日 13:47]

?<=は戻り読みですが、
PHPの正規表現は戻り読みは固定長しかサポートしていません。


/(?<=abc)/はOKだが
/(?<=ab+c)/はだめみたいです。


http://d.hatena.ne.jp/cubicdaiya/20071201/1196513384
http://www.geocities.jp/kosako3/oniguruma/doc/RE.ja.txt

この意見に回答する

ツリーへ TOPへ

A02-1
replyertorres23 [7月29日 17:09]

ご回答ありがとうございます。
リンク先の説明はシンプルでわかりやすかったです。

この意見に回答する

ツリーへ TOPへ

<<質問一覧へ



Pick Up Q&A

Q
PHPのHTML埋め込み記述について
 このエントリーをはてなブックマークに追加 
A
$_POST["data"] == "男" ? $val = "checked" : $val = "" ; の意味は以下と同じです。 if($_POST["data"] == "男"){ $val = "checked; } e...

>>続きを読む

kende様のご指摘通り、三項演算子を使用する際には、コードの複雑度などを考慮する必要がありますね。書きやすさと共に可読性も追求したいところですね。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)