【问题标题】:preg_match_all returns only every second matchpreg_match_all 仅返回每第二个匹配项
【发布时间】:2020-09-12 08:20:16
【问题描述】:

我有这样的程序:

$txt = "
{ABC}
+ 1
- 1

{DEF}
+ 2
- 2

{IJK}
+ 3
- 3

{LMN}
+ 4 
- 4
";
preg_match_all('/\{.*?\{/s', $txt, $matches);
var_dump($matches);

我想匹配两个左大括号(或文本结尾)之间的所有内容。 但是我的结果只包含 ABC 和 IJK 块,因为下一个 { 已经被吃掉了。

array(1) {
  [0]=>
  array(2) {
    [0]=>
    string(16) "{ABC}
+ 1
- 1

{"
    [1]=>
    string(16) "{IJK}
+ 3
- 3

{"
  }
}

【问题讨论】:

  • 请注意,对于您的实际字符串,一个简单的explode("\n\n", $txt)(或preg_split('~\R\R~', $txt),如果您不确定换行顺序)会给您正确的结果。

标签: php regex preg-match-all


【解决方案1】:

使用正则表达式 lookahead (?=) 运算符将允许您匹配 { 之前的任何内容,而无需实际匹配 { 字符本身。

preg_match_all('/\{.*?(?=\{)/s', $txt, $matches)

会给你这个结果:

array(1) {
  [0]=>
  array(3) {
    [0]=>
    string(15) "{ABC}
+ 1
- 1

"
    [1]=>
    string(15) "{DEF}
+ 2
- 2

"
    [2]=>
    string(15) "{IJK}
+ 3
- 3

"
  }
}

您提到您还想匹配 { 和文本结尾之间的内容。您可以通过使用 pipe | 运算符和字符串结尾 anchor $ 在前瞻中来做到这一点。

preg_match_all('/\{.*?(?=\{|$)/s', $txt, $matches)

会给你想要的结果:

array(1) {
  [0]=>
  array(4) {
    [0]=>
    string(15) "{ABC}
+ 1
- 1

"
    [1]=>
    string(15) "{DEF}
+ 2
- 2

"
    [2]=>
    string(15) "{IJK}
+ 3
- 3

"
    [3]=>
    string(14) "{LMN}
+ 4 
- 4"
  }
}

【讨论】:

    【解决方案2】:

    我建议使用negated character class [^,它将匹配除左括号之外的任何字符。

    这样,它将从开头的{ 匹配到下一次出现{ 或字符串的结尾。

    {[^{]*
    

    Regex demo | Php demo

    例如

    preg_match_all('/{[^{]*/', $txt, $matches);
    

    【讨论】:

      猜你喜欢
      • 2014-12-26
      • 1970-01-01
      • 1970-01-01
      • 2014-12-23
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 2013-02-21
      • 1970-01-01
      相关资源
      最近更新 更多