【问题标题】:Regex for a period not immediatly following a word in a list, without variable length lookbehind?正则表达式不紧跟列表中的一个单词,没有可变长度的后视?
【发布时间】:2017-08-31 10:21:58
【问题描述】:

我正在尝试编写一个匹配句点紧跟在列表中的单词之后的正则表达式。

我相信我需要一个前瞻或后向断言来执行此操作,并且我已经尝试过:

/(?!(mr|ms|mrs))\./u/(?!(mr|ms|mrs)\.)\./u

这两个都匹配所有句点,因此不排除单词后面的句点。

我还尝试了一个lookbehind,我相信这是我需要的:

/(?<!(mr|ms|mrs))\./u

但看起来那些必须是固定长度,因为它不会编译:preg_replace(): Compilation failed: lookbehind assertion is not fixed length at offset 15

这里有几个测试用例,以及使用 preg replace 删除匹配项时的预期结果:

'Mr. Tom A. Suggins'     // Mr. Tom A Suggins
'Mrs.. Jane P Suggins, jr.'   // Mrs. Jane P Suggins, jr
'.Ms.. .Jane P. Suggins' // Ms. Jane P Suggins

在没有可变长度后向支持的情况下,有没有办法在 PHP 中做到这一点?

【问题讨论】:

    标签: php regex


    【解决方案1】:

    您可以在 PCRE 正则表达式中使用 (*SKIP)(*F) 动词来失败/跳过某些选定的匹配;

    $repl = preg_replace('/(?:Mrs?|Ms)\.(*SKIP)(*F)|\./', '', $str);
    

    RegEx Demo

    【讨论】:

      【解决方案2】:
      /(?<!mr|ms|mrs)\./u
      

      只需稍作改动即可修复:

      /(?<!m[rs])(?<!mrs)\./u
      

      Demo

      【讨论】:

      • 确实如此。正如你所问的,它相当于/(?&lt;!(mr|ms|mrs))\./u。如果要使大小写不敏感,则需要添加i。如果要查找所有匹配项,需要添加gTest
      • 要明确(?&lt;!mr|ms|mrs)\. 根本不需要修复,因为在后视中允许更改固定分支。 (?&lt;!(mr|ms|mrs))\. 的问题只是额外的捕获组。
      【解决方案3】:

      使用这个正则表达式来匹配这些句点:

      (?:mrs|m[rs])\.\K|\.
      

      然后将它们替换为空:

      preg_repalce('~(?:mrs|m[rs])\.\K|\.~i', '', $content);
      

      Live demo

      【讨论】:

      • 加一个,因为\K 似乎比(*SKIP)(*F) 更简洁。不过我只能接受一个答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-29
      • 1970-01-01
      • 1970-01-01
      • 2012-02-21
      • 2013-06-22
      • 2014-05-18
      相关资源
      最近更新 更多