PHP正则表达式和相邻的捕获组

rin*_*t.6 8 php regex string backreference camelcasing

我第一次在正则表达式中使用捕获组,我想知道我的问题是什么,因为我假设正则表达式引擎从左到右查看字符串.

我正在尝试将UpperCamelCase字符串转换为hyphened-lowercase-string,例如:

HelloWorldThisIsATest => hello-world-this-is-a-test
Run Code Online (Sandbox Code Playgroud)

我的前提条件是字母字符串,所以我不需要担心数字或其他字符.这是我尝试过的:

mb_strtolower(preg_replace('/([A-Za-z])([A-Z])/', '$1-$2', "HelloWorldThisIsATest"));
Run Code Online (Sandbox Code Playgroud)

结果:

hello-world-this-is-atest
Run Code Online (Sandbox Code Playgroud)

这几乎是我想要的,除了a和之间应该有一个连字符test.我已经包含A-Z在我的第一个捕获组中,所以我会假设引擎看到AT并连接了那个.

我究竟做错了什么?

zx8*_*x81 6

你的正则表达式不起作用的原因:重叠匹配

  • 您正则表达式匹配sAIsATest,可以让你插入-之间sA
  • 为了-A和之间插入T,正则表达式必须匹配AT.
  • 这是不可能的,因为A它已经作为一部分匹配sA.您不能在直接正则表达式中重叠匹配.
  • 所有希望都失去了吗?没有!对于外观来说,这是一个完美的情况.

用两条简单的线条做

这是使用正则表达式执行此操作的简单方法:

$regex = '~(?<=[a-zA-Z])(?=[A-Z])~';
echo strtolower(preg_replace($regex,"-","HelloWorldThisIsATest"));
Run Code Online (Sandbox Code Playgroud)

请参阅php演示文稿底部的输出:

输出: hello-world-this-is-a-test

马上就会添加解释.:)

  • 正则表达式与任何字符都不匹配.相反,它针对字符串中的位置:字母大小写的变化之间的位置.为此,它使用了lookbehind和lookahead
  • (?<=[a-zA-Z])回顾后发断言,什么先于当前位置是信
  • (?=[A-Z])预测先行断言,接下来的当前位置是一个大写字母.
  • 我们只用a替换这些位置-,并将批次转换为小写.

如果仔细查看此regex101屏幕,可以看到正则表达式匹配的单词之间的线条.

参考


Ja͢*_*͢ck 5

为简单起见,我将两个正则表达式分开:

preg_replace(array('/([a-z])([A-Z])/', '/([A-Z]+)([A-Z])/'), '$1-$2', $string);
Run Code Online (Sandbox Code Playgroud)

它处理字符串两次以查找:

  1. 小写 - >大写边界
  2. 多个大写字母后跟另一个大写字母

这将有以下行为:

ThisIsHTMLTest -> This-Is-HTML-Test
ThisIsATest    -> This-Is-A-Test
Run Code Online (Sandbox Code Playgroud)

或者,使用前瞻断言(这将影响上一次匹配中使用的最后一个大写字母的重用):

preg_replace('/([A-Z]+|[a-z]+)(?=[A-Z])/', '$1-', $string);
Run Code Online (Sandbox Code Playgroud)