人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

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などで文字列操作するより、できる限り正規表現を使いたいのです。

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


●質問者: cochoo
●カテゴリ:ウェブ制作
✍キーワード:AAA dd FFF PHP コード
○ 状態 :終了
└ 回答数 : 4/4件

▽最新の回答へ

1 ● kn1967
●20ポイント
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/ダミーで失礼します。

◎質問者からの返答

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

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

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

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

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


2 ● horonict
●15ポイント

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

パターン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...

◎質問者からの返答

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

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

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

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


3 ● kn1967
●50ポイント ベストアンサー

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

回答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

◎質問者からの返答

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

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

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

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

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

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


4 ● kn1967
●20ポイント

>[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


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

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

◎質問者からの返答

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

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

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

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ