你似乎误解如何该正则表达式的作品。让我打破它给你:
(?= lookahead assertion: the following pattern must match, but
will not consume any of the text.
(.{3})* matches a series of 3 characters, any number of times. In
other words, this consumes characters in multiples of 3.
(.{4})$ makes sure there are exactly 4 characters left.
)
这种模式在要插入一个破折号-
每一个地方产生空匹配。这就是为什么preg_replace("/(?=(.{3})*(.{4})$)/", "-", "1231231234");
在正确的位置插入破折号 - 替换空字符串与插入相同。让我们来看看这一步一步,使用文本31231234
为例:
remaining text remaining pattern what happens
step 0: 31231234 (.{3})*(.{4})$ (.{3})* matches one time
step 1: 31234 (.{3})*(.{4})$ (.{3})* matches again
step 2: 34 (.{3})*(.{4})$ (.{3})* fails to match another time
step 3: 34 (.{4})$ (.{4}) fails to match -> backtrack
step 5: 31234 (.{4})$ (.{4}) fails to match -> pattern failed to
match, no dash will be inserted.
后的格局未能在位置0中的文本匹配,将再次在位置1检查(剩余的文本是1231234
):
remaining text remaining pattern what happens
step 0: 1231234 (.{3})*(.{4})$ (.{3})* matches one time
step 1: 1234 (.{3})*(.{4})$ (.{3})* matches again
step 2: 4 (.{3})*(.{4})$ (.{3})* fails to match another time
step 3: 4 (.{4})$ (.{4})$ matches -> dash will be inserted
here, giving "3-1231234"
同样的事情再次发生3个字符后,让最终的结果3-123-1234
。换言之,组(.{4})$
指定在文本的最后4个字符中不应插入破折号。通过消耗最后4个字符,如果剩余的字符数少于4个字符,则无法匹配模式。这就是为什么(.{4})(.{4})$
和(.{4}){2}$
都会产生8个字符的块 - 如果少于8个字符,则该模式不能匹配。
为了插入另一短跑在过去的8个字符,你必须使用4个字符.{4}
两组,让其中一人可选:
(?=((.{3})*.{4})?(.{4})$)
感谢您的详细解释。还有一个问题。当使用$时,它实际上是从这一点开始的回溯搜索,还是某种从左至右的重复?例如,在这个简单的测试中:https://regex101.com/r/eE6zK7/1它表示该比赛是在20步后发现的。 – Rafael
@Rafael:'$'只是一个字符串末尾的锚,它不会影响正则表达式的“方向”。如果你点击regex101上的“调试器”,你可以看到它是如何一步一步匹配的。 –