【问题标题】:Learning Regular Expressions [closed]学习正则表达式
【发布时间】:2010-09-05 12:09:21
【问题描述】:

我不太懂正则表达式。您能以易于理解的方式向我解释吗?如果有任何在线工具或书籍,您可以链接到它们吗?

【问题讨论】:

    标签: regex


    【解决方案1】:

    最重要的部分是概念。一旦您了解了构建块的工作原理,语法上的差异只不过是温和的方言而已。正则表达式引擎语法之上的一层是您正在使用的编程语言的语法。 Perl 等语言消除了大部分复杂性,但如果您在 C 程序中使用正则表达式,则必须牢记其他注意事项。

    如果您将正则表达式视为可以随意混合和匹配的构建块,它可以帮助您学习如何编写和调试自己的模式,以及如何理解其他人编写的模式。

    从简单开始

    从概念上讲,最简单的正则表达式是文字字符。模式N 匹配字符“N”。

    彼此相邻的正则表达式匹配序列。例如,模式Nick 匹配序列“N”后跟“i”后跟“c”后跟“k”。

    如果您曾经在 Unix 上使用过grep——即使只是为了搜索普通字符串——那么您已经在使用正则表达式了! (grep 中的re 指的是正则表达式。)

    从菜单中订购

    增加一点复杂性,您可以将 'Nick' 或 'nick' 与模式 [Nn]ick 匹配。方括号中的部分是一个字符类,这意味着它与包含的字符之一完全匹配。您还可以在字符类中使用范围,因此 [a-c] 匹配“a”或“b”或“c”。

    . 模式很特殊:它不仅匹配文字点,还匹配任何字符。在概念上与真正的大字符类[-.?+%$A-Za-z0-9...] 相同。

    将字符类视为菜单:只选择一个。

    有用的快捷方式

    使用. 可以为您节省大量输入,并且还有其他常用模式的快捷方式。假设你想匹配一个数字:一种写法是[0-9]。数字是经常匹配的目标,因此您可以改用快捷方式\d。其他是\s(空格)和\w(单词字符:字母数字或下划线)。

    大写的变体是它们的补码,所以\S 匹配任何-空白字符,例如。

    一次是不够的

    从那里,您可以使用 量词 重复部分模式。例如,ab?c 模式匹配 'abc' 或 'ac' 因为? 量词使得它修改的子模式是可选的。其他量词是

    • *(零次或多次)
    • +(一次或多次)
    • {n}(正好 n 次)
    • {n,}(至少 n 次)
    • {n,m}(至少 n 次但不超过 m 次)

    将其中一些块放在一起,模式[Nn]*ick 匹配所有的

    • ick
    • 尼克
    • 尼克
    • 尼克
    • 尼克
    • 尼克
    • (等等)

    第一个匹配展示了一个重要的教训:* 总是成功!任何模式都可以匹配零次。

    其他一些有用的例子:

    • [0-9]+(及其等效的\d+)匹配任何非负整数
    • \d{4}-\d{2}-\d{2} 匹配格式为 2019-01-01 的日期

    分组

    量词将模式修改为紧挨着它的左边。您可能希望0abc+0 匹配“0abc0”、“0abcabc0”等,但加号量词左侧的模式立即c。这意味着0abc+0 匹配“0abc0”、“0abcc0”、“0abccc0”等。

    要匹配一个或多个末端带有零的“abc”序列,请使用0(abc)+0。括号表示可以量化为一个单元的子模式。正则表达式引擎保存或“捕获”与括号组匹配的输入文本部分也很常见。以这种方式提取位比计数索引和substr 更加灵活且不易出错。

    交替

    之前,我们看到了一种匹配“Nick”或“nick”的方法。另一个是与Nick|nick 中的交替。请记住,交替包括左侧的所有内容和右侧的所有内容。使用分组括号限制|的范围,例如(Nick|nick)

    再举一个例子,您可以将[a-c] 等效地写为a|b|c,但这可能不是最理想的,因为许多实现都假设替代方案的长度大于1。

    转义

    虽然有些字符匹配自己,但有些字符有特殊含义。模式 \d+ 不匹配反斜杠后跟小写 D 后跟加号:要得到它,我们将使用 \\d\+。反斜杠删除后面字符的特殊含义。

    贪婪

    正则表达式量词是贪婪的。这意味着它们匹配尽可能多的文本,同时允许整个模式成功匹配。

    例如说输入是

    “你好,”她说,“你好吗?”

    您可能认为".+" 只匹配“Hello”,然后当您看到它从“Hello”一直匹配到“you?”时会感到惊讶。

    要从贪婪切换到您可能认为的谨慎,请在量词中添加一个额外的?。现在您了解了\((.+?)\),您问题中的示例是如何工作的。它匹配文字左括号的序列,后跟一个或多个字符,并以右括号结束。

    如果您的输入是“(123) (456)”,那么第一次捕获将是“123”。非贪婪量词希望让模式的其余部分尽快开始匹配。

    (至于您的困惑,我不知道任何正则表达式方言 ((.+?)) 会做同样的事情。我怀疑在传输过程中某处丢失了某些东西。)

    锚点

    使用特殊模式^ 仅匹配输入的开头,使用$ 仅匹配末尾。用你的模式制作“书挡”,你说“我知道前面和后面是什么,但把中间的一切都给我”是一种有用的技巧。

    假设你要匹配表单的 cmets

    -- This is a comment --

    你会写^--\s+(.+)\s+--$

    构建你自己的

    正则表达式是递归的,所以现在您了解了这些基本规则,您可以随意组合它们。

    编写和调试正则表达式的工具:

    书籍

    免费资源

    脚注

    †: 上面关于. 匹配任何字符的陈述是出于教学目的的简化,并非严格正确。点匹配除换行符"\n" 之外的任何字符,但实际上您很少期望.+ 之类的模式跨越换行符边界。 Perl 正则表达式有/s switch 和Java Pattern.DOTALL,例如,使. 匹配任何字符。对于没有此类功能的语言,您可以使用 [\s\S] 之类的内容来匹配“任何空格或任何非空格”,即任何内容。

    【讨论】:

    • 您也可以使用试错法,比在线正则表达式测试器和调试器有很大帮助:regex101.com
    • 值得一提的是,尽管a{,m} 是一个类似的模式,但至少在 Javascript、Perl 和 Python 中不是一个东西。
    • 值得一提的是,有不同种类的正则表达式引擎,它们都有不同的特征集和语法规则。
    • hackr.io/tutorials/learn-regular-expressions-regex 是查找最佳在线正则表达式教程的好地方。这里的所有教程都是由编程社区提交和推荐的(像 SO 一样赞成)。
    • 这有助于快速参考:Quick-Start: Regex Cheat Sheet
    猜你喜欢
    • 1970-01-01
    • 2022-11-28
    • 2013-02-17
    • 2018-07-05
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多