26

我想建立一个正则表达式替换一些字符串来搜索,所以这些字符串需要在我可以将它们放入正则表达式之前进行转义,这样如果搜索的字符串包含正则表达式字符,它仍然可以工作。

某些语言具有可以为您执行此操作的功能(例如 python re.escapehttps ://stackoverflow.com/a/10013356/1900520 )。R有这样的功能吗?

例如(组成函数):

x = "foo[bar]"
y = escape(x) # y should now be "foo\\[bar\\]"
4

5 回答 5

24

我编写了 Perlquotemeta函数的 R 版本:

library(stringr)
quotemeta <- function(string) {
  str_replace_all(string, "(\\W)", "\\\\\\1")
}

我总是使用 perl 风格的正则表达式,所以这对我有用。我不知道它是否适用于 R 中的“正常”正则表达式。

编辑:我找到了解释为什么这样做的来源。它在perlre 手册页的引用元字符部分:

这曾经在一个常见的习惯用法中用于禁用或引用要用于模式的字符串中正则表达式元字符的特殊含义。简单地引用所有非“单词”字符:

$pattern =~ s/(\W)/\\$1/g;

正如你所看到的,上面的 R 代码是这个替换的直接翻译(在经历了反斜杠地狱之后)。手册页还说(强调我的):

与其他一些正则表达式语言不同,没有不是字母数字的反斜杠符号。

这强化了我的观点,即该解决方案仅适用于 PCRE。

于 2013-02-12T17:57:57.417 回答
14

显然escapeRegex在 Hmisc 包中调用了一个函数。函数本身对“字符串”的输入值具有以下定义:

gsub("([.|()\\^{}+$*?]|\\[|\\])", "\\\\\\1", string)

我之前的回答:

我不确定是否有内置功能,但您可以制作一个来做您想做的事。这基本上只是创建了一个包含要替换的值的向量和一个包含要替换它们的向量,然后循环遍历那些进行必要替换的值。

re.escape <- function(strings){
    vals <- c("\\\\", "\\[", "\\]", "\\(", "\\)", 
              "\\{", "\\}", "\\^", "\\$","\\*", 
              "\\+", "\\?", "\\.", "\\|")
    replace.vals <- paste0("\\\\", vals)
    for(i in seq_along(vals)){
        strings <- gsub(vals[i], replace.vals[i], strings)
    }
    strings
}

一些输出

> test.strings <- c("What the $^&(){}.*|?", "foo[bar]")
> re.escape(test.strings)
[1] "What the \\$\\^&\\(\\)\\{\\}\\.\\*\\|\\?"
[2] "foo\\[bar\\]"  
于 2013-02-12T17:31:44.917 回答
4

比@ryanthompson 函数更简单的方法是简单地为字符串添加前缀\\Q和后缀\\E。请参阅帮助文件?base::regex

于 2019-04-23T11:48:08.940 回答
1

使用rex

这些天来,我使用rex. 对于您的具体示例,rex完全符合您的要求:

library(rex)
library(assertthat)
x = "foo[bar]"
y = rex(x)
assert_that(y == "foo\\[bar\\]")

但当然,rex做的远不止这些。这个问题提到了构建一个正则表达式,这正是rex设计的目的。例如,假设我们想要匹配 中的确切字符串x,之前或之后没有任何内容:

x = "foo[bar]"
y = rex(start, x, end)

现在 y 是^foo\[bar\]$并且只会匹配 x 中包含的确切字符串。

于 2021-05-06T05:24:27.100 回答
0

根据?regex

该符号\w匹配“单词”字符( 的同义词[[:alnum:]_],扩展名)并且\W是它的否定([^[:alnum:]_])。

因此,使用捕获组,(\\W)我们可以检测到非单词字符的出现并使用\\1-syntax 对其进行转义:

> gsub("(\\W)", "\\\\\\1", "[](){}.|^+$*?\\These are words")
[1] "\\[\\]\\(\\)\\{\\}\\.\\|\\^\\+\\$\\*\\?\\\\These\\ are\\ words"

或者类似地,替换"([^[:alnum:]_])"for "(\\W)"

于 2022-02-10T13:32:34.263 回答