【问题标题】:PHP regex catch the first pattern and everything after it even if it repeats.PHP regex 捕获第一个模式和它之后的所有内容,即使它重复。
【发布时间】:2016-11-02 17:03:36
【问题描述】:

我正在为聊天机器人进行语音识别,我需要它来简单地捕捉模式(包括模式)之后的所有内容并将其放入一个输出数组中。我认为这很容易,但我无法让它发挥作用。初始分割模式可能会重复,如果它稍后在字符串中重复,它似乎使用它作为分割点而不是第一次出现。可能有一种简单的方法可以做到这一点。

$input_line = "aaaa delimit bbbb delimit cccc delimit dddd delimit eeee";

preg_match("/(.+) (delimit) (.+)/", $input_line, $output_array);

我希望输出匹配之一是

 => delimit bbbb delimit cccc delimit dddd delimit eeee

但我得到的输出数组是

array(4
0=>aaaa delimit bbbb delimit cccc delimit dddd delimit eeee
1=>aaaa delimit bbbb delimit cccc delimit dddd
2=>delimit
3=>eeee)

所以我只想捕捉第一个分隔符以及它之后的所有内容,即使还有其他分隔符。我试过了:

(.+) ((delimit) (.+)){1}

以及使用 *,?,{} 的其他变体,但似乎无法获得它。对于此示例,4 个字母的组(即 aaaa)可以表示用户可能与定界词一起输入的任何词串。

【问题讨论】:

  • 你过度使用了捕获组。只需使用preg_match("/.*?(delimit.*)/s", $input, $match)(注意第一个.* 是懒惰的-.*? 可以到达第一个delimit)。甚至preg_match("/delimit.*/s", $input_line, $m)

标签: php regex


【解决方案1】:

您在数组中获得了如此多的元素,因为您在模式中使用了太多的捕获组。由于正则表达式 egnine 从左到右解析字符串,您可以将您的模式定义为 /pattern.*/s - 它会找到第一个 pattern 然后将匹配任何 0+ 字符(甚至包括换行符,因为 /s 修饰符启用了 DOTALL点匹配任何字符时的模式)。

要匹配第一个 delimit 之前的任何内容,然后是它之后的内容,请在 delimit 之前使用 (.*?),以便惰性 *? 匹配任何 0+ 字符,直到第一次出现 @ 987654330@:

preg_match("/(.*?)(delimit.*)/s", $input, $match)

regex demo

示例代码:

$input_line = "aaaa delimit bbbb delimit cccc delimit dddd delimit eeee";
if (preg_match("/(.*?)(delimit.*)/s", $input_line, $m)) {
  echo $m[1] . "\n";
  echo $m[2];
}

输出:

aaaa
delimit bbbb delimit cccc delimit dddd delimit eeee

online PHP demo

【讨论】:

  • 如果我理解了这个问题,请告诉我。
  • 是的,这似乎可以满足我的需求。看来我的错误是不了解如何使用 *?像你一样使用太多的捕获组。感谢您的帮助!
  • 对不起,我不是很忙,我在哪里接受你的回答?
【解决方案2】:

preg_split 的另一种可能方法:

$res = preg_split('~(?=delimit)~', $str, 2)[1];

模式使用前瞻(向前看)在分隔符开始的位置成功。第三个参数设置为2(两部分),这样正则表达式引擎在第一次出现时停止搜索。

显然,如果“delimit”是一个固定字符串,不要使用正则表达式,而是使用explode

【讨论】:

    猜你喜欢
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 2017-05-05
    • 2017-09-16
    • 2022-12-04
    • 2017-06-11
    • 1970-01-01
    • 2017-07-22
    相关资源
    最近更新 更多