R 中的 gsub 正则表达式 - 忽略换行符

gsub regex in R - ignore newline symbol

这是一个可重现的例子

S0 <- "\n3 4 5"
S1 <- "\n3   5"

我想使用 gsub 和以下正则表达式模式(在 R 之外工作 - 在 regex101 中测试)到 return 数字。此正则表达式应忽略 \n 它们是否同时出现。

([^\n])(\s{1})?

我不是在寻找一种方法来匹配具有根本不同模式的数字 - 我想知道如何让上述模式在 R 中工作。以下对我不起作用

gsub("([^\\n])(\s{1})?", "\1", S0)
gsub("([^[\\]n])(\s{1})?", "\1", S1)

输出应该是

#S0 - 345
#S1 - 3 5

几个问题。在你的 S 对象中不是反斜杠(它是一个转义运算符而不是一个字符)并且有一个预定义的数字字符 class 可以取反:

gsub("[^[:digit:]]", "", S)
[1] "345"

另一方面,如果您想排除换行符和空格,可以通过删除其中一个转义运算符来完成,因为除了字符 class 上下文:

gsub("[\n ]", "", S)
[1] "345"

由于您特别希望该正则表达式起作用,您可以匹配和可选 \n(使用 (\n)?):

gsub("(\n)?([^\n])(\s{1})", "\2", S0)
#[1] "345"
gsub("(\n)?([^\n])(\s{1})", "\2", S1)
#[1] "3 5"

请注意,您是对的,如果您使用像这样的正则表达式测试器:https://regex101.com/ 它可以在没有额外 "(\n)?" 的情况下工作。但是,我认为在 R 中你必须匹配更多才能使捕获组正常工作。

regex101 (PCRE) 中的 ([^\n])(\s{1})? 模式与 gsub 中使用的相同模式匹配不同的字符串,而没有 perl=TRUE(即,当它由 TRE regex 库处理时).如果您使用 perl=TRUE 并使用 gsub("([^\\n])(\s{1})?", "\1", S1, perl=TRUE).

,它们的工作原理相同

PCRE Regex ([^\n])(\s{1})有什么特别之处?

带有 PCRE 选项的正则表达式测试器中的这个模式匹配:

  • ([^\n]) - \n 以外的任何字符(放入第 1 组)
  • (\s{1})? - 将任何单个空白字符匹配并捕获到组 2 中,可选 1 次或 0 次。

请注意,此模式不匹配第一个捕获组的任何非换行符,如果它是 [^\n],它将匹配任何非换行符。

现在,与 gsub 相同的正则表达式将是

gsub("([^\n])(\s{1})?", "\1", S1)               # OR
gsub("([^\\n])(\s{1})?", "\1", S1, perl=TRUE)

为什么反斜杠的数量不同?因为第一个正则表达式是用 TRE 正则表达式库处理的,在这些模式中,在 括号表达式 中,没有正则表达式转义被这样解析,\n 被视为 2 个单独的字符。在 PCRE 模式中,perl=TRUE[...] 被称为 字符 类 并且在它们内部,您可以定义正则表达式转义,因此\ 正则表达式转义字符应该加倍(也就是说,在 R 字符串文字内部,它应该是四倍,因为你需要一个 \ 来将 R 引擎的 \ 转义为 "see" 一个反斜杠)。

实际上,如果你想匹配一个换行符,你只需要在正则表达式模式中使用\n,你可以使用"\n""\n"作为TRE和PCRE正则表达式引擎将 LF 和 \n 正则表达式转义解析为换行符匹配模式。这四个是等价的:

gsub("\n([^\n])(\s{1})?", "\1", S1)
gsub("\n([^\n])(\s{1})?", "\1", S1)
gsub("\n([^\\n])(\s{1})?", "\1", S1, perl=TRUE)
gsub("\n([^\\n])(\s{1})?", "\1", S1, perl=TRUE)

如果\n必须是可选的,只需要在它后面加上?量词,不需要用组包起来:

gsub("\n?([^\n])(\s{1})?", "\1", S1)
        ^

并进一步简化:

gsub("\n?([^\n])\s?", "\1", S1)

此外,如果通过 [^\n] 您想匹配除换行符以外的任何字符,只需使用 .(?n) 内联修饰符:

gsub("(?n)(.)(\s{1})?", "\1", S1)

参见 R demo online