采用以下字符向量x
x <- c("1 Date in the form", "2 Number of game",
"3 Day of week", "4-5 Visiting team and league")
我想要的结果是以下向量,每个字符串包含第一个大写单词,如果字符串包含-
,也是最后一个单词。
[1] "Date" "Number" "Day" "Visiting" "league"
所以不要做
unlist(sapply(strsplit(x, "[[:blank:]]+|, "), function(y){
if(grepl("[-]", y[1])) c(y[2], tail(y,1)) else y[2]
}))
得到结果,我想我可以尝试将它缩短为正则表达式。结果几乎是sub
中这个正则表达式的“相反”。我已经尝试过各种方式来获得相反的结果,其中包括[^A-Za-z]+
等不同种类,并且没有成功。
> sub("[A-Z][a-z]+", "", x)
[1] "1 in the form" "2 of game"
[3] "3 of week" "4-5 team and league"
所以我想这是一个两部分问题。
sub()
或gsub()
,如何返回"[A-Z][a-z]+"
的反面?
如何编写正则表达式,如“匹配第一个大写单词,如果字符串包含-
,也匹配最后一个单词。”?
答案 0 :(得分:3)
以下是一些建议:
要使用sub
提取第一个大写单词,您可以使用
sub(".*\\b([A-Z].*?)\\b.*", "\\1", x)
#[1] "Date" "Number" "Day" "Visiting"
其中\\b
表示单词边界。
您也可以使用一个sub
命令提取所有单词,但请注意,您必须应用额外的步骤,因为sub
返回的向量的长度与输入向量x
。
以下正则表达式使用前瞻((?=.*-)
)来测试字符串中是否有-
。如果是这种情况,则提取两个单词。如果它不存在,则应用逻辑或(|
)之后的正则表达式,并仅返回第一个大写单词。
res <- sub("(?:(?=.*-).*\\b([A-Z].*?\\b ).*\\b(.+)$)|(?:.*\\b([A-Z].*?)\\b.*)",
"\\1\\2\\3", x, perl = TRUE)
# [1] "Date" "Number" "Day" "Visiting league"
为了在同一个字符串中分隔多个单词,还需要一个额外的步骤:
unlist(strsplit(res, " ", fixed = TRUE))
# [1] "Date" "Number" "Day" "Visiting" "league"
答案 1 :(得分:2)
这是一个使用三个正则表达式的解决方案。
cap_words <- regmatches(x, regexpr("[A-Z][a-z]+", x)) # capitalised word
last_words <- sub(".*\\s", "", x[grep("-", x)]) # get last word in strings with a dash
c(cap_words, last_words)
# [1] "Date" "Number" "Day" "Visiting" "league"