如何处理像 \^$ 这样的特殊字符?*|+()[{ 在我的正则表达式中?

How do I deal with special characters like \^$.?*|+()[{ in my regex?

提问人:Richie Cotton 提问时间:12/31/2014 最后编辑:k-dubsRichie Cotton 更新时间:6/15/2023 访问量:179741

问:

我想匹配正则表达式特殊字符 .我试过了:\^$.?*|+()[{

x <- "a[b"
grepl("[", x)
## Error: invalid regular expression '[', reason 'Missing ']''

(等效或。stringr::str_detect(x, "[")stringi::stri_detect_regex(x, "[")

将值加倍以转义它不起作用:

grepl("[[", x)
## Error: invalid regular expression '[[', reason 'Missing ']''

使用反斜杠也是如此:

grepl("\[", x)
## Error: '\[' is an unrecognized escape in character string starting ""\["

如何匹配特殊字符?


在一些特殊情况下,这些问题已经足够古老且写得很好,以至于可以厚颜无耻地将其作为副本关闭:
R 正则表达式
中的转义句点 如何在 R 中转义问号?
正则表达式中的转义管道 (“|”)

正则表达式 R-常见问题

评论


答:

141赞 9 revs, 4 users 93%Richie Cotton #1

使用双反斜杠进行转义

R 将反斜杠视为字符常量的转义值。(...正则表达式也是如此。因此,在为模式提供字符参数时需要两个反斜杠。第一个实际上不是一个角色,而是它使第二个变成了一个角色。您可以看到如何使用 cat 处理它们。

y <- "double quote: \", tab: \t, newline: \n, unicode point: \u20AC"
print(y)
## [1] "double quote: \", tab: \t, newline: \n, unicode point: €"
cat(y)
## double quote: ", tab:    , newline: 
## , unicode point: €

延伸阅读:在 R 中用反斜杠转义反斜杠会在字符串中产生 2 个反斜杠,而不是 1

要在正则表达式中使用特殊字符,最简单的方法通常是使用反斜杠对它们进行转义,但如上所述,反斜杠本身需要转义。

grepl("\\[", "a[b")
## [1] TRUE

要匹配反斜杠,您需要双重转义,从而产生四个反斜杠。

grepl("\\\\", c("a\\b", "a\nb"))
## [1]  TRUE FALSE

该软件包包含每个特殊字符的常量,以避免键入错误的斜杠。rebus

library(rebus)
OPEN_BRACKET
## [1] "\\["
BACKSLASH
## [1] "\\\\"

有关更多示例,请参阅:

?SpecialCharacters

您的问题可以通过以下方式解决:

library(rebus)
grepl(OPEN_BRACKET, "a[b")

形成字符类

还可以将特殊字符括在方括号中,以形成字符类

grepl("[?]", "a?b")
## [1] TRUE

其中两个特殊字符在字符类中具有特殊含义:和 。\^

反斜杠仍然需要转义,即使它位于字符类中。

grepl("[\\\\]", c("a\\b", "a\nb"))
## [1]  TRUE FALSE

插入符号只有在左方括号的正后方括号之后时才需要转义。

grepl("[ ^]", "a^b")  # matches spaces as well.
## [1] TRUE
grepl("[\\^]", "a^b") 
## [1] TRUE

rebus还允许您形成字符类。

char_class("?")
## <regex> [?]

使用预先存在的字符类

如果要匹配所有标点符号,可以使用字符类。[:punct:]

grepl("[[:punct:]]", c("//", "[", "(", "{", "?", "^", "$"))
## [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE

stringi将其映射到 Unicode General Category 的标点符号,因此其行为略有不同。

stri_detect_regex(c("//", "[", "(", "{", "?", "^", "$"), "[[:punct:]]")
## [1]  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE

您还可以使用跨平台语法来访问 UGC。

stri_detect_regex(c("//", "[", "(", "{", "?", "^", "$"), "\\p{P}")
## [1]  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE

使用 \Q \E 转义符

将字符放在 和 之间会使正则表达式引擎从字面上而不是将其视为正则表达式。\\Q\\E

grepl("\\Q.\\E", "a.b")
## [1] TRUE

rebus允许您编写正则表达式的文本块。

literal(".")
## <regex> \Q.\E

不要使用正则表达式

正则表达式并不总是答案。如果你想匹配一个固定的字符串,那么你可以这样做,例如:

grepl("[", "a[b", fixed = TRUE)
stringr::str_detect("a[b", fixed("["))
stringi::stri_detect_fixed("a[b", "[")

评论

3赞 Sam Firke 11/7/2015
用于查看使用反斜杠转义的效果很有启发性。cat
2赞 dnlbrky 12/5/2016
谢谢你的提示。从未注意到它被埋在.\\Q\\E?base::regex
0赞 Pablo Casas 8/2/2018
像魅力一样工作stringr::str_detect("a[b", fixed("["))
0赞 petergensler 10/21/2016 #2

我认为匹配角色的最简单方法,例如

\^$.?*|+()[

使用 R 中的字符类。 请考虑以下操作来清除数据文件中的列标题,其中可能包含空格和标点符号:

> library(stringr)
> colnames(order_table) <- str_replace_all(colnames(order_table),"[:punct:]|[:space:]","")

这种方法允许我们字符串字符类以匹配标点字符,以及空格字符,通常必须进行转义才能检测到。您可以在下面的备忘单中了解有关字符类的更多信息,也可以输入以查看有关此内容的更多信息。\\?regexp

https://www.rstudio.com/wp-content/uploads/2016/09/RegExCheatsheet.pdf

-1赞 Wiktor Stribiżew 6/15/2023 #3

如果向量的值包含特殊的正则表达式元字符,并且需要从向量创建替代,则需要使用

regex.escape <- function(string) {
    gsub("([][{}()+*^${|\\\\?.])", "\\\\\\1", string)
}
x <- c("a[b", "c++", "d()e")
regex <- paste(regex.escape(x), collapse="|")
## => a\[b|c\+\+|d\(\)e

请注意 - 如果你使用像 ///等这样的提取基本 R 正则表达式方法 - TRE 正则表达式风格,作为一个 POSIX 正则表达式引擎,总是返回最长的匹配项(即检查所有备选项并返回最长的匹配项)。regmatchesgregexprregexec

如果您使用带有 perl=TRUE 的基本 R 正则表达式函数或 stringr/stringi ICU 正则表达式函数,则应阅读下面的摘要。

请注意,如果您构建的正则表达式没有侧面,您很可能还希望首先按长度降序对值进行排序,因为正则表达式引擎从左到右搜索匹配项,而用户定义的列表往往包含可能在字符串内相同位置匹配的项目(=向量中的值可能以相同的字符开头), 并且可能会丢失更长的匹配项,请参阅记住正则表达式引擎是渴望的):

sort.by.length.desc <- function (v) v[order( -nchar(v)) ]

所以,如果你有,你可以只使用x <- c("a[b", "c++", "d()e", "d()ee")

x <- c("a[b", "c++", "d()e", "d()ee")
regex <- paste(regex.escape(sort.by.length.desc(x)), collapse="|")
# => d\(\)ee|d\(\)e|a\[b|c\+\+

请注意前面的 。d\(\)ee\d\(\)e

在较长正则表达式的中间/开始/结尾使用一组备选方案

您需要使用任何类型的组对备选方案进行分组,如果不需要访问组值,则不捕获组,如果需要访问值,则需要捕获组。使用明确单词边界的示例:

x <- c("a[b", "c++", "d()e", "d()ee")
text <- "aaaa[b,abc++,d()e,d()ee"
regex <- paste0("(?!\\B\\w)(?:", paste(regex.escape(sort.by.length.desc(x)), collapse="|"), ")(?<!\\w\\B)")
## -> (?!\B\w)(?:d\(\)ee|d\(\)e|a\[b|c\+\+)(?<!\w\B) 
unlist(regmatches(text,gregexpr(regex, text, perl=TRUE)))
## => [1] "d()e"  "d()ee"

您可以注意到,该模式现在看起来像 + 您的交替 + ,其中交替被放入一个非捕获组 () 中,如果下一个字符是单词字符,则需要单词边界,如果紧挨着左侧的字符是单词字符,则该部分需要单词边界。(?!\B\w)(?:)(?<!\w\B)(?:d\(\)ee|d\(\)e|a\[b|c\+\+)(?!\B\w)(?<!\w\B)