r语言 - 仅在"level"由括号确定的顶层拆分带有嵌套括号的字符串



我正在尝试创建一个正则表达式,该表达式将允许我仅在中心逗号上拆分下面的字符串。

str_1 <- "N(0, 1)"
str_2 <- "N(N(0.1, 1), 1)"
str_3 <- "N(U(0, 1), 1)"
str_4 <- "N(0, T(0, 1))"
str_5 <- "N(N(0, 1), N(0, 1))"

把它们看作是分布的参数。现在,我想在";顶级";。

一些细节:数字可以是十进制数字,也可以是正数和负数。它们将始终分组在U()N()LN()T()内,并用逗号分隔。稍后将添加更多的分组,因此需要一个更通用的解决方案,或者它很容易扩展。我想做的是在";顶级";逗号

现在,str_1的第一种情况是直接使用

unlist(strsplit(str_1, ",", perl = TRUE))

在我继续之前,我需要知道我是否有一个嵌套。我知道如果有嵌套,我会有N、U、LN或T中的多个。所以为了检查,我做了(针对str_2(:

length(attr(gregexpr("(N|LN|U|T)", str_2, perl = TRUE)[[1]], "match.length")) > 1

在确定了我是否有嵌套(可能是一种更干净的测试方法?(之后,我可以继续计算剩余字符串的拆分。然而,这就是我的困境。由于str_2str_3str_4的情况不明确,因此我无法计算逗号。我该如何确保我只在中间逗号处分开?

我期望以下输出(因此去掉第一个字母、括号和最后一个括号(

# str_2
"N(0.1, 1)" "1"
# str_3
"U(0, 1)" "1"
# str_4
"0" "T(0, 1)"
# str_5
"N(0, 1)" "N(0, 1)"

如果可能的话,我希望使用基本R来减少代码的依赖项数量。非常感谢您的帮助。这也可能是正则表达式无法解决的,但需要一种编程方法,可能是如本Java问题中所建议的递归。

如果您的字符向量是您显示的格式,那么您可以使用单个PCRE regex:来实现所需内容

(?:G(?!^)s*,s*|^N()K(?:d+|w+(([^()]*(?:(?1)[^()]*)*)))(?=s*,|)$)

请参阅regex演示详细信息

  • (?:G(?!^)s*,s*|^N()-上一次成功匹配的末尾(G(?!^)(,然后在字符串的开头用一个逗号(s*,s*(或一个N(字符串(^N((括起来
  • K-一个匹配重置运算符,用于丢弃当前匹配内存缓冲区中迄今为止匹配的所有文本
  • (?:-非捕获组启动
    • d+-一个或多个数字
    • |-或
    • w+-一个或多个单词字符
    • (([^()]*(?:(?1)[^()]*)*))-第1组(递归正常工作所需(:一个(,然后是除()之外的任何零个或多个字符,然后是零个或多次出现第1组模式(递归(,然后是()之外的零个或更多个字符,最后是)字符
  • )-非捕获组结束
  • (?=s*,|)$)-后面紧跟零个或多个空格,然后在字符串末尾加一个逗号或)字符

查看regex演示:

strs <- c("N(0, 1)", "N(N(0.1, 1), 1)", "N(U(0, 1), 1)", "N(0, T(0, 1))", "N(N(0, 1), N(0, 1))")
p <- "(?:\G(?!^)\s*,\s*|^N\()\K(?:\d+|\w+(\([^()]*(?:(?1)[^()]*)*\)))(?=\s*,|\)$)"
regmatches(strs, gregexpr(p, strs, perl=TRUE))
# => [[1]]
#    [1] "0" "1"
#    
#    [[2]]
#    [1] "N(0.1, 1)" "1"        
#    
#    [[3]]
#    [1] "U(0, 1)" "1"      
#    
#    [[4]]
#    [1] "0"       "T(0, 1)"
#    
#    [[5]]
#    [1] "N(0, 1)" "N(0, 1)"

如果我们认为结构保持不变,那么我们可以做:

lapply(parse(text=strings), function(x)c(deparse(x[[2]]), deparse(x[[3]])))
[[1]]
[1] "0" "1"
[[2]]
[1] "N(0.1, 1)" "1"        
[[3]]
[1] "U(0, 1)" "1"      
[[4]]
[1] "0"       "T(0, 1)"
[[5]]
[1] "N(0, 1)" "N(0, 1)"

strings <- c("N(0, 1)", "N(N(0.1, 1), 1)", "N(U(0, 1), 1)", "N(0, T(0, 1))", "N(N(0, 1), N(0, 1))")

s定义为字符串的字符向量。我们计算左括号的累积数量减去右括号的累积次数,并将差值为0的任何逗号替换为分号,然后将其拆分。

为此,我们使用gsubfn,它与gsub类似,只是替换不需要是字符串,而是可以是proto对象。proto对象的pre方法在每个字符串的开头运行,fun方法在传递给gsubfn的模式的每个匹配中运行。下面定义的CCD_ 36方法将CCD_ 37设置为0,其中CCD_。fun在每次与左括号、右括号或逗号匹配时运行,每次我们获得与的匹配

  • 左括号将递增lev
  • 右括号将递减lev
  • 逗号如果lev==0,它将发出分号来替换逗号

使用sub删除输入s开头和结尾的垃圾,运行gsubfn,然后用分号分隔结果。最后,我们将结果简化为一个数据帧。输出字符矢量在这里每个都具有长度2,但如果它们可以具有不同的长度,则省略as.data.frame

library(gsubfn)
library(magrittr)

# s is char vec; rm is TRUE if 1st two chars & last one to be removed
# output is list of char vecs
Split <- function(s, rm = TRUE) {
p <- proto(
pre = function(this) this$lev <- 0,
fun = function(this, x) {
this$lev <- this$lev + ( x == "(" ) - ( x == ")" )
if (x == "," && this$lev == 0) ";" else x
}
)
if (rm) s <- sub("^..(.*).$", r"{1}", s)
s %>% gsubfn(r"{[(),]}", p, .) %>% strsplit(" *; *")
}
# test 1
s <- c(str_1 = "N(0, 1)", str_2 = "N(N(0.1, 1), 1)", str_3 = "N(U(0, 1), 1)", 
str_4 = "N(0, T(0, 1))", str_5 = "N(N(0, 1), N(0, 1))")
s %>% Split %>% as.data.frame
##   str_1     str_2   str_3   str_4   str_5
## 1     0 N(0.1, 1) U(0, 1)       0 N(0, 1)
## 2     1         1       1 T(0, 1) N(0, 1)

注意,这可以与任何数量的参数一起使用:

# test 2
w <- "lognormal(N(0, 1), 1), lognormal(0, U(0, 1)), beta(U(1, 1), 2), N(0, 1)"
w %>% Split(rm = FALSE)  %>% unlist
## [1] "lognormal(N(0, 1), 1)" "lognormal(0, U(0, 1))" "beta(U(1, 1), 2)"     
## [4] "N(0, 1)"   

相关内容

  • 没有找到相关文章

最新更新