提取正则表达式匹配

133
我想从字符串中提取一个数字。我想对字符串 "aaa12xxx" 执行类似于 [0-9]+ 的操作,以获取 "12"。我认为代码应该是这样的:
> grep("[0-9]+", "aaa12xxx", value=TRUE)
[1] "aaa12xxx"

然后我想到了...

> sub("[0-9]+", "\\1", "aaa12xxx")
[1] "aaaxxx"

但我做了一些事情,得到了某种形式的回应:

> sub("[0-9]+", "ARGH!", "aaa12xxx")
[1] "aaaARGH!xxx"

我忽略了一个小细节。

13个回答

187

使用新的stringr包,它将所有现有的正则表达式操作封装在一个一致的语法中,并添加了一些缺失的内容:

library(stringr)
str_locate("aaa12xxx", "[0-9]+")
#      start end
# [1,]     4   5
str_extract("aaa12xxx", "[0-9]+")
# [1] "12"

5
几乎就是我需要的,但当我开始输入?str_extract时,我看到了str_extract_all,生活又变得美好了。 - dwanderson

124

说“忽略标准函数”可能有点仓促——?gsub的帮助文件甚至在“另请参见”中特别提到:

基于'regexpr'、'gregexpr'和'regexec'的结果提取匹配子字符串的'regmatches'。

因此,以下方法可行且相当简单:

txt <- "aaa12xxx"
regmatches(txt,regexpr("[0-9]+",txt))
#[1] "12"

2
你如何提取多个组?例如,从字符串“aaa12bbb15ccc”中分别提取12和15? - Duccio A
4
@DuccioA - regmatches(x, gregexpr("[0-9]+", x)) - 就像sub用于一次替换,gsub用于所有替换一样,regexpr找到一个结果,而gregexpr找到所有结果。 - thelatemail

29

对于你的特定情况,你可以删除所有非数字字符:

gsub("[^0-9]", "", "aaa12xxxx")
# [1] "12"

在更复杂的情况下它不会起作用。

gsub("[^0-9]", "", "aaa12xxxx34")
# [1] "1234"

不是从字符串中提取目标的最佳选项。这对于仅返回字符串中任何数字的好处在于,可以通过删除所有不是数字的字符来使它们可能或不可能在一起,并且如果您认为它提取了(例如,gsub("[^ 0-9]","","aaa12xx1xx")返回121而不是可能预期的c(12,1)),则可能会出现错误。 - daneshjai
1
@daneshjai 这正是 OP 想要的。这不是一般化的解决方案。 - Marek
不一定。问题的标题是“提取正则表达式匹配项”。它适用于这个例子,但可能会给人错误的印象,在某些情况下产生相反的结果。因此,我认为对于那些最终落在这里并且可能对正则表达式不熟悉的人来说,澄清这一点是删除所有字符而不是提取目标模式是有帮助的。 - daneshjai
@daneshjai 大多数答案会返回 "aaa12xx1xx" 的 12,这并不是你所期望的。 - Marek

17

您可以使用Perl正则表达式的懒惰匹配:

> sub(".*?([0-9]+).*", "\\1", "aaa12xx99",perl=TRUE)
[1] "12"
尝试替换非数字字符将导致错误,但在这种情况下不会。

5
如果您愿意使用略微丑陋的“[^0-9]*([0-9]+).*”,则不需要使用PERL。 - Jyotirmoy Bhattacharya

6

在正则表达式中使用捕获括号和组引用替换。括号内的任何内容都会被记住。然后通过\2访问第一个项目。第一个反斜杠转义了R中反斜杠的解释,以便将其传递给正则表达式解析器。

gsub('([[:alpha:]]+)([0-9]+)([[:alpha:]]+)', '\\2', "aaa12xxx")

5
一种方法是这样的:
test <- regexpr("[0-9]+","aaa12456xxx")

现在,请注意regexpr给出了字符串的起始和结束索引:

    > test
[1] 4
attr(,"match.length")
[1] 5

因此,您可以使用substr函数与该信息一起使用。
substr("aaa12456xxx",test,test+attr(test,"match.length")-1)

我相信有更优雅的方法完成这个任务,但是这是我能找到的最快捷的方式。或者,你可以使用sub/gsub函数来去除不需要的内容以保留你想要的内容。


4

这些方法之间一个重要的区别是在没有匹配项的情况下的行为。例如,如果所有位置都没有匹配项,regmatches方法可能不会返回与输入相同长度的字符串。

> txt <- c("aaa12xxx","xyz")

> regmatches(txt,regexpr("[0-9]+",txt)) # could cause problems

[1] "12"

> gsub("[^0-9]", "", txt)

[1] "12" ""  

> str_extract(txt, "[0-9]+")

[1] "12" NA  

3

这个问题的解决方案

library(stringr)
str_extract_all("aaa12xxx", regex("[[:digit:]]{1,}"))
# [[1]]
# [1] "12"

[[:digit:]]: 数字 [0-9]

{1,}: 至少匹配1次


2

另一种解决方案:

temp = regexpr('\\d', "aaa12xxx");
substr("aaa12xxx", temp[1], temp[1]+attr(temp,"match.length")[1])

2

在 gsubfn 包中使用 strapply。strapply 类似于 apply,它的参数是对象、修改器和函数,除了对象是字符串向量(而不是数组)以外,修饰符是正则表达式(而不是边缘):

library(gsubfn)
x <- c("xy13", "ab 12 cd 34 xy")
strapply(x, "\\d+", as.numeric)
# list(13, c(12, 34))

这里的意思是在 x 的每个组件中匹配一个或多个数字 (\d+),并将每个匹配项转换为数字形式 .numeric。它返回一个列表,其组件是各自组件的匹配向量。从输出结果来看,我们可以看到 x 的第一个组件有一个匹配项,即 13,而 x 的第二个组件有两个匹配项,分别是 12 和 34。更多信息请参见 http://gsubfn.googlecode.com


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