正则表达式匹配模式的每第 n 次出现
Regex expression to match every nth occurence of a pattern
考虑这个字符串,
str = "abc-de-fghi-j-k-lm-n-o-p-qrst-u-vw-x-yz"
我想在每第 n 次出现模式时分隔字符串,这里 -
:
f(str, n = 2)
[1] "abc-de" "fghi-j" "k-lm" "n-o"...
f(str, n = 3)
[1] "abc-de-fghi" "j-k-lm" "n-o-p" "qrst-u-vw"...
我知道我可以这样做:
spl <- str_split(str, "-", )[[1]]
unname(sapply(split(spl, ceiling(seq(spl) / 2)), paste, collapse = "-"))
[1] "abc-de" "fghi-j" "k-lm" "n-o" "p-qrst" "u-vw" "x-yz"
但我正在寻找更短更简洁的解决方案
有哪些可能性?
您可以将 str_extract_all
与模式 \w+(?:-\w+){0,2}
一起使用,例如查找包含 3 个单词和 2 个连字符的术语:
str <- "abc-de-fghi-j-k-lm-n-o-p-qrst-u-vw-x-yz"
n <- 2
regex <- paste0("\w+(?:-\w+){0,", n, "}")
str_extract_all(str, regex)[[1]]
[1] "abc-de-fghi" "j-k-lm" "n-o-p" "qrst-u-vw" "x-yz"
n <- 3
regex <- paste0("\w+(?:-\w+){0,", n, "}")
str_extract_all(str, regex)[[1]]
[1] "abc-de-fghi-j" "k-lm-n-o" "p-qrst-u-vw" "x-yz"
另一种方法:首先对找到的每个 split-pattern 进行拆分,然后将 paste/collapse 分成 n-length 组,使用 split-pattern 变量作为折叠字符。
str <- "abc-de-fghi-j-k-lm-n-o-p-qrst-u-vw-x-yz"
n <- 3
pattern <- "-"
ans <- unlist(strsplit(str, pattern))
sapply(split(ans,
ceiling(seq_along(ans)/n)),
paste0, collapse = pattern)
# "abc-de-fghi" "j-k-lm" "n-o-p" "qrst-u-vw" "x-yz"
以下情况如何(其中 'n-1' 是数字的占位符):
(?:[^-]*(?:-[^-]*){n-1})\K-
在线查看demo
(?:
- 打开第一 non-capture 组;
[^-]*
- 匹配其他连字符的 0+ 个字符;
(?:
- 打开嵌套的第二个 non-capture 组;
-[^-]*
- 匹配连字符和除连字符以外的 0+ 个字符;
){n}
- 关闭嵌套的 non-capture 组并匹配 n-times;
)
- 关闭第一个 non-capture 组;
\K-
- 忘记我们刚刚匹配的内容并匹配结尾的连字符。
注意:使用\K
表示我们必须使用PCRE(perl=TRUE
)
要创建 'n-1',我们可以使用 sprintf()
功能来使用变量:
str <- "abc-de-fghi-j-k-lm-n-o-p-qrst-u-vw-x-yz"
for (n in 1:10) {
print(strsplit(str, sprintf("(?:[^-]*(?:-[^-]*){%s})\K-", n-1), perl=TRUE)[[1]])
}
打印:
1) gsubfn gsubfn
在同名包中类似gsub
除了替换可以是函数、列表或原型对象.在原型对象的情况下,可以提供一个 fun
方法,它有一个内置的 count
变量,可用于区分事件。对于每个匹配项,匹配项都会传递给 fun
并替换为 fun
.
的输出
我们使用末尾注释中显示的输入,还使用 n
指定要在结果的每个元素中使用的组件数,并 sep
指定不包含的字符出现在输入中。
gsubfn
用 sep
替换每第 n
个减号,然后 strsplit
拆分。
不需要复杂的正则表达式。
library(gsubfn)
n <- 3
sep <- " "
p <- proto(fun = function(., x) if (count %% n) "-" else sep)
strsplit(gsubfn("-", p, STR), sep)
## [[1]]
## [1] "abc-de-fghi" "j-k-lm" "n-o-p" "qrst-u-vw" "x-yz"
##
## [[2]]
## [1] "abc-de-fghi" "j-k-lm" "n-o-p" "qrst-u-vw" "x-yz"
2) rollapply 另一种方法是拆分每个 - 然后使用 rollapply
再次将其粘贴在一起,给出与 (1) 中相同的结果。
library(zoo)
roll <- function(x) rollapply(x, n, by = n, paste, collapse = "-",
partial = TRUE, align = "left")
lapply(strsplit(STR, "-"), roll)
备注
# input
STR = "abc-de-fghi-j-k-lm-n-o-p-qrst-u-vw-x-yz"
STR <- c(STR, STR)
考虑这个字符串,
str = "abc-de-fghi-j-k-lm-n-o-p-qrst-u-vw-x-yz"
我想在每第 n 次出现模式时分隔字符串,这里 -
:
f(str, n = 2)
[1] "abc-de" "fghi-j" "k-lm" "n-o"...
f(str, n = 3)
[1] "abc-de-fghi" "j-k-lm" "n-o-p" "qrst-u-vw"...
我知道我可以这样做:
spl <- str_split(str, "-", )[[1]]
unname(sapply(split(spl, ceiling(seq(spl) / 2)), paste, collapse = "-"))
[1] "abc-de" "fghi-j" "k-lm" "n-o" "p-qrst" "u-vw" "x-yz"
但我正在寻找更短更简洁的解决方案
有哪些可能性?
您可以将 str_extract_all
与模式 \w+(?:-\w+){0,2}
一起使用,例如查找包含 3 个单词和 2 个连字符的术语:
str <- "abc-de-fghi-j-k-lm-n-o-p-qrst-u-vw-x-yz"
n <- 2
regex <- paste0("\w+(?:-\w+){0,", n, "}")
str_extract_all(str, regex)[[1]]
[1] "abc-de-fghi" "j-k-lm" "n-o-p" "qrst-u-vw" "x-yz"
n <- 3
regex <- paste0("\w+(?:-\w+){0,", n, "}")
str_extract_all(str, regex)[[1]]
[1] "abc-de-fghi-j" "k-lm-n-o" "p-qrst-u-vw" "x-yz"
另一种方法:首先对找到的每个 split-pattern 进行拆分,然后将 paste/collapse 分成 n-length 组,使用 split-pattern 变量作为折叠字符。
str <- "abc-de-fghi-j-k-lm-n-o-p-qrst-u-vw-x-yz"
n <- 3
pattern <- "-"
ans <- unlist(strsplit(str, pattern))
sapply(split(ans,
ceiling(seq_along(ans)/n)),
paste0, collapse = pattern)
# "abc-de-fghi" "j-k-lm" "n-o-p" "qrst-u-vw" "x-yz"
以下情况如何(其中 'n-1' 是数字的占位符):
(?:[^-]*(?:-[^-]*){n-1})\K-
在线查看demo
(?:
- 打开第一 non-capture 组;[^-]*
- 匹配其他连字符的 0+ 个字符;(?:
- 打开嵌套的第二个 non-capture 组;-[^-]*
- 匹配连字符和除连字符以外的 0+ 个字符;){n}
- 关闭嵌套的 non-capture 组并匹配 n-times;
)
- 关闭第一个 non-capture 组;
\K-
- 忘记我们刚刚匹配的内容并匹配结尾的连字符。
注意:使用\K
表示我们必须使用PCRE(perl=TRUE
)
要创建 'n-1',我们可以使用 sprintf()
功能来使用变量:
str <- "abc-de-fghi-j-k-lm-n-o-p-qrst-u-vw-x-yz"
for (n in 1:10) {
print(strsplit(str, sprintf("(?:[^-]*(?:-[^-]*){%s})\K-", n-1), perl=TRUE)[[1]])
}
打印:
1) gsubfn gsubfn
在同名包中类似gsub
除了替换可以是函数、列表或原型对象.在原型对象的情况下,可以提供一个 fun
方法,它有一个内置的 count
变量,可用于区分事件。对于每个匹配项,匹配项都会传递给 fun
并替换为 fun
.
我们使用末尾注释中显示的输入,还使用 n
指定要在结果的每个元素中使用的组件数,并 sep
指定不包含的字符出现在输入中。
gsubfn
用 sep
替换每第 n
个减号,然后 strsplit
拆分。
不需要复杂的正则表达式。
library(gsubfn)
n <- 3
sep <- " "
p <- proto(fun = function(., x) if (count %% n) "-" else sep)
strsplit(gsubfn("-", p, STR), sep)
## [[1]]
## [1] "abc-de-fghi" "j-k-lm" "n-o-p" "qrst-u-vw" "x-yz"
##
## [[2]]
## [1] "abc-de-fghi" "j-k-lm" "n-o-p" "qrst-u-vw" "x-yz"
2) rollapply 另一种方法是拆分每个 - 然后使用 rollapply
再次将其粘贴在一起,给出与 (1) 中相同的结果。
library(zoo)
roll <- function(x) rollapply(x, n, by = n, paste, collapse = "-",
partial = TRUE, align = "left")
lapply(strsplit(STR, "-"), roll)
备注
# input
STR = "abc-de-fghi-j-k-lm-n-o-p-qrst-u-vw-x-yz"
STR <- c(STR, STR)