在不同的子字符串出现 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)
正则表达式只匹配两个以 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"
我一直在尝试用 '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)
正则表达式只匹配两个以 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"