R 拆分字符串,但忽略由给定字符包围的分隔符
我想拆分一个字符串,但仅当它没有被给定的字符集包围时才使用分隔符 当前:R 拆分字符串,但忽略由给定字符包围的分隔符,r,regex,string-parsing,R,Regex,String Parsing,我想拆分一个字符串,但仅当它没有被给定的字符集包围时才使用分隔符 当前: strsplit("1 ? 2 ? (3 ? 4) ? {5 ? (6 ? 7)}","\\?") #> [[1]] #> [1] "1 " " 2 " " (3 " " 4) " " {5 " " (6 " " 7)}" 预期: strsplit2 <- function(x, split, fixed = FALSE, perl = FALSE, useBytes = FALSE,
strsplit("1 ? 2 ? (3 ? 4) ? {5 ? (6 ? 7)}","\\?")
#> [[1]]
#> [1] "1 " " 2 " " (3 " " 4) " " {5 " " (6 " " 7)}"
预期:
strsplit2 <- function(x, split, fixed = FALSE, perl = FALSE, useBytes = FALSE,
escape = c("()","{}","[]","''",'""',"%%")){
# ...
}
strsplit2("1 ? 2 ? (3 ? 4) ? {5 ? (6 ? 7)}","\\?")
#> [[1]]
#> [1] "1 " " 2 " " (3 ? 4) " " {5 ? (6 ? 7)}"
我通过一些复杂的解析解决了这个问题,但我担心性能,不知道正则表达式是否可以更快
供参考:
我目前的解决方案与这个问题不太相关,它是:
parse_qm_args <- function(x){
x <- str2lang(x)
# if single symbol
if(is.symbol(x)) return(x)
i <- numeric(0)
out <- character(0)
while(identical(x[[c(i,1)]], quote(`?`)) &&
(!length(i) || length(x[[i]]) == 3)){
out <- c(x[[c(i,3)]],out)
i <- c(2, i)
}
# if no `?` was found
if(!length(out)) return(x)
if(length(x[[i]]) == 2) {
# if we have a unary `?` fetch its arg
out <- c(x[[c(i,2)]],out)
} else {
# if we have a binary `?` fetch the its first arg
out <- c(x[[c(i)]], out)
}
out
}
*SKIP*FAIL和perl=T是您的朋友:
some_string <- c("1 ? 2 ? (3 ? 4) ? {5 ? (6 ? 7)}")
pattern <- c("(?:\\{[^{}]*\\}|\\([^()]*\\))(*SKIP)(*FAIL)|\\?")
some_parts <- strsplit(some_string, pattern, perl = T)
some_parts
看。这对嵌套构造不起作用。*SKIP*FAIL和perl=t是您的朋友:
some_string <- c("1 ? 2 ? (3 ? 4) ? {5 ? (6 ? 7)}")
pattern <- c("(?:\\{[^{}]*\\}|\\([^()]*\\))(*SKIP)(*FAIL)|\\?")
some_parts <- strsplit(some_string, pattern, perl = T)
some_parts
看。这对嵌套结构不起作用。这里是@CodeManiac思想的一个实现,它进行了一些优化并处理了边缘情况
splitter这里是@CodeManiac想法的一个实现,其中包括一些优化和处理边缘情况
splitter最好的方法是使用递归。在这种情况下,您将捕获所有分组的元素,然后在未分组的删除器上拆分:
pattern = "([({'](?:[^(){}']*|(?1))*[')}])(*SKIP)(*FAIL)|\\?"
x1 <- "1 ? 2 ? (3 ? 4) ? {5 ? (6 ? 7)}"
x2 <- "1 ? 2 ? '3 ? 4' ? {5 ? (6 ? 7)}"
x3 <- "1 ? 2 ? '3 {(? 4' ? {5 ? (6 ? 7)}"
x4 <- "1 ? 2 ? '(3 ? 4) ? {5 ? (6 ? 7)}'"
strsplit(c(x1,x2,x3, x4),pattern,perl=TRUE)
[[1]]
[1] "1 " " 2 " " (3 ? 4) " " {5 ? (6 ? 7)}"
[[2]]
[1] "1 " " 2 " " '3 ? 4' " " {5 ? (6 ? 7)}"
[[3]]
[1] "1 " " 2 " " '3 {(? 4' " " {5 ? (6 ? 7)}"
[[4]]
[1] "1 " " 2 " " '(3 ? 4) ? {5 ? (6 ? 7)}'"
最好的办法是使用递归。在这种情况下,您将捕获所有分组的元素,然后在未分组的删除器上拆分:
pattern = "([({'](?:[^(){}']*|(?1))*[')}])(*SKIP)(*FAIL)|\\?"
x1 <- "1 ? 2 ? (3 ? 4) ? {5 ? (6 ? 7)}"
x2 <- "1 ? 2 ? '3 ? 4' ? {5 ? (6 ? 7)}"
x3 <- "1 ? 2 ? '3 {(? 4' ? {5 ? (6 ? 7)}"
x4 <- "1 ? 2 ? '(3 ? 4) ? {5 ? (6 ? 7)}'"
strsplit(c(x1,x2,x3, x4),pattern,perl=TRUE)
[[1]]
[1] "1 " " 2 " " (3 ? 4) " " {5 ? (6 ? 7)}"
[[2]]
[1] "1 " " 2 " " '3 ? 4' " " {5 ? (6 ? 7)}"
[[3]]
[1] "1 " " 2 " " '3 {(? 4' " " {5 ? (6 ? 7)}"
[[4]]
[1] "1 " " 2 " " '(3 ? 4) ? {5 ? (6 ? 7)}'"
这似乎是相关的:但我不知道如何概括它你的牙套总是平衡的吗?如果是的话,那么最简单的方法就是遍历字符串,跟踪开始大括号和?的位置,只有在到达分隔符且开始大括号和结束大括号相等时才拆分,否则替换?使用输出字符串中所需的+解析总是比反向引用更快,在这里,您的用例需要反向引用,IMO使用简单解析就足以获得您在扩展我的第一条注释时所期望的结果。类似的事情可以很容易地完成,我不认为正则表达式在需要返回引用时可以更快地进行解析,但这种循环很慢,但我想C++可以使用RCPP实现……这似乎是相关的:但是我不知道如何概括你的括号总是平衡的吗?如果是的话,那么最简单的方法就是遍历字符串,跟踪开始大括号和?的位置,只有在到达分隔符且开始大括号和结束大括号相等时才拆分,否则替换?使用输出字符串中所需的+解析总是比反向引用更快,在这里,您的用例需要反向引用,IMO使用简单解析就足以获得您在扩展我的第一条注释时所期望的结果。有些事情可以很容易地完成,我认为ReGEX在需要返回引用时可以更快地进行简单解析,但这种循环在R中很慢,但我想它可以在C++中使用RCPP……:[^ {} ] **?1 * ]使它很慢。此外,似乎可能存在{和}内部的不平衡和不平衡,反之亦然。我会使用一个更精确的正则表达式,有更多的替换,可能是展开的。此外,似乎可能存在{和}内部的不平衡和不平衡,反之亦然。我会使用一个更精确的正则表达式和更多的替换,可能是展开的。
pattern = "([({'](?:[^(){}']*|(?1))*[')}])(*SKIP)(*FAIL)|\\?"
x1 <- "1 ? 2 ? (3 ? 4) ? {5 ? (6 ? 7)}"
x2 <- "1 ? 2 ? '3 ? 4' ? {5 ? (6 ? 7)}"
x3 <- "1 ? 2 ? '3 {(? 4' ? {5 ? (6 ? 7)}"
x4 <- "1 ? 2 ? '(3 ? 4) ? {5 ? (6 ? 7)}'"
strsplit(c(x1,x2,x3, x4),pattern,perl=TRUE)
[[1]]
[1] "1 " " 2 " " (3 ? 4) " " {5 ? (6 ? 7)}"
[[2]]
[1] "1 " " 2 " " '3 ? 4' " " {5 ? (6 ? 7)}"
[[3]]
[1] "1 " " 2 " " '3 {(? 4' " " {5 ? (6 ? 7)}"
[[4]]
[1] "1 " " 2 " " '(3 ? 4) ? {5 ? (6 ? 7)}'"