【问题标题】:Turning a string with brackets and parentheses into a nested list将带有方括号和圆括号的字符串转换为嵌套列表
【发布时间】:2022-12-10 03:05:09
【问题描述】:

考虑以下字符串:

x = "a (b, c), d [e, f (g, h)], i (j, k (l (m, n [o, p])))"

我的目标是获取此字符串并将其转换为以下列表:

list("a" = list("b", "c"),
     "d" = list("e", "f" = list("g", "h")),
     "i" = list("j", "k" = list("l" = list("m", "n" = list("o", "p")))))

$a
$a[[1]]
[1] "b"

$a[[2]]
[1] "c"


$d
$d[[1]]
[1] "e"

$d$f
$d$f[[1]]
[1] "g"

$d$f[[2]]
[1] "h"



$i
$i[[1]]
[1] "j"

$i$k
$i$k$l
$i$k$l[[1]]
[1] "m"

$i$k$l$n
$i$k$l$n[[1]]
[1] "o"

$i$k$l$n[[2]]
[1] "p"

第一个问题是尝试分离每个组件:

x = "a (b, c), d [e, f (g, h)], i (j, k (l (m, n [o, p])))"

str_split_quotes = function(s) {
  o = el(strsplit(s, split = "(?<=\\)|\\]),", perl = T))
  lapply(o, function(z) gsub(pattern = " ", "", z))
}

str_unparse_level = function(s) {
  
  check_parsed = function(s) {
    grepl("\\)|\\]", s)
  }
  
  parse = function(s)  {
    if (check_parsed(s)) {
      substring_name    = substr(s, 1, 1)
      substring_content = substr(s, 3, nchar(s) - 1)
      substring_content_split = el(strsplit(substring_content, ",(?![^()]*+\\))", perl = T))
      o = list(substring_content_split)
      names(o) = substring_name
      return(o)}
    else {return(s)}
  }
  
  lapply(s, parse)
}

str_unparse_level(str_split_quotes(x))
[[1]]
[[1]]$a
[1] "b" "c"


[[2]]
[[2]]$d
[1] "e"      "f(g,h)"


[[3]]
[[3]]$i
[1] "j"              "k(l(m,n[o,p]))"

直观地,这里需要发生的是某种涉及递归的函数(由于圆括号/方括号的嵌套深度可变)需要在这里执行,以便创建一个列表,正如我在上面寻求的那样。鉴于我很少使用递归,我不清楚该怎么做。

【问题讨论】:

  • 你不需要递归。这是一个与“表达式中的平衡括号”相关的已知问题。该方法是遍历您的字符串并将左括号 - ( 和 [ - 放在堆栈中,当您到达右括号时,您处理堆栈中右括号和最后一个左括号之间的表达式。如此直到堆栈空。然后你进一步遍历字符串并处理下一个表达式。在你的情况下,堆栈可能是一个具有两个字段的对象 - 左括号和它后面的部分字符串。

标签: r


【解决方案1】:

一个选项是在将([修改为list后使用eval(parse

out <- eval(parse(text = gsub('(\w+)', '"\1"', 
   paste0("list(", gsub("\(", "=list(", chartr("[]", "()", x)), 
      ")"))))

-检查OP的输出

> op_out <- list("a" = list("b", "c"),
+                "d" = list("e", "f" = list("g", "h")),
+                "i" = list("j", "k" = list("l" = list("m", "n" = list("o", "p")))))
> all.equal(out, op_out)
[1] TRUE

【讨论】:

    【解决方案2】:

    这是一个使用一些递归来解析字符串的解析器

    
    parse_list <- function(x) {
      opens <- c("(", "[")
      closes  <- c(")", "]")
      tokens <- Filter((x) x!= " ", strsplit(x, "")[[1]])
      maybenames <- function(values, names) if (any(names!="")) setNames(values, names) else values
      inner <- function(start=1) {
        i <- start
        names <- character()
        values <- list()
        while (i <= length(tokens)) {
          if (i < length(tokens)-1 && tokens[i+1] %in% opens) {
            name <- tokens[i]
            i <- i + 1
            opener <- tokens[i]
            i <- i + 1
            result <- inner(i)
            names <- c(names, name)
            values <- c(values, list(result$value))
            i <- result$resume
            closer <- tokens[i]
          } else if (tokens[i] == ",") {
            # next item
          } else if (tokens[i] %in% closes) {
            return(list(value=maybenames(values, names), resume = i))
          } else {
            names <- c(names, "")
            values <- c(values, list(tokens[i]))
          }
          i <- i + 1
        }
        return(maybenames(values, names))
      }
      inner()
    }
    

    你可以这样称呼它

    x = "a (b, c), d [e, f (g, h)], i (j, k (l (m, n [o, p])))"
    parse_list(x)
    

    这确实假设您的所有标签都是单个字符,如果不是这种情况,您将需要调整 tokens 变量以执行所需的任何拆分。实际上并没有任何验证或错误检查。您可能还想添加它。

    【讨论】:

      猜你喜欢
      • 2012-01-28
      • 2014-06-04
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 2021-01-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多