理解正则表达式

18

我厌倦了对正则表达式感到害怕。本文的主题仅限于PHP实现的正则表达式,但任何通用的正则表达式建议显然都会受到欢迎(例如,请不要让我困惑于与PHP不适用的范围)。

以下内容(据我所知)将删除数字之间的任何空格。也许有更好的方法来做到这一点,但我仍然希望理解发生了什么。

$pat="/\b(\d+)\s+(?=\d+\b)/";
$sub="123 345";
$string=preg_replace($pat, "$1", $sub);

经过模式匹配,我的解释是:

  • \b 一个单词边界
  • \d+ 一个或多个数字的子模式
  • \s+ 一个或多个空格
  • (?=\d+\b) 向前断言,要求后面有一个或多个数字紧接着单词边界?
  • 综上所述,查找任何单词边界后跟一个或多个数字然后是一些空格,然后进行某种向前断言,并将结果保存在$1中以替换该模式。

问题:

  • 我的解释正确吗?
  • 那个向前断言是什么意思?
  • 前导/和尾随/的目的是什么?

答案:

经过模式匹配,我理解如下:

  • \b:一个单词边界。
  • \d+:匹配一个或多个数字的子模式。
  • \s+:匹配一个或多个空格。
  • (?=\d+\b):正向预查,要求其后紧接着一个或多个数字并且后面跟单词边界。
  • 将以上内容联合起来,查找任何一个单词边界后跟着一个或多个数字并且后面跟着一些空格,然后进行正向预查,并将结果保存在$1中以替换这个模式。

问题:

  • 我的解释正确吗?
  • 那个正向预查的含义是什么?
  • 前导/和尾随/的作用是什么?
回答:
  • 你的解释是正确的。
  • 正向预查是指在匹配字符串时,在当前位置向前检查是否有满足指定条件的字符或者子串,但是不将该字符或子串计入最终匹配结果。这里的正向预查要求其后紧接着一个或多个数字并且后面跟单词边界。
  • 前导/和尾随/是正则表达式的分隔符,用于标识正则表达式的开始和结束。

  • 9
    供参考和教程使用:http://regular-expressions.info - deceze
    请参考以下工具来查找开源RegexBuddy替代品和在线正则表达式测试:Open source RegexBuddy alternativesOnline regex testing,或者访问提到的 RegExp.info - mario
    谢谢。我现在正在查看deceze的建议,稍后会看其他人的。 - user1032531
    1
    虽然基于ruby的regex(不确定是否有很大差异),但我也发现http://www.rubular.com/是其中一个易于使用的在线正则表达式测试器。 - RhodriM
    我强烈推荐您使用Kodos,以便更轻松地掌握正则表达式技能(它也更容易调试正则表达式并测试不同的正则表达式语句修改)。 - tulvit
    2个回答

    18

    我的上述解释正确吗?

    是的,您的解释是正确的。

    这个前瞻断言是什么意思?

    这个前瞻断言是一种匹配具有特定模式字符前面的字符的方法,而不必实际匹配该模式。

    因此,使用正则表达式abcd(?=e)来匹配字符串abcde将会给你匹配结果:abcd

    之所以能够匹配成功,是因为字符串abcde确实包含:

    1. 一个a
    2. 后面跟着一个b
    3. 后面跟着一个c
    4. 后面跟着一个d,其后面紧跟着一个e(这是一个单一的字符!)

    需要注意的是,在第四个项目后,它还包含了实际的字符"e",而我们没有对其进行匹配。

    另一方面,如果尝试使用正则表达式abcd(?=f)来匹配该字符串,则会失败,因为序列中没有f字符:

    "a", followed by "b", followed by "c", followed by "d that has an f in front of it"
    

    未找到。

    前导/和尾部/的目的是什么?

    它们是定界符,在PHP中用于区分字符串模式部分和修改器部分。定界符可以是任何字符,尽管我个人更喜欢使用@符号。请记住,如果您在模式中使用了定界符,则需要对其进行转义。


    但是,“a”后面跟着“b”,再跟着“c”,再跟着“d”,前面有一个“e”(不是“e”也不是“f”),这个不匹配。你能否详细说明一下? - user1032531
    @user1032531 好的,请给我一分钟。Marten,对不起,我想我不小心覆盖了你的建议编辑,但是那个信息现在已经在问题中了。 - Asad Saeeduddin
    啊哈,分隔符!所以只有在我有修饰符的情况下才需要它们,对吗? - user1032531
    2
    预查是“零宽度”断言,意味着它们不包含在匹配中。因此,abcd(?=e) 表示仅当 abcd后面跟着一个 e时才匹配。 - garyh
    关于分隔符,preg_replace('[^a-zA-Z0-9_]', '','Hello[$&goodby')没有任何分隔符(除非方括号充当它们?)。这是无效的吗? - user1032531

    6

    谢谢Maarteen00,我会去看看。 - user1032531

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接