PHP 正则表达式和相邻的捕获组 | 珊瑚贝

PHP regex and adjacent capturing groups


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

我正在尝试将 UpperCamelCase 字符串转换为连字符小写字符串,例如:

1
HelloWorldThisIsATest => helloworldthisisatest

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

1
mb_strtolower(preg_replace(‘/([A-Za-z])([A-Z])/’, ‘$1-$2’,“HelloWorldThisIsATest”));

结果:

1
helloworldthisisatest

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

我做错了什么?

  • “HelloWorldHTMLTest” 呢?那应该变成 “hello-world-html-test” 还是 “hello-world-h-t-m-l-test”?
  • @Jack 我没想到的有趣用例……我会说第一个。


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

  • 您的正则表达式匹配 IsATest 中的 sA,允许您在 s 和 A 之间插入 –
  • 为了在 A 和 T 之间插入 -,正则表达式必须匹配 AT。
  • 这是不可能的,因为 A 已经作为 sA 的一部分进行了匹配。在直接正则表达式中不能有重叠匹配。
  • 所有的希望都失去了吗?不!这是环视的完美情况。

用两条简单的线做到这一点

这是使用正则表达式的简单方法:

1
2
$regex = ‘~(?<=[a-zA-Z])(?=[A-Z])~’;
echo strtolower(preg_replace($regex,“-“,“HelloWorldThisIsATest”));

查看 php 演示底部的输出:

Output: hello-world-this-is-a-test

稍后会添加解释。 :)

  • 正则表达式不匹配任何字符。相反,它针对字符串中的位置:字母大小写变化之间的位置。为此,它使用后视和前瞻
  • (?<=[a-zA-Z]) 后视断言当前位置之前是一个字母
  • (?=[A-Z]) 前瞻断言当前位置后面是一个大写字母。
  • 我们只是用 – 替换这些位置,并将手数转换为小写。

如果您仔细查看此 regex101 屏幕,您会看到单词之间的线条,其中 regex 匹配。

参考

  • 前瞻和后瞻零长度断言
  • 掌握前瞻和后瞻
  • 您的正则表达式无法工作的原因是它需要允许连续匹配。稍后将对此进行解释。您必须像我的回答一样使用环视。
  • 你的问题说 I’m wondering what my problem is… 我的回答实际上提供了一个解释。
  • 我也喜欢你的回答,因为它解释了为什么我的正则表达式不起作用。
  • 您的正则表达式将仅匹配两个字母。
  • @AvinashRaj 查看我的演示。 :)
  • @AvinashRaj 谢谢,我知道你是一名正则表达式学者——这是解决这类问题的最佳解决方案(零宽度匹配。)
  • 谢谢林克,下次见。 :)


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

1
preg_replace(array(‘/([a-z])([A-Z])/’, ‘/([A-Z]+)([A-Z])/’), ‘$1-$2’, $string);

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

  • 小写 -> 大写边界
  • 多个大写字母后跟另一个大写字母
  • 这将具有以下行为:

    1
    2
    ThisIsHTMLTest -> ThisIsHTMLTest
    ThisIsATest    -> ThisIsATest

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

    1
    preg_replace(‘/([A-Z]+|[a-z]+)(?=[A-Z])/’, ‘$1-‘, $string);


    • +1,好清晰的解决方案,也解决了多个大写缩写的用例
    • 我们确定没有因为角色安排而不需要三遍的情况吗?……或者更多……?我有一种预感,可能就是这种情况。
    • 1 因为它涵盖了将来可能适用于我的用例,也是一个很好的解决方案
    • @zx81 虽然在技术上是可行的,但您使用的首字母缩略词将完全以大写字母命名。
    • @rink.attendant.6 顺便说一句,我已经设法将它全部压缩到一个正则表达式中:)
    • 嗯,不太确定…在我看来,第一次通过时,字符串被 – 的任意数字扩展,这可能是奇数或偶数…因此,在第一次通过时遗漏了两个位置最终可能会得到不同的平价。但是我的直觉可能是错误的,我并没有停下来在纸上解决它。
    • @zx81 当你有的时候让我;我很想看看是否有”失败”的案例。
    • 嘿,杰克,IMO 最好的确定方法是对具有随机序列的文件进行测试。没有时间,但我拿了一篇维基百科文章,删除了 [^a-zA-Z]+ 并运行了两个替换。如你所料,剩下的大写字母还不少,一个也没有。值得尝试更大的样本,因为在普通文本中没有那么多大小写切换。下次见! :)


    为了修复 Jack 在您的评论中提到的有趣用例(避免缩写词的拆分),我采用了 zx81 的使用前瞻和后瞻的路线。

    1
    (?<=[az])(?=[AZ])|(?<=[AZ])(?=[AZ][az])

    你可以一分为二来解释:

    第一部分

    1
    2
    3
    4
    5
    6
    (?<=                     look behind to see if there is:
      [az]                    any character of: ‘a’ to ‘z’
    )                        end of lookbehind
    (?=                      look ahead to see if there is:
      [AZ]                    any character of: ‘A’ to ‘Z’
    )                        end of lookahead

    (TL;DR: CamelCase Pattern 的字符串之间的匹配。)

    第二部分

    1
    2
    3
    4
    5
    6
    7
    (?<=                     look behind to see if there is:
      [AZ]                    any character of: ‘A’ to ‘Z’
    )                        end of lookbehind
    (?=                      look ahead to see if there is:
      [AZ]                    any character of: ‘A’ to ‘Z’
      [az]                    any character of: ‘a’ to ‘z’
    )                        end of lookahead

    (TL;DR: 特殊情况,缩写和驼峰模式匹配)

    所以你的代码是:

    1
    mb_strtolower(preg_replace(‘/(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/’, ‘-‘,“HelloWorldThisIsATest”));

    比赛演示

    代码演示

    • 当我看到帖子被编辑时,我正要评论要求解释!谢谢,这就是我要找的。我会在几分钟内接受答案。
    • 它们都是很好的答案,但我不得不接受另一个答案,因为它为我的问题的第一部分提供了解释。


    来源:https://www.codenong.com/24359865/

    微信公众号
    手机浏览(小程序)

    Warning: get_headers(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed in /mydata/web/wwwshanhubei/web/wp-content/themes/shanhuke/single.php on line 57

    Warning: get_headers(): Failed to enable crypto in /mydata/web/wwwshanhubei/web/wp-content/themes/shanhuke/single.php on line 57

    Warning: get_headers(https://static.shanhubei.com/qrcode/qrcode_viewid_9289.jpg): failed to open stream: operation failed in /mydata/web/wwwshanhubei/web/wp-content/themes/shanhuke/single.php on line 57
    0
    分享到:
    没有账号? 忘记密码?