用异常替换重复的字母

Replace duplicate letters with exception

我正在尝试用一个字母替换任何重复的字母。
我在这里使用 gsub 并且它正在工作:

text <- c("This tree is veeeeery tall")
gsub("([a-zA-Z])\1+", "\1", text)
##[1] "This tre is very tal"

但是 我需要为某些单词例外:

"This tree is very tall"

我尝试了这个问题的解决方案,但它不起作用。

text <- c("This tree is veeeeery tall")
words2keep <- c("tree", "tall")
gsub(perl=T,paste0('(?!\b',paste(collapse='\b|\b',words2keep),'\b)\b([a-zA-Z])\1+\b'),'\1',text)
##[1] "This tree is veeeeery tall"

那么,有什么办法吗?

这是 stringrstr_replace_all 的解决方案:

text1 <- c("This tree is veeeeery tall")
text2 <- c("This tree is vaeeeeery tall")
text3 <- c("This tree is eeeeery tall")
words2keep <- c("tree", "tall")

library(stringr)
replace_func = function(string){
  str_replace_all(string, "(\w)\1+", "\1")
}

names(words2keep) = replace_func(words2keep)


text_clean1 = replace_func(text1)
str_replace_all(text_clean1, words2keep)
# [1] "This tree is very tall"

text_clean2 = replace_func(text2)
str_replace_all(text_clean2, words2keep)
# [1] "This tree is vaery tall"

text_clean3 = replace_func(text3)
str_replace_all(text_clean3, words2keep)
# [1] "This tree is ery tall"

此解决方案首先通过 text 将要通过的相同 str_replace_all 运行 words2keep,并使结果成为 words2keep 的名称:

> words2keep
   tre    tal 
"tree" "tall"

然后将相同的 str_replace_all 应用于 text 以删除所有重复的单词字符:

> replace_func(text1)
[1] "This tre is very tal" 

最后,技巧是使用第三个 str_replace_all 通过提供 named words2keep 向量将错误修改的词替换为原始词。

使用 PCRE perl=TRUE 选项,很容易向正则表达式引入异常。您所需要的只是一个交替运算符,它将分隔两个主要部分:第一个,左边的部分是我们匹配和跳过的部分,第二个是我们要实际处理的部分。

\b(?:tree|tall)\b(*SKIP)(*F)|([a-zA-Z])+

regex demo

详情

  • \b(?:tree|tall)\b(*SKIP)(*F) - 前导单词边界、整个单词 treetall、尾随单词边界以及 2 个 PCRE 动词的组合 (*SKIP)(*F)让正则表达式引擎跳过匹配并从当前位置继续寻找下一个(跳过的匹配结束)
  • | - 或
  • ([a-zA-Z])+ - 捕获到第 1 组的任何 ASCII 字母,然后同一字母的一个或多个重复(请注意 \p{L}(*UCP) 动词使模式完全支持 Unicode )

要在 R 中动态构建正则表达式,您需要 paste 将异常词向量放入正则表达式的左侧:

text <- c("This tree is veeeeery tall")
words2keep <- c("tree", "tall")
p <- paste0('\b(?:',paste(collapse='|',words2keep),')\b(*SKIP)(*F)|([A-Za-z])\1+')
## OR: p <- paste0('(*UCP)\b(?:',paste(collapse='|',words2keep),')\b(*SKIP)(*F)|(\p{L})\1+')
p
## => [1] "\b(?:tree|tall)\b(*SKIP)(*F)|([A-Za-z])\1+"
gsub(p, '\1',text, perl=TRUE)
## => [1] "This tree is very tall"

R demo online