你可以使正则表达式的一部分忽略大小写吗?

121

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

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

fooFOOfOoFoOBARBARbarbarbAr

如果我想匹配所有不区分大小写的"foo"出现,但只想匹配大写的"BAR"怎么办?
理想的解决方案应该是适用于所有正则表达式,但我也很想听听特定语言的解决方案(感谢Espo)。
编辑
Espo提供的链接非常有帮助。里面有一个很好的例子,可以在表达式中启用和禁用修饰符。
对于我的人为例子,我可以这样做:
(?i)foo*(?-i)|BAR

这使得匹配过程中,仅针对foo部分不区分大小写。

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

我想知道的那些主流实现(Perl、PHP、.NET)都支持内联模式更改。


此问题已添加到Stack Overflow正则表达式FAQ,位于“修饰符”下。 - aliteralmind
5个回答

98

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

现代正则表达式支持在正则表达式中的某个部分应用修饰符。如果在正则表达式的中间插入修饰符(?ism),修饰符仅适用于修饰符右侧的正则表达式部分。您可以通过在修饰符前加减号来关闭模式。减号后面的所有模式都将被关闭。例如,(?i-sm)打开不区分大小写模式,并关闭单行模式和多行模式。

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

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

来源


25

仅对正则表达式的一部分开启和关闭模式中描述的那样,确实可以依赖于内联修饰符:

正则表达式 (?i)te(?-i)st 可以匹配 test 和 TEst,但不能匹配 teSTTEST

然而,更受支持的功能是 (?i:...) 内联修饰符组(请参见 修改器区间)。其语法是 (?i:,然后是您想要使大小写不敏感的模式,最后是一个 )

(?i:foo)|BAR
反向操作: 如果你的模式使用不区分大小写选项进行编译,并且你需要使正则表达式的一部分区分大小写,你需要在 ? 后面添加 -(?-i:...)
各种语言中的示例用法(使用尖括号包装匹配项):
  • - preg_replace("~(?i:foo)|BAR~", '<$0>', "fooFOOfOoFoOBARBARbarbarbAr") (演示)
  • - re.sub(r'(?i:foo)|BAR', r'<\g<0>>', 'fooFOOfOoFoOBARBARbarbarbAr') (演示) (注意 Python re 支持 内联修饰符组,自 Python 3.6 起)
  • / / - Regex.Replace("fooFOOfOoFoOBARBARbarbarbAr", "(?i:foo)|BAR", "<$&>") (演示)
  • - "fooFOOfOoFoOBARBARbarbarbAr".replaceAll("(?i:foo)|BAR", "<$0>") (演示)
  • - $s =~ s/(?i:foo)|BAR/<$&>/g (演示)
  • - "fooFOOfOoFoOBARBARbarbarbAr".gsub(/(?i:foo)|BAR/, '<\0>') (演示)
  • - gsub("((?i:foo)|BAR)", "<\\1>", "fooFOOfOoFoOBARBARbarbarbAr", perl=TRUE) (演示)
  • - "fooFOOfOoFoOBARBARbarbarbAr".replacingOccurrences(of: "(?i:foo)|BAR", with: "<$0>", options: [.regularExpression])
  • - (使用 RE2) - regexp.MustCompile(`(?i:foo)|BAR`).ReplaceAllString( "fooFOOfOoFoOBARBARbarbarbAr", `<${0}>`) (演示)

不支持 , , , std::regex, , .

在这些情况下,您可以将两个字母变体放入字符类中(不是组,请参见为什么字符类比交替更快?)。示例:

  • - sed -E 's/[Ff][Oo][Oo]|BAR/<&>/g' file > outfile (演示)
  • - grep -Eo '[Ff][Oo][Oo]|BAR' file (或者如果你使用GNU grep,你仍然可以使用PCRE正则表达式,grep -Po '(?i:foo)|BAR' file (演示))

1
如果使用“类Perl”正则表达式,则在bash中支持它。尝试:echo BAR | grep -P '(?i)bar' - Noam Manos
1
@NoamManos 这不是纯Bash,这是grep,它已经涉及到PCRE,即Perl兼容的正则表达式库,因此它已经包含在perl中。正如您所看到的,我没有在这里列出grep,因为grep-P选项并非普遍支持(仅由GNU grep支持)。 - Wiktor Stribiżew

6
你在使用哪种编程语言?一种标准的方法是使用类似于 /([Ff][Oo]{2}|BAR)/ 的正则表达式,并打开大小写敏感选项。但在Java中,有一个大小写敏感修饰符 (?i),它使其右侧的所有字符不区分大小写,还有一个强制大小写敏感的修饰符 (?-i)。可以在 这里 找到Java正则表达式修饰符的示例。

+1 为什么要让它不区分大小写,当你可以匹配两种情况呢? - Nona Urbiz
16
@NonaUrbiz表示,表达式(?i)foobar[Ff][Oo]{2}[Bb][Aa][Rr]更易读。 - Thanatos
3
因为它可以变得非常复杂和棘手。 - Chop

6

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


4
您可以使用

标签


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

在 .Net 中方括号中的 ?: 表示非捕获组,仅用于分组 |(或)语句的项。

28
“[fF][oO][oO]”不是更好的选择吗?对于手头的例子,你甚至可以使用“[fF][oO]{2}”;-) - Tomalak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接