【问题标题】:Is there an R function to escape a string for regex characters是否有 R 函数来转义正则表达式字符的字符串
【发布时间】:2013-02-12 16:10:30
【问题描述】:

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

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

例如(组成函数):

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

【问题讨论】:

  • 你能添加一个示例字符串以及你希望输出的样子吗?
  • 大多数正则表达式函数都有一个名为 'fixed' 的参数,如果设置为 TRUE 将导致模式按原样匹配。
  • 这不好 - 我想根据用户提供的输入构建一个正则表达式 - 所以我需要“清理”输入但仍然使用正则表达式。
  • 我确定我刚才看到了一个很好的答案,但它已经消失了......
  • 与Dason的回答有关,另见stringr::fixed()

标签: regex string r


【解决方案1】:

我已经编写了 Perl 的 quotemeta 函数的 R 版本:

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

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

编辑:我找到了解释为什么这样做的来源。在Quoting Metacharacters section of the perlre manpage:

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

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

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

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

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

【讨论】:

  • Ryan,我可能不太了解您的函数的正确用法,但是当我尝试使用正则表达式删除空格时它失败了:quotemeta('\s+')。我该如何管理它?
【解决方案2】:

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

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\\]"  

【讨论】:

  • 这不是一个好的解决方案。您必须在 vals 中包含每个特殊的正则表达式字符,这可能会很困难。
  • @RyanThompson 当然 - 但这是一个开始。而且特殊字符的列表是有限的,所以它不是一个非常大的负担。我并不是说这是一个最佳解决方案——只是它是一种可能性。另请注意,您的方法可能会转义通常不被视为正则表达式字符的字符,因此也可能被视为“坏”。
  • 我的方法可能会转义一些不需要转义的字符,但这样做不会造成伤害,因为对于 PCRE,any 非字母数字字符被视为以反斜杠为前缀时的文字,即使不需要反斜杠。
  • 此方法的另一个致命缺陷是它连续应用其转义而不是一次全部应用,因此在一次传递中所做的更改可能会在下一次传递中出现乱码。
  • 你说得对,我认为它按预期工作。我没有仔细看,注意到反斜杠是列表中的第一个替换,并且由于反斜杠也是 gsub() 添加的唯一字符,因此您永远不会插入一个字符然后对插入进行操作。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    使用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 中包含的确切字符串。

    【讨论】:

      【解决方案5】:

      根据?regex

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

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

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

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

      【讨论】:

        猜你喜欢
        • 2013-01-28
        • 2010-09-21
        相关资源
        最近更新 更多