在不同的子字符串出现 N 次后删除子字符串的所有实例

Remove all instances of sub-string after a different sub-string has occurred N times

我一直在尝试用 'Z' 替换字符“-”,但前提是字符串中有 2 个或更多 'Z'。

input = c("XX-XXZZXX-XZXXXXX", "XX-XXXZXXZXZXXX", "XXXXXZXXXZXXZX-X", 
"XXXZXXXZXZXZXXX", "XZXXX-XXXZXZXXX", "XX-XXX-ZZX", "XXZX-XXZXXX-XZ", 
"XZXZXX-XXZXXZXX")

desired_output = c("XX-XXZZXXZXZXXXXX", "XX-XXXZXXZXZXXX", "XXXXXZXXXZXXZXZX", 
"XXXZXXXZXZXZXXX", "XZXXX-XXXZXZXXX", "XX-XXX-ZZX", "XXZX-XXZXXXZXZ", 
"XZXZXXZXXZXXZXX")

我已经成功地删除了第二次出现之前或之后的所有内容,但无法在保留其他所有内容的同时完全填补空白来替换所需的角色。字符串中没有 Z 或 - 的受让人。

这不是一个简单的正则表达式,但您仍然可以使用它来实现您的需要。

input = c("XX-XXZZXX-XZXXXXX", "XX-XXXZXXZXZXXX", "XXXXXZXXXZXXZX-X", 
"XXXZXXXZXZXZXXX", "XZXXX-XXXZXZXXX", "XX-XXX-ZZX", "XXZX-XXZXXX-XZ", 
"XZXZXX-XXZXXZXX")
gsub("(?:^([^Z]*Z){2}|(?!^)\G)[^-]*\K-", "Z", input, perl=T)

IDEONE demo

正则表达式只匹配两个以 Z 结尾的块(以确保从头开始有两个 Z),然后匹配除连字符和连字符之外的任何字符。只有连字符被 gsub 替换,因为我们省略了与 \K 运算符匹配的内容。由于 \G 运算符匹配上一次成功匹配后的位置,因此我们匹配所有后续连字符。

解释:

  • (?:^([^Z]*Z){2}|(?!^)\G) - 匹配 2 个选项:
    • ^([^Z]*Z){2} - 字符串 (^) 的开头,后跟 2 次出现 ({2}) 的子字符串,其中包含除 Z 之外的 0 个或多个字符 ([^Z]*) 然后是 Z 或...
    • (?!^)\G - 上一次成功匹配结束
  • [^-]*\K - 匹配除 - 之外的 0 个或多个字符 0 次或更多次,并省略整个与 \K
  • 匹配的文本
  • - - 将替换为 Z.
  • 的文字连字符

这里需要perl=T.

@stribizhev 的回答证明了我在正则表达式方面的表现,但你可以在没有正则表达式的情况下通过简单地拆分整个字符串,计算 Z 的出现次数,然后替换掉后续的内容来做到这一点-:

input = c("XX-XXZZXX-XZXXXXX", "XX-XXXZXXZXZXXX", "XXXXXZXXXZXXZX-X", 
          "XXXZXXXZXZXZXXX", "XZXXX-XXXZXZXXX", "XX-XXX-ZZX", "XXZX-XXZXXX-XZ", 
          "XZXZXX-XXZXXZXX")

desired_output = c("XX-XXZZXXZXZXXXXX", "XX-XXXZXXZXZXXX", "XXXXXZXXXZXXZXZX", 
                   "XXXZXXXZXZXZXXX", "XZXXX-XXXZXZXXX", "XX-XXX-ZZX", "XXZX-XXZXXXZXZ", 
                   "XZXZXXZXXZXXZXX")


sp <- strsplit(input, '')
f <- function(x, n = 2) {
  x[x == '-' & (cumsum(x == 'Z') >= n)] <- 'Z'
  paste0(x, collapse = '')
}
identical(res <- sapply(sp, f), desired_output)
# [1] TRUE

cbind(input, res, desired_output)
#      input               res                 desired_output     
# [1,] "XX-XXZZXX-XZXXXXX" "XX-XXZZXXZXZXXXXX" "XX-XXZZXXZXZXXXXX"
# [2,] "XX-XXXZXXZXZXXX"   "XX-XXXZXXZXZXXX"   "XX-XXXZXXZXZXXX"  
# [3,] "XXXXXZXXXZXXZX-X"  "XXXXXZXXXZXXZXZX"  "XXXXXZXXXZXXZXZX" 
# [4,] "XXXZXXXZXZXZXXX"   "XXXZXXXZXZXZXXX"   "XXXZXXXZXZXZXXX"  
# [5,] "XZXXX-XXXZXZXXX"   "XZXXX-XXXZXZXXX"   "XZXXX-XXXZXZXXX"  
# [6,] "XX-XXX-ZZX"        "XX-XXX-ZZX"        "XX-XXX-ZZX"       
# [7,] "XXZX-XXZXXX-XZ"    "XXZX-XXZXXXZXZ"    "XXZX-XXZXXXZXZ"   
# [8,] "XZXZXX-XXZXXZXX"   "XZXZXXZXXZXXZXX"   "XZXZXXZXXZXXZXX"