【问题标题】:how do the regular expressions * and ? metacharacter work?正则表达式 * 和 ?元字符工作?
【发布时间】:2012-01-07 06:46:02
【问题描述】:

您好,我正在使用正则表达式,但我对元字符感到困惑,尤其是 '*' 和 '?'。

'*' 应该匹配前面的字符 0 次或更多次。

例如,'ta*k' 应该匹配 'tak' 和 'tk'。

但我根本不会认为这是真的 - 这是我的推理:

为了:

正则表达式:我需要一个 't'

字符串:我没有't'

regexp:好的,你的下一个字符必须是'a'

字符串:是的

regexp:好的,继续给我字符,直到你的字符不是'a'

字符串:好的。我刚刚给了你'k'

regexp:好的,你的下一个字符必须是'k'

字符串:我没有更多字符了!

正则表达式:失败

对于传统知识:

正则表达式:我需要一个 't'

字符串:我没有't'

regexp:好的,你的下一个字符必须是'a'

字符串:不,它是一个 'k'

正则表达式:失败

谁能帮我解释一下为什么 'tak' 和 'tk' 匹配 'ta*k'?

【问题讨论】:

  • 为什么会这样?结果与元字符的预期语义相匹配。你描述的行动方案没有。
  • 也重新标记:在这个问题中没有关于 Action-Script 的内容。
  • 嘿,谢谢你们的帮助,你们所有的答案都很有道理。我想要带回家的一点是,当正则表达式解析自己时,它需要从任何文字中向前看,看看是否有任何元字符,然后一起测试。我想我的下一个问题是“如果有很多像 '.* 这样的元字符怎么办?”,但我会读一下 FakeRainBrigand 离开的那个网站,看看我自己能不能弄清楚:)跨度>

标签: regex


【解决方案1】:

* 并不意味着匹配一个字符零次或多次,而是匹配一个原子零次或多次。单个字符是一个原子,但任何分组也是。

* 表示零个或多个。当正则表达式光标“吞下”t 时,位置为:

in the regex: t|a*k
in the string: t|ak

然后,正则表达式引擎会尝试并尽可能多地吃掉as。这里有一个。吞下之后的位置是:

in the regex: ta*|k
in the string: ta|k

然后k被吞了:

in the regex: ta*k|
in the string: tak|

正则表达式结束,匹配。请注意,字符串后面可能有其他字符,正则表达式引擎并不关心:它有一个匹配项。

如果字符串是tka* 之前的位置是:

in the regex: t|a*k
in the string: t|k

但是*可以匹配一个空集as,因此a*是满足的!这意味着位置变成:

in the regex: ta*|k
in the string: t|k

冲洗,重复。现在,让我们将taak 作为输入,将ta?k 作为正则表达式:这将失败,但让我们看看如何......

# before first character
regex: |ta?k
input: |taak
# t
regex: t|a?k
input: t|aak
# a?
regex: ta?|k
input: ta|ak
# k? Oops! No...
regex: |ta?k
input: t|aak
# t? Oops! No...
regex: |ta?k
input: ta|ak
# t? Oops! No...
regex: |ta?k
input: taa|k
# t? Oops! No...
regex: |ta?k
input: taak|
# t? Oops! No... And nothing to read anymore
# FAIL

这就是为什么让正则表达式快速失败非常重要的原因。

【讨论】:

  • "字符串后面可能有其他字符,正则表达式引擎不在乎:它有一个匹配项。" -- 不对。正则表达式通常是贪婪的。这意味着它们将匹配尽可能多的字符(有一些例外,但这不是一个)。如果您的意思是“lorem tak ipsum”仍然匹配,那取决于实现,并且变体通常存在于相同的语言/工具中。
  • “如果你的意思是“lorem tak ipsum”仍然匹配,这取决于实现“tak 。
  • 是的,因为 Python 在命名方面犯了与 Java 完全相同的错误……正则表达式不必匹配其整个输入。绝不。你必须使用.search
【解决方案2】:

因为 a* 表示“a 的零个或多个实例”。

当“it”要求所有不是“a”的字符时,一旦它有一个,它(大致)将它推回输入流中。 (或者它向前窥视,或者它只是保持它等等)

第一个序列:这是你的第一个非"a",我会坚持下去。接下来你需要一个"k",这就是我所拥有的。

第二个序列:下一个字符不需要必须是"a"——它可能是一个或多个"a"。在这种情况下,它没有。我会坚持那个非"a"。您需要"k"?我收到你的"k" 还在这儿。

【讨论】:

    【解决方案3】:

    你领先一位:

    regexp:好的,继续给我字符,直到你的字符不是 '一个'

    字符串:下一个字符不是'a'

    regexp:好的,你的下一个字符需要是 'k'

    字符串:下一个字符是'k'

    所以它起作用了。请注意,'a*' 表示“'a' 的 0 次或多次出现”,而不是“'a' 的 1 次或多次出现”。对于后者,有“+”号,就像在“a+”中一样。

    【讨论】:

      【解决方案4】:

      ta*k 表示,一个't',后跟0个或多个'a',然后是一个'k'。所以 0 'a' 字符,会使 'tk' 成为可能的匹配项。

      如果您想要“1 或更多”而不是“0 或更多”,请使用 + 而不是 *。也就是说,ta+k 将匹配 'tak' 而不是 'tk'。

      如果有什么我没有解释的,请告诉我。


      顺便说一下,R​​egEx 并不总是从左到右。引擎经常回溯、窥视并研究输入。这真的很复杂,这就是它如此强大的原因。如果您查看诸如 this one 之类的网站,它们有时会解释引擎在做什么。我推荐他们的教程,因为那是我了解 RegEx 的地方!

      【讨论】:

        【解决方案5】:

        要记住的基本事项是,正则表达式是输入一组字符串的便捷简写。 a{1,5} 只是字符串集(a、aa、aaa、aaaa、aaaaa)的简写。 a* 是 ([empty], a, aa, aaa, ...) 的简写。

        因此,实际上,当您将正则表达式提供给搜索算法时,您就是在告诉它要搜索的字符串列表。

        因此,当您将 ta*k 提供给您的搜索算法时,您实际上是在为它提供一组字符串(tk、tak、taak、taaak、taaaak...)。

        所以,是的,了解搜索算法的工作原理很有用,这样您就可以提供最有效的正则表达式,但不要让尾巴摇摆不定。

        【讨论】:

          猜你喜欢
          • 2017-03-12
          • 1970-01-01
          • 2020-07-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-04-17
          • 2015-07-19
          • 2021-12-14
          相关资源
          最近更新 更多