理解量词

我正在通过量词的Java教程。

在贪心,不情愿和拥有量词的差异中有所不同。

我无法理解到底有什么区别。

说明如下:

Enter your regex: .*foo  // greedy quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfooxxxxxxfoo" starting at index 0 and ending at index 13.

Enter your regex: .*?foo  // reluctant quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfoo" starting at index 0 and ending at index 4.
I found the text "xxxxxxfoo" starting at index 4 and ending at index 13.

Enter your regex: .*+foo // possessive quantifier
Enter input string to search: xfooxxxxxxfoo
No match found.

第一个例子使用贪婪的量词。*找到“任何东西”,零次或多次,后面跟着字母“f”“o”“o”。 由于量词是贪婪的,表达式的。*部分首先会吃掉整个输入字符串。 此时,整体表达不能成功,因为最后三个字母(“f”“o”“o”)已被使用。 所以匹配器一次只能退回一个字母,直到“foo”的最右侧出现反刍,此时匹配成功并且搜索结束。

然而,第二个例子是不愿意的,所以它首先消耗“没有”。 因为“foo”没有出现在字符串的开头,所以它不得不吞下第一个字母(一个“x”),它会在0和4处触发第一个匹配。我们的测试工具会继续这个过程,直到输入字符串为止累。 它在4日和13日发现另一场比赛。

第三个例子没有找到匹配,因为量词是占有的。 在这种情况下,整个输入字符串被。* +消耗掉,在表达式结尾处没有任何结果满足“foo”。 使用占有量词来处理你想要抓住所有东西而又不退缩的情况; 在没有立即找到匹配的情况下,它将胜过等价的贪婪量词。


一般规则

量词的基本知识?*+ (分别为“零个或一个”,“零个或多个”,“一个或多个”)。

  • 我们说量子是贪婪的,如果它试图尽可能多地描述字符。
  • 如果量词尽可能少地描述字符,我们会说量词不情愿懒惰 )。
  • 我们说如果量词是贪婪的并且不允许回溯,则量词是占有的
  • 只有知道正则表达式解析器的工作原理时,才能理解“回溯”的含义(请参见下面的“动态示例”)。

    单例解释

  • ? :首先测试1次出现,然后是0; 如果你发现了一次,然后你需要丢弃它,你可以做到
  • ?? :首先测试0个事件,然后是1
  • ?+ :首先测试1次,然后是0; 如果您发现了一次,然后您需要丢弃它, 则无法执行此操作
  • * :尝试尽可能多地发生(甚至0); 如果您发现了N个事件,然后您需要丢弃(某些)事件,则可以从最后一次开始
  • *? :尽量减少事件发生(甚至0)
  • *+ :尝试获得尽可能多的事件(即使是0); 如果你发现了N个事件,然后你需要丢弃(一些)它们,你不能这样做
  • + :尝试获得尽可能多的事件(至少1次); 如果您发现了N个事件,然后您需要丢弃(某些)事件,则可以从最后一次开始
  • +? :尽可能减少事件发生(至少1次)
  • ++ :尝试获得尽可能多的事件(至少1次); 如果你发现了N个事件,然后你需要丢弃(一些)它们,你不能这样做
  • 动态的例子

    在本节中,我将尝试向您展示正则表达式解析器背后的逻辑:

    1)案例/.*foo/

    首先是子模式/.*/的转向。 它开始阐述第一个字符:

    xfooxxxxxxfoo
    ^
    

    然后它会尝试尽可能多地阐述字符:

    xfooxxxxxxfoo
    ^^
    xfooxxxxxxfoo
    ^^^
    [...]
    xfooxxxxxxfoo
    ^^^^^^^^^^^
    xfooxxxxxxfoo
    ^^^^^^^^^^^^
    xfooxxxxxxfoo
    ^^^^^^^^^^^^^
    

    游标到达最后,但子模式/foo/尚未发挥其作用。 所以游标“返回”允许子模式/foo/获得匹配:

    xfooxxxxxxfoo
    ^^^^^^^^^^^^
    

    /foo/仍然无法匹配,所以我们需要再次返回:

    xfooxxxxxxfoo
    ^^^^^^^^^^^
    xfooxxxxxxfoo
    ^^^^^^^^^^
    

    现在子模式/foo/可以匹配:

    xfooxxxxxxfoo
    ^^^^^^^^^^^^^
    

    所以匹配是整个字符串xfooxxxxxxfoo

    2)案例/.*?foo/

    首先是子模式/.*?/ 。 这是懒惰的,所以我们希望它可以匹配0个字符。 但是如果是这样,子模式/foo/不能匹配,所以它必须详细说明一个字符:

    xfooxxxxxxfoo
    ^
    

    现在是foo的依次为:

    xfooxxxxxxfoo
    ^^^^
    

    所以这场比赛是xfoo

    (如果为正则表达式设置了global类型,那么解析器会在匹配后的第一个字符处重新开始,给出第二个匹配xxxxxxfoo

    3)案例/.*+foo/

    首先是子模式/.*+/的转向。 它试图尽可能多地阐述角色:

    xfooxxxxxxfoo
    ^
    [...]
    xfooxxxxxxfoo
    ^^^^^^^^^^^^^
    

    游标到达最后,但子模式/foo/尚未发挥其作用。 所以光标“回去”......哦,不,可惜,它不能(因为它是占有欲)!

    所以我们没有匹配。


    懒惰(不情愿)和贪婪的情况之间的主要区别在于回溯结构的行为和占有欲的行为过于激进

  • 延迟的情况将总是在一次匹配后,将匹配引擎的焦点放到正则表达式中的下一个运算符。 如果下一个操作员失败,回溯结构将强制延迟情况被重复,并且这会一直持续到操作员或目标文本结束; 例如在你的例子中,在每次成功匹配后传递给char f匹配,所以每当你有一个foo短语时,你会得到一个匹配,这就是为什么我们从它的用法中得到多个匹配。
  • 。*?FOO

    x fooxxxxxxfoo
    在开始时,懒的情况下会与x匹配(匹配成功后),并将焦点传递给下一个运算符; foo是正则表达式的一部分,并且因为它出现在x之后,所以我们得到这个片段的匹配,这个字符串的次要部分是相同的。

  • 贪婪的情况是相反的,将继续它的匹配直到它失败,永远不会将焦点传递给下一个运算符,只有当匹配失败后回溯才会生效,并且下一个运算符将从反向匹配;
  • * FOO

    xfooxxxxxxfo o
    当贪婪的情况下(最后一个字符)匹配将失败,因为我们无法匹配正则表达式的foo部分。 比回溯会迫使贪婪的案件backtrace其步骤并执行下一个运算符foo ,类似于懒惰的情况;

    xfooxxxxxx f oo
    此时, foo部分将获得成功的匹配,从而以整个字符串的成功匹配结束。

  • 所有制案例与贪婪案例非常相似,除了最后一部分引起backtracking的匹配失败之外,所有格并非如此。 如果它可以匹配,它将拥有并将牺牲过程中匹配的成功。 如果它在匹配一个字符时失败了,那么只有焦点会传递给正则表达式的下一个运算符。
  • * + FOO

    xfooxxxxxxfo o
    类似贪婪的情况下,我们已经到达了字符串的末尾,但所有格仍然可以匹配它,因此不会将火炬传递给backtrack结构,并且会导致匹配失败。

    链接地址: http://www.djcxy.com/p/13433.html

    上一篇: Understanding Quantifiers

    下一篇: Reluctant quantifier acting greedy