我有以下字符串向量,我需要匹配第二个重复的单词,而不是第一个,没有空间。
names_vec <- c("Linda Smith","Elizabeth Olsen Green Elizabeth Olsen Green",
"Eva Ferguson","Charlize Martinez White Charlize Martinez White",
"digital copy solutions digitals",
"honor security services honor")
结果向量应该是:答:我的错误有误会。当在"荣誉安全服务"中匹配第二副本时,"荣誉";最后一个Word是必须匹配和删除的。
matched_vec <- c("Elizabeth Olsen Green","Charlize Martinez White","honor security services")
我尝试了不同的方法,但都没有成功。下面的代码匹配第一个出现的单词,但我需要最后一个,因为我想删除最后一个重复的单词,而不是第一个。
下面的代码获取括号内的内容,我想要其他重复的单词。
str_view_all(names_vec , "(\b\S+\s*\b)(?=.*\b\1\b)", match = TRUE)
[Elizabeth Olsen Green] Elizabeth Olsen Green
[Charlize Martinez White] Charlize Martinez White
[honor] security services honor
我使用的正则表达式匹配每个字符串的第一个重复的单词,从字符串的开始有重复。
我的期望是匹配字符串的第二个重复的单词,所以它必须从右向左搜索并匹配所有第二个重复的单词。
人们会问我,为什么要麻烦。问题是我有一些公司名称,如果你从左到右数的话,通常我想要删除的重复单词是第二个或最后一个。
这是另一种可以考虑的方法
library(stringr)
str_view_all_Mod <- function(string, pattern, match = NA)
{
if(identical(match, TRUE)) {
string <- string[str_detect(string, pattern)]
}
else if (identical(match, FALSE)) {
string <- string[!str_detect(string, pattern)]
}
loc <- str_locate_all(string, pattern)
string_list <- Map(loc = loc, string = string, function(loc,
string) {
if (nrow(loc) == 0)
return(string)
for (i in rev(seq_len(nrow(loc)))) {
str_sub(string, loc[i, , drop = FALSE]) <- paste0(" /// ",
str_sub(string, loc[i, , drop = FALSE]), " /// ")
}
string
})
string <- unlist(string_list)
string <- str_remove_all(string, pattern = "/// ///")
return(string)
}
reverse_String <- function(text)
{
splits <- strsplit(text, "")[[1]]
reversed <- rev(splits)
final_result <- paste(reversed, collapse = "")
return(final_result)
}
names_vec <- c("Linda Smith","Elizabeth Olsen Green Elizabeth Olsen Green Allo bonjour Elizabeth Olsen Green",
"Eva Ferguson","Charlize Martinez White Charlize Martinez White",
"digital copy solutions digitals",
"honor security services honor")
nb_Text <- length(names_vec)
names_vec_rev <- rep(NA, nb_Text)
for(i in 1 : nb_Text)
{
names_vec_rev[i] <- reverse_String(names_vec[i])
}
text <- str_view_all_Mod(names_vec_rev, "(\b\S+\s*\b)(?=.*\b\1\b)", match = TRUE)
text <- stringr::str_extract(text, "///[^/]*///")
text <- stringr::str_remove_all(text, "///")
text <- lapply(X = text, FUN = reverse_String)
unlist(text)
[1] " Elizabeth Olsen Green " " Charlize Martinez White " " honor "
以下似乎是一个紧凑的stringr
解决方案:
str_remove(names_vec, "(.*).*(?=\b\1\b)")
[1] "" "Elizabeth Olsen Green" "" "Charlize Martinez White" "" "honor"
在这里,我们删除了所有重复的内容以及后面的内容,从而只保留了实际的repeat或duplicate本身。为了识别欺骗,我们使用正向正向的(?=...)
和反向引用的\1
包裹在字\b
边界中。
如果你不想要空字符串,通过子集删除它们:
matched_vec <- str_remove(names_vec, "(.*).*(?=\b\1\b)")
matched_vec[matched_vec != ""]
[1] "Elizabeth Olsen Green" "Charlize Martinez White" "honor"
或者考虑tidyverse
解决方案:
data.frame(names_vec) %>%
extract(names_vec, into = c("1st","2nd"), "(.*).*(\b\1\b)", remove = FALSE) %>%
select(-"1st")
names_vec 2nd
1 Linda Smith
2 Elizabeth Olsen Green Elizabeth Olsen Green Elizabeth Olsen Green
3 Eva Ferguson
4 Charlize Martinez White Charlize Martinez White Charlize Martinez White
5 digital copy solutions digitals
6 honor security services honor honor
这里我们使用tidyr
的extract
函数将字符串划分为两个捕获组,一个用于1st
部分,一个用于2nd
部分,这是1st
的重复;重复的由反向引用\1
您可以使用stringi::stri_reverse
来反转字符。然后我在gsub
中使用您的正则表达式并删除第一次重复,实际上是最后一次重复,并再次反转结果。
stringi::stri_reverse(
gsub("(\b\S+\s*\b)(?=.*\b\1\b)", "",
stringi::stri_reverse(names_vec), perl=TRUE) )
#[1] "Linda Smith" "Elizabeth Olsen Green "
#[3] "Eva Ferguson" "Charlize Martinez White "
#[5] "digital copy solutions digitals" "honor security services "
或者只使用sub
:
sub("(\b\S.*\b)(.*)\b\1\b", "\1\2", names_vec)
#[1] "Linda Smith" "Elizabeth Olsen Green "
#[3] "Eva Ferguson" "Charlize Martinez White "
#[5] "digital copy solutions digitals" "honor security services "