Regex 为什么这个正则表达式匹配第二项而不是第一项

Regex 为什么这个正则表达式匹配第二项而不是第一项,regex,perl,Regex,Perl,假设我有以下正则表达式: /BAR|FOO BAR/gi "/BAR|FOO BAR/gi" 和以下输入字符串:“FOO BAR” 我本想在“酒吧”里找到一对,但实际上我在“美食酒吧”里找到了一对。为什么会这样?正则表达式从开头开始。它会看到F,并尝试将其与条选项匹配。这当然是失败的。然后,它尝试FOO-BAR选项,该选项似乎有效,因此它使用该选项运行,以确定它是否有效。果然是这样,所以匹配是foobarRegex将首先查找匹配的模式 首先,让我们检查正则表达式: /BAR|FOO BAR/

假设我有以下正则表达式:

/BAR|FOO BAR/gi
"/BAR|FOO BAR/gi"
和以下输入字符串:“FOO BAR”


我本想在“酒吧”里找到一对,但实际上我在“美食酒吧”里找到了一对。为什么会这样?

正则表达式从开头开始。它会看到
F
,并尝试将其与
选项匹配。这当然是失败的。然后,它尝试
FOO-BAR
选项,该选项似乎有效,因此它使用该选项运行,以确定它是否有效。果然是这样,所以匹配是
foobar

Regex将首先查找匹配的模式 首先,让我们检查正则表达式:

/BAR|FOO BAR/gi
"/BAR|FOO BAR/gi"
它搜索的是匹配字符串中的
BAR
FOO BAR
。标志(假设符合正则表达式)为“全局”和“不区分大小写”:

  • Global标志表示表达式将尝试返回
  • 不区分大小写标志表示表达式将匹配,而不考虑大小写
  • 让我们尝试一些方法来了解匹配是如何工作的(注意:我使用的是
    perl
    ,因为它是最流行的正则表达式实现,但是如果符合您的语言,这些示例应该适用于您的语言):

    这将为所有3条语句()打印
    true
    ,表明
    FOO
    BAR
    FOO
    都是带有忽略大小写标志的有效匹配项

    那么,为什么您的正则表达式匹配的是“
    FOO BAR
    ”而不是“
    BAR
    ”?

    因为,如文档所述,解析器将

    请注意,设置
    /g
    不会导致两者匹配,因为它将尝试尽可能多次地匹配整个规则
    /FOO BAR | BAR/
    ,而不是匹配规则的每一侧。一旦“
    FOO BAR
    ”匹配,它将停止尝试匹配字符串的该部分并继续

    如果您想同时匹配
    FOO-BAR
    BAR
    ,您会怎么做?

    将匹配“
    FOO BAR
    ”和“
    BAR
    ”,给定您的输入字符串:

    my $string = "FOO BAR";
    
    $string =~ /(FOO (BAR))/;
    print "$1\n"; # Prints 'FOO BAR'
    print $2;     # Prints 'BAR'
    
    在上下文中演示
    /g
    标志

    使用
    /g
    标志,将匹配
    FOO
    BAR

    my $string = "FOO BAR";
    
    while($string =~ /(FOO|BAR)/g) {
        print "$1\n";
    }
    
    要匹配您正在寻找的内容。。。 将匹配任何输入字符串的
    FOO
    ,后跟空格、
    BAR
    FOO BAR

    my $string = "FOO BAR";
    
    while($string =~ /((FOO\s)?(BAR))/g) {
        print "$1\n$2\n$3";
    }
    

    注意:我已从示例中删除了不相关的标志,以避免将来读者因类似问题而感到困惑。

    @SweetieBelle Erm。。。您的示例将尝试匹配F,fail,继续到O,fail,next O,fail,space,fail,B,aha!找到了比赛的开始。A和R也匹配,这就是整个模式,成功@SweetieBelle:正则表达式引擎在字符串的第一个位置检查每个模式,然后是第二个位置,以此类推。阅读正则表达式与常规自动机的关系。@tripleee阅读下面的答案。关于正则表达式是如何工作的,我知道很多,但这个答案的措辞并不清楚。像许多快速被接受的答案一样,它并没有解释真正发生了什么,只是简单地介绍了一下。请检查我的答案,了解演示代码的详细解释,以及如何匹配
    FOO BAR
    BAR
    。此外,将来,请指定您作为正则表达式使用的语言,不同语言的正则表达式有所不同。@SweetieBelle我注意到Ruby和Javascript中的行为,所以我认为这在整个正则表达式中是常见的,但感谢您的提示和详细回答。Ruby和Javascript都使用符合perl的正则表达式,因此,是的,它将与大多数其他正则表达式实现相同,但语言之间存在细微差别。
    /(FOO(BAR))/
    无法单独匹配
    BAR
    。它只会在
    FOO-BAR
    的上下文中匹配它。呃,不,它不会。它将匹配
    FOO
    ,一个任意数量的空格(包括零),然后匹配
    BAR
    。整个匹配将被捕获到第0组和第1组,
    FOO
    将被捕获到第2组,
    BAR
    将被捕获到第3组。我必须说,你反复使用括号来“捕捉”整个比赛让我感到困惑,因为你“非常了解正则表达式的工作原理”。我在想你是想得到你的名字…@Kolink如果你想在所有情况下都只需要一个空格,你可以匹配
    \s
    ,而不是
    \s*
    ,但是如果没有前面的空格,那就不匹配
    条。您可以匹配空格,或将空格与
    FOO
    匹配,或使用分层替换。此外,如果没有括号,您将无法在
    while
    循环中捕获整个匹配项:。由于OP想要捕捉
    FOO BAR
    ,我允许这样做。好的,Perl与我习惯的有一些不同。关键是,如果搜索字符串只是
    /BAR | FOO BAR/
    会匹配它,但您自己的正则表达式都不会匹配。