可变大小的前瞻消费
Variable sized lookahead consume
我正在尝试使用正则表达式来解析使用 php 的不同字符串,例如,该字符串可以是;
"twoX // threeY"
或
"twoX /// threeY"
所以有一个左关键字,一个由 2 或 3 个斜杠和一个右关键字组成的 divider
。这些也是我想单独消费的部分。
"/((?<left>.+)?)(?=(?<divider>[\/]{2,3}))([\/]{2,3})((?<right>.+)?)/";
当我在第一个字符串上使用这个正则表达式时,所有内容都被正确解析,所以;
left: twoX
divider: //
right: threeY
但是当我在第二个字符串上 运行 这个表达式时, left 和 divider 不会被解析适当地。我得到的结果是;
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>.+)?)
我正在尝试使用正则表达式来解析使用 php 的不同字符串,例如,该字符串可以是;
"twoX // threeY"
或
"twoX /// threeY"
所以有一个左关键字,一个由 2 或 3 个斜杠和一个右关键字组成的 divider
。这些也是我想单独消费的部分。
"/((?<left>.+)?)(?=(?<divider>[\/]{2,3}))([\/]{2,3})((?<right>.+)?)/";
当我在第一个字符串上使用这个正则表达式时,所有内容都被正确解析,所以;
left: twoX
divider: //
right: threeY
但是当我在第二个字符串上 运行 这个表达式时, left 和 divider 不会被解析适当地。我得到的结果是;
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>.+)?)