7

私は基本的な正規表現で大丈夫ですが、pos/neg先読み/後ろ見の周りで少し迷子になります。

私はこれからID#を取得しようとしています:

[キーワードstuff=otherstuff id = 123 morestuff = stuff]

前後に無制限の量の「もの」が存在する可能性があります。私は自分が試したことをデバッグするために正規表現コーチを使用してきましたが、もう前進していません...

これまでのところ私はこれを持っています:

\[keyword (?:id=([0-9]+))?[^\]]*\]

これはidの後の余分な属性を処理しますが、keywordとidの間のすべてを無視する方法がわかりません。行くことができないことはわかってい[^id]* ますが、このようなネガティブな先読みを使用する必要(?!id)*があると思いますが、幅がゼロであるため、そこから先に進むことはないと思います。これも機能しません:

\[keyword[A-z0-9 =]*(?!id)(?:id=([0-9]+))?[^\]]*\]

私は例を探し回っていますが、見つかりませんでした。あるいは、私は持っているかもしれませんが、彼らは私の頭をはるかに超えて行きました。私は彼らが何であるかさえ知りませんでした。

ヘルプ!ありがとう。

編集:[keyword stuff = otherstuff]にも一致する必要があります。ここで、id =はまったく存在しないため、id#グループに1または0を指定する必要があります。他にも、一致させたくない[otherkeywords id=32]があります。ドキュメントは、preg_match_allを使用して、ドキュメント全体で複数の[keyword id=3]と一致する必要があります。

4

3 に答える 3

2

先読み/後れは必要ありません:

/\[keyword(?:[^\]]*?\bid=([0-9]+))?[^\]]*?\]/

実際のタグの終わりをチェックするために末尾の「[^]]*]」を追加しました。不要な場合があります。

編集:他の方法では一致する可能性があるため、IDに\bを追加しました[keyword you-dont-want-this-guid=123123-132123-123 id=123]

$ php -r 'preg_match_all("/\[keyword(?:[^\]]*?\bid=([0-9]+))?[^\]]*?\]/","[keyword stuff=otherstuff morestuff=stuff]",$matches);var_dump($matches);'
array(2) {
  [0]=>
  array(1) {
    [0]=>
    string(42) "[keyword stuff=otherstuff morestuff=stuff]"
  }
  [1]=>
  array(1) {
    [0]=>
    string(0) ""
  }
}
$ php -r 'var_dump(preg_match_all("/\[keyword(?:[^\]]*?\bid=([0-9]+))?[^\]]*?\]/","[keyword stuff=otherstuff id=123 morestuff=stuff]",$matches),$matches);'
int(1)
array(2) {
  [0]=>
  array(1) {
    [0]=>
    string(49) "[keyword stuff=otherstuff id=123 morestuff=stuff]"
  }
  [1]=>
  array(1) {
    [0]=>
    string(3) "123"
  }
}
于 2010-07-20T00:50:19.950 に答える
2

あなたは前/後ろを見る必要はありません。

質問にはPHPのタグが付いているため、 preg_match_all()を使用して、一致を$matchesに保存します。

方法は次のとおりです。

<?php

  // Store the string. I single quote, in case there are backslashes I
  // didn't see.
$string = 'blah blah[keyword stuff=otherstuff id=123 morestuff=stuff]
           blah blah[otherkeyword stuff=otherstuff id=555 morestuff=stuff]
           blah blah[keyword stuff=otherstuff id=444 morestuff=stuff]';

  // The pattern is '[keyword' followed by not ']' a space and id
  // The space before id is important, so you don't catch 'guid', etc.
  // If '[keyword'  is always at the beginning of a line, you can use
  // '^\[keyword'
$pattern = '/\[keyword[^\]]* id=([0-9]+)/';

  // Find every single $pattern in $string and store it in $matches
preg_match_all($pattern, $string, $matches);

  // The only tricky part you have to know is that each entire match is stored in
  // $matches[0][x], and the part of the match in the parentheses, which is what
  // you want is stored in $matches[1][x]. The brackets are optional, since it's
  // only one line.
foreach($matches[1] as $value)
{     
    echo $value . "<br/>";
}
?>

出力:

123
444   

(555はスキップされます)

PS

\b代わりにタブがある場合は、リテラルスペースの代わりに使用することもできます。\b単語の境界を表します...この場合は単語の始まりです。

$pattern = '/\[keyword[^\]]*\bid=([0-9]+)/';
于 2010-07-20T00:51:01.893 に答える
0

私はこれがあなたが得ているものだと思います:

\[keyword(?:\s+(?!id\b)[A-Za-z]+=[^\]\s]+)*(?:\s+id=([0-9]+))?[^\]]*\]

(属性名にはASCII文字のみを含めることができ、値には空白以外の文字を含めることができると想定しています]。)

(?:\s+(?!id\b)[A-Za-z]+=[^\]\s]+)*attribute=value属性名がでない限り、任意の数のペア(およびそれらの前の空白)に一致しますid。(単語の境界)は、のように、で始まる\b属性名がある場合に備えてあります。今回は属性名の前にを付ける必要はありません。これは、一致する名前の前に空白が付くことがわかっているためです。しかし、あなたが学んだように、この場合、先読みアプローチはやり過ぎです。ididiocy\b

さて、これについて:

[A-z0-9 =]

これA-zはタイプミスまたはエラーのいずれかです。すべての大文字と小文字に一致することを期待している場合は、そうです。しかし、それはまた一致します

'[', ']', '^', '_', '`` and '\'

...コードポイントが大文字と小文字の間にあるためです。ASCII文字、つまり。

于 2010-07-20T04:37:42.837 に答える