R中的正则表达式:从字符串中提取单词

7
我猜这是一个常见的问题,我找到了很多网页,包括一些来自SO的网页,但我无法理解如何实现它。
我对正则表达式不熟悉,并且我想在R中使用它从句子中提取前几个单词。
例如,如果我的句子是:
z = "I love stack overflow it is such a cool site"

我想将我的输出设置为(如果我需要前四个单词)
[1] "I love stack overflow"

或者(如果我需要最后四个单词)
[1] "such a cool site"

当然,以下的作品。
paste(strsplit(z," ")[[1]][1:4],collapse=" ")
paste(strsplit(z," ")[[1]][7:10],collapse=" ")

但是我想尝试正则表达式的解决方案来解决性能问题,因为我需要处理非常大的文件(也为了了解它)。
我查看了几个链接,包括从字符串中提取前三个单词的正则表达式http://osherove.com/blog/2005/1/7/using-regex-to-return-the-first-n-words-in-a-string.html 所以我尝试了一些东西。
gsub("^((?:\S+\s+){2}\S+).*",z,perl=TRUE)
Error: '\S' is an unrecognized escape in character string starting ""^((?:\S"

我试过其他方法,但通常会返回整个字符串或空字符串。
substr 的另一个问题是它返回一个列表。也许在处理大文件并执行应用程序时,使用 [[]] 运算符会使事情变慢。
看起来 R 中使用的语法有些不同? 谢谢!

2
在 R 正则表达式中,您需要使用双重转义。\S -> \\S - Wiktor Stribiżew
您还可以尝试使用stringi::stri_extract_all_words(z)[[1]][1:4],这更容易使用,不需要了解正则表达式。但是您将获得单独的单词值。 - David Arenburg
你能不能使用我之前在这个问题中提到的相同的想法呢?(http://stackoverflow.com/questions/33785594/manipulate-char-vectors-inside-a-data-table-object-in-r)如@sribizhev所指出的那样,你只需要在R中加倍斜杠即可。 - A5C1D2H2I1M1N2O1R2T1
是的@Ananda Mahto,抱歉我学习比较慢,现在我明白我需要双反斜杠。 - Fagui Curtain
2个回答

8
你已经接受了一个答案,但我想分享一些关于R中正则表达式的知识,帮助你更好地理解,因为你已经非常接近正确答案了。
你的gsub方法有两个问题:
  1. 你使用了单个反斜杠(\)。在R中,你需要对它们进行转义,因为它们是特殊字符。你可以通过添加另一个反斜杠(\\)来转义它们。如果你执行nchar("\\"),你会发现它返回"1"。

  2. 你没有指定要替换为什么内容。在这里,我们不想替换任何内容,而是想捕获字符串的特定部分。你可以用圆括号(...)来捕获组,然后可以按组的编号引用它们。在这里,我们只有一个组,所以我们将其称为"\\1"

你应该尝试类似以下的代码:
sub("^((?:\\S+\\s+){2}\\S+).*", "\\1", z, perl = TRUE)
# [1] "I love stack"

这基本上是在说:

  • 从“z”的内容开始工作。
  • 开始创建第一组。
  • 查找非空白字符(例如单词)后跟两次空格符(\S+\s+),然后是下一组非空白字符(\S+)。这将使我们得到3个单词,同时不会获取第三个单词后的空格符。因此,如果您想要不同数量的单词,请将{2}更改为比实际所需数量少1。
  • 在那里结束第一组。
  • 然后,只需从“z”返回第一组的内容(\1)。

要获取最后三个单词,只需交换捕获组的位置,并将其放置在匹配模式的末尾。

sub("^.*\\s+((?:\\S+\\s+){2}\\S+)$", "\\1", z, perl = TRUE)
# [1] "a cool site"

谢谢。@Ananda Mahto。您能否使用相同的函数“sub”给出最后4个单词的正则表达式? - Fagui Curtain
1
@FaguiCurtain,我刚刚将引用从固定在行首改为了放在行尾,像这样:^.*((?:\\S+\\s+){2}\\S+)$。将“2”改为“3”,就可以得到4个单词而不是3个。 - A5C1D2H2I1M1N2O1R2T1

3
获取前四个单词。
library(stringr)
str_extract(x, "^\\s*(?:\\S+\\s+){3}\\S+")

获取最后四个。
str_extract(x, "(?:\\S+\\s+){3}\\S+(?=\\s*$)")

或者 sub("^\\s*((?:\\S+\\s+){3}\\S+).*", "\\1", x) - Avinash Raj
1
你能给我使用函数sub的正确正则表达式吗?我在10,000个样本上进行了测试,发现基于R语言的sub函数比来自library(stringr)str_extract函数快30倍。谢谢。 - Fagui Curtain
我很蠢但不知道如何调整这个函数。sub("(?:\\S+\\s+){3}\\S+(?=\\s*$)",replacement="",z,perl=TRUE) 返回的是 "我喜欢堆栈溢出",它返回了除了最后四个单词以外的所有东西... - Fagui Curtain
sub('^.* (\\w+\\s+\\w+\\s+\\w+\\s+\\w+)$', '\\1', z) 对于最后5个字符串有效,但我不明白如何使用 {...} 来使表达式更简单。 - Fagui Curtain
1
返回翻译文本: sub('^.* (\\w+(?:\\s+\\w+){4})$', '\\1', z) - Avinash Raj

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