PHPのパターンマッチで質問があります。

前回の質問で解決したはずなのですが、仕変のため、再度質問させてください。
次のフォーマットで文字列を抽出したいと思います。

●フォーマット
任意の文字列
[pat_A]任意の文字列A
[pat_B]任意の文字列B

●抜き出したい文字列
任意の文字列A
任意の文字列B

●特記事項
[pat_A]よりも前に任意の文字列が含まれる場合があります。
任意の文字列には、改行コード(\n\r)が含まれる場合があります。
任意の文字列Aは、[pat_A]~[pat_B]まで
任意の文字列Bは、[pat_B]~eofまで

これを正規表現で実現しようといろいろ試したのですが、なぜか改行が含まれません。

preg_match_all('/(\[pat_A|pat_B\])(.*|\n|\r)/', $msg, $n);
preg_match_all('/(\[pat_A|pat_B\])(.*|.*\n.*|.*\r.*)/', $msg, $n);

●例
$msg = "aaa
bbbbb
[pat_A]
cccc
[pat_B]dd
ee
fff";

●上記正規表現を実行した結果
1) pat_Aで抽出された文字列
なし
2) pat_Bで抽出された文字列
dd

●期待値
1) pat_Aで抽出したい文字列
cccc
2) pat_Bで抽出したい文字列
dd
ee
fff

[pat_A][pat_B]は出現順序が変わる可能性があるので、
strPosなどで文字列操作するより、できる限り正規表現を使いたいのです。

方法についてご教授をお願いいたします。

回答の条件
  • URL必須
  • 1人5回まで
  • 登録:
  • 終了:2009/12/24 01:57:33
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:kn1967 No.3

回答回数2915ベストアンサー獲得回数301

ポイント50pt

コメント欄が開いてないので、本回答で失礼しますと共に、

回答1は浅はかでした。申し訳ない。


改行を含む文字列であり、順不同、

さらに、特定の文字による判断が無理となれば、

一発では無理かと思いますので、下記提案します。

// パターン
$pat = '/(\[pat_A\]|\[pat_B\])/';
// 分割してデータ部分取り出し
$m = preg_split($pat, $msg);
array_shift($m);
// キー項目の取り出しと結合
preg_match_all($pat, $msg, $n);
$n[1] = $m;
// 結果出力
print_r($n);

PHP: preg_split - Manual

PHP: preg_match_all - Manual

id:cochoo

ご回答いただきありがとうございます。

この方法は気がつきませんでした。すごくいい方法だと思います。

すごくわがままなのですが、もう1つ質問させていただいてよろしいでしょうか?

仮に[pat_A][pat_B]が$msgに複数含まれる場合、foreachでカウントするより、

一発でそのマッチ数を知る方法はないでしょうか?

よろしくお願いいたします!

2009/12/24 00:16:24

その他の回答3件)

id:kn1967 No.1

回答回数2915ベストアンサー獲得回数301

ポイント20pt
preg_match_all('/(\[pat_A\]|\[pat_B\])(\r\n|\r|\n)?([^\[]+)/', $msg, $n);

もしくは

preg_match_all('/(\[pat_A\]|\[pat_B\])([^\[]+)/', $msg, $n);

上記の違いは[pat_A]や[pat_B]直後の改行を消し去るかどうかの違いです。


http://q.hatena.ne.jp/ダミーで失礼します。

id:cochoo

早速のご回答ありがとうございます。

なるほど、パターン区切り文字を次のパターンの"["としたわけですね。

ただ、これだと任意の文字列AかBの中に"["が含まれるとうまく動きません。

[^ ]だと文字列ではなく、1文字が含まれないとしか判断できません。

区切りを次の文字列[pattern_A]か[pattern_B]とすることはできないでしょうか?

2009/12/23 23:06:18
id:horonict No.2

回答回数257ベストアンサー獲得回数51

ポイント15pt

パターン修飾子を使い、以下のようにするのが正解です。

パターンAは $n[1] に、パターンBは $n[2] に代入されます。

preg_match("/\[pat_A\]([^\[pat_B\]]*)\[pat_B\](.*$)/ms", $msg, $n);

パターン修飾子とは

http://jp2.php.net/manual/ja/reference.pcre.pattern.modifiers.ph...

id:cochoo

ご回答ありがとうございます。

なるほど、やはりこうなりますよね。理解しました。

わがままをいわせていただくと、[pat_A]と[pat_B]の順序が入れ替わるというのはだめですよね^^;

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

2009/12/23 23:30:58
id:kn1967 No.3

回答回数2915ベストアンサー獲得回数301ここでベストアンサー

ポイント50pt

コメント欄が開いてないので、本回答で失礼しますと共に、

回答1は浅はかでした。申し訳ない。


改行を含む文字列であり、順不同、

さらに、特定の文字による判断が無理となれば、

一発では無理かと思いますので、下記提案します。

// パターン
$pat = '/(\[pat_A\]|\[pat_B\])/';
// 分割してデータ部分取り出し
$m = preg_split($pat, $msg);
array_shift($m);
// キー項目の取り出しと結合
preg_match_all($pat, $msg, $n);
$n[1] = $m;
// 結果出力
print_r($n);

PHP: preg_split - Manual

PHP: preg_match_all - Manual

id:cochoo

ご回答いただきありがとうございます。

この方法は気がつきませんでした。すごくいい方法だと思います。

すごくわがままなのですが、もう1つ質問させていただいてよろしいでしょうか?

仮に[pat_A][pat_B]が$msgに複数含まれる場合、foreachでカウントするより、

一発でそのマッチ数を知る方法はないでしょうか?

よろしくお願いいたします!

2009/12/24 00:16:24
id:kn1967 No.4

回答回数2915ベストアンサー獲得回数301

ポイント20pt

>[pat_A][pat_B]が$msgに複数含まれる場合、foreachでカウントするより、

>一発でそのマッチ数


回答3の方法では、複数の[pat_A]や[pat_B]の存在を容認しているため、

続けて下記コマンドを実行すれば、それぞれの個数を得られます。

// 要素の内容毎に集計
$c = array_count_values($n[0]);
// 結果出力
print_r($c);

PHP: array_count_values - Manual


※この程度ならコメント欄でかまいませんよ。

 そのほうが多分レスポンス早くなりますし・・・。

id:cochoo

遅くにご回答ありがとうございます。

本当に助かりました。ありがとうございました。

# コメント欄!?そうですね。ご配慮くださりありがとうございました。

2009/12/24 01:56:46
  • id:kn1967
    コメント欄が使えるようになったし、
    新質問 http://q.hatena.ne.jp/1261587226 とも関連しそうなので追記

    回答3の
    $n[1] = $m;

    $h = array();
    $c = count($n[0]);
    for($i = 0; $i < $c; $i++){
    $h[$n[0][$i]] .= $m[$i];
    }
    とすると $h に合成された結果がでてきますので、お試しあれ。
  • id:cochoo
    ご連絡が遅くなり申し訳ありません。
    この方法です!期待していたのは!
    こういう方法があったのですね。ありがとうございます。

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

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

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

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