R:正则表达式疯狂(stringi)
R: Regex madness (stringi)
我有一个字符串向量,如下所示:
G30(H).G3(M).G0(L).Replicate(1)
遍历 c("H", "M", "L")
,我想提取 G30
(对于“H
”)、G3
(对于“M
”)和G0
(对于“L
”)。
我的各种尝试让我感到困惑 - regex101.com
调试器,例如表示 (\w*)\(M\)
工作正常,但将其传输到 R 失败 ...
我很确定有更好的解决方案,但这行得通...
jnk <- 'G30(H).G3(M).G0(L).Replicate(1)'
patter <- '([^\(]+)\(H\)\.([^\(]+)\(M\)\.([^\(]+)\(L\)\.Replicate\(\d+\)'
H <- sub(patter, '\1', jnk)
M <- sub(patter, '\2', jnk)
L <- sub(patter, '\3', jnk)
编辑:
实际上,我曾经发现一个非常好的函数 parse.one
,它可以像正则表达式一样以 python 的方式搜索更多...
看看这个:
parse.one <- function(res, result) {
m <- do.call(rbind, lapply(seq_along(res), function(i) {
if(result[i] == -1) return("")
st <- attr(result, "capture.start")[i, ]
substring(res[i], st, st + attr(result, "capture.length")[i, ] - 1)
}))
colnames(m) <- attr(result, "capture.names")
m
}
jnk <- 'G30(H).G3(M).G0(L).Replicate(1)'
pattern <- '(?<H>[^\(]+)\(H\)\.(?<M>[^\(]+)\(M\)\.(?<L>[^\(]+)\(L\)\.Replicate\(\d+\)'
parse.one(jnk, regexpr(pattern, jnk, perl=TRUE))
结果如下所示:
> parse.one(jnk, regexpr(pattern, jnk, perl=TRUE))
H M L
[1,] "G30" "G3" "G0"
如果顺序始终相同,另一种方法可能是拆分字符串。例如:
string <- "G30(H).G3(M).G0(L).Replicate(1)"
tmp <- str_split(string, "\.")[[1]]
lapply(tmp[1:3], function(x) str_split(x, "\(")[[1]][1])
[[1]]
[1] "G30"
[[2]]
[1] "G3"
[[3]]
[1] "G0"
如果允许更改标签(例如“(H).”)之前的代码(例如'G30')或字符串中标签的顺序(不同的字母或长度),您可能想尝试基于 regexpr().
的更灵活的解决方案
aa <-paste("G30(H).G3(M).G0(L).Replicate(",1:10,")", sep="")
my.tags <- c("H","M", "L")
extr.data <- lapply(my.tags, (function(tag){
pat <- paste("\(", tag, "\)\.", sep="")
pos <- regexpr(paste("(^|\.)([[:alnum:]])*", pat ,sep=""), aa)
out <- substr(aa, pos, (pos+attributes(pos)$match.length - 4 - length(tag)))
gsub("(^\.)", "", out)
}))
names(extr.data) <- my.tags
extr.data
我将假设函数 (G...) 是可变的并且输入也是可变的。这确实假设您的函数以 G 开头并且您的输入始终是字母。
parse = function(arb){
tmp = stringi::stri_extract_all_regex(arb,"G.*?\([A-Z]\)")[[1]]
unlist(lapply(lapply(tmp,strsplit,"\)|\("),function(x){
output = x[[1]][1]
names(output) = x[[1]][2]
return(output)
}))
}
这首先解析出所有 G 函数及其输入。然后,每一个都被分成它们的功能部分和它们的输入部分。这是放入以其输入命名的函数的字符向量。
parse("G30(H).G3(M).G0(L).Replicate(1)")
> H M L
"G30" "G3" "G0"
或
parse("G35(L).G31(P).G02(K).Replicate(1)")
> L P K
"G35" "G31" "G02"
使用 stringi
包和 outer()
函数:
library(stringi)
strings <- c(
"G30(H).G3(M).G0(L).Replicate(1)",
"G5(M).G11(L).G6(H).Replicate(9)",
"G10(M).G6(H).G8(M).Replicate(200)" # No "L", repeated "M"
)
targets <- c("H", "M", "L")
patterns <- paste0("\w+(?=\(", targets, "\))")
matches <- outer(strings, patterns, FUN = stri_extract_first_regex)
colnames(matches) <- targets
matches
# H M L
# [1,] "G30" "G3" "G0"
# [2,] "G6" "G5" "G11"
# [3,] "G6" "G10" NA
这将忽略第一个目标字母之后的任何实例,当未找到目标时为您提供 NA
,并且 returns 简单矩阵中的所有内容。 patterns
中存储的正则表达式匹配子字符串,如 XX(Y)
,其中 Y
是目标字母,XX
是任意数量的单词字符。
我有一个字符串向量,如下所示:
G30(H).G3(M).G0(L).Replicate(1)
遍历 c("H", "M", "L")
,我想提取 G30
(对于“H
”)、G3
(对于“M
”)和G0
(对于“L
”)。
我的各种尝试让我感到困惑 - regex101.com
调试器,例如表示 (\w*)\(M\)
工作正常,但将其传输到 R 失败 ...
我很确定有更好的解决方案,但这行得通...
jnk <- 'G30(H).G3(M).G0(L).Replicate(1)'
patter <- '([^\(]+)\(H\)\.([^\(]+)\(M\)\.([^\(]+)\(L\)\.Replicate\(\d+\)'
H <- sub(patter, '\1', jnk)
M <- sub(patter, '\2', jnk)
L <- sub(patter, '\3', jnk)
编辑:
实际上,我曾经发现一个非常好的函数 parse.one
,它可以像正则表达式一样以 python 的方式搜索更多...
看看这个:
parse.one <- function(res, result) {
m <- do.call(rbind, lapply(seq_along(res), function(i) {
if(result[i] == -1) return("")
st <- attr(result, "capture.start")[i, ]
substring(res[i], st, st + attr(result, "capture.length")[i, ] - 1)
}))
colnames(m) <- attr(result, "capture.names")
m
}
jnk <- 'G30(H).G3(M).G0(L).Replicate(1)'
pattern <- '(?<H>[^\(]+)\(H\)\.(?<M>[^\(]+)\(M\)\.(?<L>[^\(]+)\(L\)\.Replicate\(\d+\)'
parse.one(jnk, regexpr(pattern, jnk, perl=TRUE))
结果如下所示:
> parse.one(jnk, regexpr(pattern, jnk, perl=TRUE))
H M L
[1,] "G30" "G3" "G0"
如果顺序始终相同,另一种方法可能是拆分字符串。例如:
string <- "G30(H).G3(M).G0(L).Replicate(1)"
tmp <- str_split(string, "\.")[[1]]
lapply(tmp[1:3], function(x) str_split(x, "\(")[[1]][1])
[[1]]
[1] "G30"
[[2]]
[1] "G3"
[[3]]
[1] "G0"
如果允许更改标签(例如“(H).”)之前的代码(例如'G30')或字符串中标签的顺序(不同的字母或长度),您可能想尝试基于 regexpr().
的更灵活的解决方案aa <-paste("G30(H).G3(M).G0(L).Replicate(",1:10,")", sep="")
my.tags <- c("H","M", "L")
extr.data <- lapply(my.tags, (function(tag){
pat <- paste("\(", tag, "\)\.", sep="")
pos <- regexpr(paste("(^|\.)([[:alnum:]])*", pat ,sep=""), aa)
out <- substr(aa, pos, (pos+attributes(pos)$match.length - 4 - length(tag)))
gsub("(^\.)", "", out)
}))
names(extr.data) <- my.tags
extr.data
我将假设函数 (G...) 是可变的并且输入也是可变的。这确实假设您的函数以 G 开头并且您的输入始终是字母。
parse = function(arb){
tmp = stringi::stri_extract_all_regex(arb,"G.*?\([A-Z]\)")[[1]]
unlist(lapply(lapply(tmp,strsplit,"\)|\("),function(x){
output = x[[1]][1]
names(output) = x[[1]][2]
return(output)
}))
}
这首先解析出所有 G 函数及其输入。然后,每一个都被分成它们的功能部分和它们的输入部分。这是放入以其输入命名的函数的字符向量。
parse("G30(H).G3(M).G0(L).Replicate(1)")
> H M L
"G30" "G3" "G0"
或
parse("G35(L).G31(P).G02(K).Replicate(1)")
> L P K
"G35" "G31" "G02"
使用 stringi
包和 outer()
函数:
library(stringi)
strings <- c(
"G30(H).G3(M).G0(L).Replicate(1)",
"G5(M).G11(L).G6(H).Replicate(9)",
"G10(M).G6(H).G8(M).Replicate(200)" # No "L", repeated "M"
)
targets <- c("H", "M", "L")
patterns <- paste0("\w+(?=\(", targets, "\))")
matches <- outer(strings, patterns, FUN = stri_extract_first_regex)
colnames(matches) <- targets
matches
# H M L
# [1,] "G30" "G3" "G0"
# [2,] "G6" "G5" "G11"
# [3,] "G6" "G10" NA
这将忽略第一个目标字母之后的任何实例,当未找到目标时为您提供 NA
,并且 returns 简单矩阵中的所有内容。 patterns
中存储的正则表达式匹配子字符串,如 XX(Y)
,其中 Y
是目标字母,XX
是任意数量的单词字符。