可变大小的前瞻消费

Variable sized lookahead consume

我正在尝试使用正则表达式来解析使用 php 的不同字符串,例如,该字符串可以是;

"twoX // threeY"

"twoX /// threeY"

所以有一个左关键字,一个由 2 或 3 个斜杠和一个右关键字组成的 divider。这些也是我想单独消费的部分。

"/((?<left>.+)?)(?=(?<divider>[\/]{2,3}))([\/]{2,3})((?<right>.+)?)/";

当我在第一个字符串上使用这个正则表达式时,所有内容都被正确解析,所以;

left: twoX

divider: //

right: threeY

但是当我在第二个字符串上 运行 这个表达式时, leftdivider 不会被解析适当地。我得到的结果是;

left: twoX /

divider: //

right: threeY

我在正则表达式中使用 {2,3} 来 select 2 或 3 个斜杠作为分隔符。但这在某种程度上似乎不适用于全匹配字符 .

有没有办法让正则表达式在不复制整个序列的情况下解析 2 个或 3 个斜杠?

(.+)? 是一个贪婪的点匹配模式,匹配尽可能多的字符,1 是最小值。因此,由于下一个模式只需要 2 个字符,下一组将只捕获 2 个字符,第一个 / 将属于第 1 组。

在第一组中使用 lazy 模式:

'~(?<left>.*?)(?<divider>/{2,3})(?<right>.*)~'
          ^^^

regex demo。如有必要,在模式周围添加 ^$ 锚点以匹配整个字符串。

请注意,您不需要在前瞻和消费模式部分重复相同的模式,这只会使模式变得麻烦,(?=(?<divider>[\/]{2,3}))([\/]{2,3}) = (?<divider>[\/]{2,3}).

详情

  • (?<left>.*?) - 组 "left" 匹配除换行字符以外的任何 0+ 个字符,尽可能 few
  • (?<divider>/{2,3}) - 2 或 3 个斜杠(无需转义,因为 ~ 用作正则表达式分隔符)
  • (?<right>.*) - 将 "right" 匹配除换行符以外的任何 0+ 个字符作为 many 尽可能匹配(直到行尾)。

还有一种看起来更自然的拆分方法,请参阅 PHP demo:

$s = "twoX // threeY";
print_r(preg_split('~\s*(/{2,3})\s*~', $s, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY));
// => Array ( [0] => twoX [1] => // [2] => threeY )

您丢失了名称,但您可以在稍后的步骤中添加它们。

+ 量词默认是贪心的,这意味着它将尝试匹配尽可能多的字符。所以你想让第一个 + 懒惰,这样它就不会尝试匹配第一个 / 通过添加 ? 量词你可以使 + 懒惰:+?.
这将导致以下正则表达式:

((?<left>.+?)?)(?=(?<divider>[\/]{2,3}))([\/]{2,3})((?<right>.+)?)