【问题标题】:Can you make just part of a regex case-insensitive?您可以只使正则表达式的一部分不区分大小写吗?
【发布时间】:2010-09-07 19:15:31
【问题描述】:

我见过很多让整个正则表达式不区分大小写的例子。我想知道的是只有部分表达式不区分大小写。

例如,假设我有一个这样的字符串:

fooFOOfOoFoOBARBARbarbarbAr

如果我想匹配所有出现的“foo”而不考虑大小写但我只想匹配大写的“BAR”怎么办?

理想的解决方案是适用于正则表达式风格的解决方案,但我也有兴趣听到特定语言的解决方案(感谢 Espo)

编辑

Espo 提供的链接非常有帮助。那里有一个很好的例子,关于在表达式中打开和关闭修饰符。

对于我人为的例子,我可以这样做:

(?i)foo*(?-i)|BAR

这使得匹配只对匹配的 foo 部分不区分大小写。

这似乎在大多数正则表达式实现中都有效,除了 Javascript、Python 和其他一些(正如 Espo 提到的)。

我想知道的大的(Perl、PHP、.NET)都支持内联模式更改。

【问题讨论】:

标签: regex


【解决方案1】:

Perl 允许您使用 (?i:) 模式修饰符使正则表达式的一部分不区分大小写。

现代正则表达式风格允许您仅将修饰符应用于正则表达式的一部分。如果在正则表达式中间插入修饰符 (?ism),则修饰符仅适用于正则表达式中修饰符右侧的部分。您可以通过在它们前面加上减号来关闭模式。减号后的所有模式都将关闭。例如。 (?i-sm) 开启不区分大小写,同时关闭单行模式和多行模式。

并非所有的正则表达式都支持这一点。 JavaScript 和 Python 将所有模式修饰符应用于整个正则表达式。它们不支持 (?-ismx) 语法,因为当模式修饰符应用于整个正则表达式时,关闭选项是没有意义的。所有选项默认关闭。

您可以快速测试您使用的正则表达式如何处理模式修饰符。正则表达式 (?i)te(?-i)st 应匹配 test 和 TEst,但不匹配 teST 或 TEST。

Source

【讨论】:

    【解决方案2】:

    确实可以依赖Turning Modes On and Off for Only Part of The Regular Expression 中所述的内联修饰符:

    正则表达式 (?i)te(?-i)st 应该匹配 test 和 TEst,但不匹配 teST 或 TEST。

    不过,一个更受支持的功能是 (?i:...) 内联修饰符组(请参阅 Modifier Spans)。语法是(?i:,然后是您想要不区分大小写的模式,然后是)。

    (?i:foo)|BAR
    

    反之:如果您的模式编译时使用了不区分大小写的选项,并且您需要使正则表达式的一部分区分大小写,则在? 之后添加-:(?-i:...)。

    各种语言的使用示例(用尖括号括起来):

    • - preg_replace("~(?i:foo)|BAR~", '<$0>', "fooFOOfOoFoOBARBARbarbarbAr") (demo)
    • - re.sub(r'(?i:foo)|BAR', r'<\g<0>>', 'fooFOOfOoFoOBARBARbarbarbAr') (demo)(注意 Python re supports Python 3.6 以来的内联修饰符组)
    • / / - Regex.Replace("fooFOOfOoFoOBARBARbarbarbAr", "(?i:foo)|BAR", "<$&>") (demo)
    • - "fooFOOfOoFoOBARBARbarbarbAr".replaceAll("(?i:foo)|BAR", "<$0>") (demo)
    • - $s =~ s/(?i:foo)|BAR/<$&>/g (demo)
    • - "fooFOOfOoFoOBARBARbarbarbAr".gsub(/(?i:foo)|BAR/, '<\0>') (demo)
    • - gsub("((?i:foo)|BAR)", "<\\1>", "fooFOOfOoFoOBARBARbarbarbAr", perl=TRUE) (demo)
    • - "fooFOOfOoFoOBARBARbarbarbAr".replacingOccurrences(of: "(?i:foo)|BAR", with: "<$0>", options: [.regularExpression])
    • - (使用 RE2) - regexp.MustCompile(`(?i:foo)|BAR`).ReplaceAllString( "fooFOOfOoFoOBARBARbarbarbAr", `<${0}>`) (demo)

    、、、std::regex、、 不支持。

    在这种情况下,您可以将两个字母变体放入一个字符类(而不是一个组,请参阅Why is a character class faster than alternation?)。例子:

    【讨论】:

    • bash 支持,如果使用“Perl-like”正则表达式。试试:echo BAR | grep -P '(?i)bar'
    • @NoamManos 那不是纯Bash,就是grep,而且它已经和PCRE相关了,PCRE是Perl兼容的正则表达式库,所以已经在perl中覆盖了。如您所见,我没有在此处列出grep,因为grep -P 选项并未得到普遍支持(仅受GNU grep 支持)
    【解决方案3】:

    您使用什么语言?执行此操作的标准方法是 /([Ff][Oo]{2}|BAR)/ 启用区分大小写,但在 Java 中,例如,有一个区分大小写的修饰符 (?i) 使所有它右边的字符不区分大小写和 (?-i) 强制敏感。可以在 here 找到该 Java 正则表达式修饰符的示例。

    【讨论】:

    • +1 当你可以同时匹配两种情况时,为什么还要让它不区分大小写
    • @NonaUrbiz:因为表达式(?i)foobar比[Ff][Oo]{2}[Bb][Aa][Rr]更具可读性
    • 而且因为它可以以的方式变得更加多毛和复杂。
    【解决方案4】:

    不幸的是,不区分大小写的匹配语法并不常见。 在 .NET 中,您可以使用 RegexOptions.IgnoreCase 标志或 ?i 修饰符

    【讨论】:

      【解决方案5】:

      你可以使用

      (?:F|f)(?:O|o)(?:O|o)
      

      .Net 括号中的 ?: 表示它是非捕获的,仅用于对 | 的术语进行分组。 (或)声明。

      【讨论】:

      • “[fF][oO][oO]”不是更好的选择吗?对于手头的例子,你甚至可以走到 "[fF][oO]\{2}" ;-)
      猜你喜欢
      • 1970-01-01
      • 2011-04-22
      • 1970-01-01
      • 2013-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多