我正在尝试使用R的stringr package从tweet中提取twitter句柄。例如,假设我要获取向量中所有以“ A”开头的单词。我可以这样做
library(stringr)
# Get all words that begin with "A"
str_extract_all(c("hAi", "hi Ahello Ame"), "(?<=\\b)A[^\\s]+")
[[1]]
character(0)
[[2]]
[1] "Ahello" "Ame"
太好了。现在,让我们尝试使用“ @”代替“ A”
str_extract_all(c("h@i", "hi @hello @me"), "(?<=\\b)\\@[^\\s]+")
[[1]]
[1] "@i"
[[2]]
character(0)
为什么这个示例给出的结果与我预期的相反,我该如何解决?
答案 0 :(得分:4)
您可能是说
str_extract_all(c("h@i", "hi @hello @me", "@twitter"), "(?<=^|\\s)@[^\\s]+")
# [[1]]
# character(0)
# [[2]]
# [1] "@hello" "@me"
# [[3]]
# [1] "@twitter"
正则表达式中的\b
是一个边界,它出现在“字符串中的两个字符之间,其中一个是单词字符,另一个不是单词字符”。 see here。由于空格和“ @”都是非单词字符,因此“ @”之前没有边界。
使用此修订版,您可以匹配字符串的开头或空格后的值。
答案 1 :(得分:2)
关于正则表达式的几件事:
(?<=\b)
与\b
相同,因为单词边界已经是零宽度断言\@
与@
相同,因为@
不是特殊的正则表达式元字符,您不必逃避它[^\s]+
与\S+
相同,几乎所有速记字符类在正则表达式中都具有相反的符号。因此,您的正则表达式\b@\S+
与@i
中的h@i
匹配,因为h
(一个字母,一个字符char)和{{1 }}(非单词char,不是字母,数字或下划线)。选中this regex debugger。
@
是一个含糊不清的模式,其含义取决于正则表达式上下文。在您的情况下,您可能想使用\b
(非单词边界,即\B
),它将与\B@\S+
匹配,后者前面带有非单词char或在字符串的开头。
@
请参见regex demo。
如果您想摆脱这种x <- c("h@i", "hi @hello @me")
regmatches(x, gregexpr("\\B@\\S+", x))
## => [[1]]
## character(0)
##
## [[2]]
## [1] "@hello" "@me"
/ \b
的歧义,请使用带有字符串方法的环视或带有\B
参数的基本R regex函数来使用明确的单词边界:
perl=TRUE
其中:
regmatches(x, gregexpr("(?<!\\w)@\\S+", x, perl=TRUE))
regmatches(x, gregexpr("(?<!\\S)@\\S+", x, perl=TRUE))
-一个明确的起始单词边界-是一个否定的后向含义,可确保在当前位置或字符串开头的左侧紧接有一个非单词char (?<!\w)
-空格开头的单词边界-是一个否定的向后查找,可确保在当前位置或字符串开头的左侧紧跟有一个空格字符。请参见this regex demo和another regex demo here。
请注意,相应的右侧边界为(?<!\S)
和(?!\w)
。
答案 2 :(得分:0)
上面的答案就足够了。万一您只想获取用户名,这将删除@符号。
str_extract_all(c("@tweeter tweet", "h@is", "tweet @tweeter2"), "(?<=\\B\\@)[^\\s]+")
[[1]]
[1] "tweeter"
[[2]]
character(0)
[[3]]
[1] "tweeter2"
虽然我不是regex的专家,但问题似乎可能是@符号与单词字符不对应,因此匹配单词开头的空字符串(\\b
)确实可以不起作用,因为当@放在单词之前时没有空字符串。
如果您没有看到它们,这里有两个很棒的正则表达式资源:
Stringr's Regex page,也可以作为插图使用:
vignette("regular-expressions", package = "stringr")