如何将字符串的缩进级别解析为 JSON 对象?

Posted

技术标签:

【中文标题】如何将字符串的缩进级别解析为 JSON 对象?【英文标题】:How do I parse the indentation level of a string into a JSON Object? 【发布时间】:2022-01-17 03:07:41 【问题描述】:

我希望能够将一个字符串解析为一个 JSON 对象,类似这样(文本可以是任何东西,我只是把它们这样放置以便您可以看到结构):

A
  A-A
  A-B
    A-B-A
    A-B-B
  A-C
    A-C-A
B

放入一个json对象,结构如下:

[
  
    "root": "A",
    "content": [
       "root": "A-A", "content": [] ,
      
        "root": "A-B",
        "content": [
           "root": "A-B-A", "content": [] ,
           "root": "A-B-B", "content": [] 
        ]
      ,
      
        "root": "A-C",
        "content": [
           "root": "A-C-A", "content": [] 
        ]
      
    ]
  ,
   "root": "B", "content": [] 
]

到目前为止,我有以下内容,但我不确定这是否是最好的方法。也许递归方法会更好?

  let body = [];
  let indentStack = [0];
  for (let line of input.split('\n'))  // input is the string I'd like to parse
    if (line.trim() == '') continue; // skips over empty lines
    let indent = line.match(/^ +/);
    indent = indent ? indent[0].length : 0; // matches the first group of spaces with regex, gets the indent level of this line
    if (indentStack[indentStack.length-1] != indent) 
      if (indentStack.includes(indent)) indentStack.length = indentStack.indexOf(indent)+1; // remove all indent levels after it as it's returned back to a higher level
      else stack.push(indent);
    console.log(`$(indent + '[' + indentStack.join() + ']').padEnd(10, ' '): $line`); // debugging
      
    if (indentStack.length == 1) body.push( root: line, content: [] );
    else 
      body[body.length-1].content.push( root: line.substring(indent), content: [] )
    
  
  console.log(body)

【问题讨论】:

如果你不介意使用库,在 npm 上搜索会发现这个包:indent-tree。 @David784 虽然看起来确实不错,但我这样做是为了一个个人项目,并希望扩展我对这个主题的了解。如果这个没有引起太多关注,我会使用它! 完全理解。该项目的源代码在 github 上是公开的,here...它很短,而且代码看起来很可读。可能是一个很好的资源...... 【参考方案1】:

我会这样做:

const data =
`A
  A-A
  A-B
    A-B-A
    A-B-B
  A-C
    A-C-A
B`;


function doTree(data)
  
  let
    res    = []
  , levels = [ res ]
    ;
  for (let line of data.split('\n'))  
          
    let 
      level   = line.search(/\S/) >> 1  // (index of first non whitespace char) / 2 --> IF indentation is 2 spaces
    , root    = line.trim()
    , content = []
      ;
    if (!root) continue
    levels[level].push(root,content)
    levels[++level] = content
    
  return res
  

console.log( doTree(data) )
.as-console-wrapper max-height: 100%!important;top:0 

关于缩进的问题...

在这里你可以有不等的缩进步骤, 使用空格或制表符。 (不要混用空格和制表符)

const data_023c = // indentation values are 0c, 2c, 3c
`A
  A-A
  A-B
     A-B-A
     A-B-B
  A-C
     A-C-A
B`;

const indentation= (()=>  // IIFE 
  
  let 
    indents = []
  , max     = -1
    ;
  return 
    clear:() => 
      
      indents.length = 0
      max  = -1
      
  , get:(line, lNum='?' ) =>
      
      let ncBefore = line.search(/\S/)

      let level = indents.indexOf(ncBefore)
      if (level===-1)
        
        if (ncBefore < max) throw `error on indentation,\n line = $lNum,\n line value is = "$line"`
        level = indents.push( ncBefore) -1
        max   = ncBefore
        
      return level
      
    
  )()

const doTree = data =>
  
  let
    res    = []
  , levels = [ res ]
  , lineN  = 0
    ;
  indentation.clear()
  for (let line of data.split('\n'))  
    
    lineN++  // line counter for indent error message
    let
      root    = line.trim()
    , content = []
      ;
    if (!root) continue
    let level = indentation.get(line, lineN)
     
    levels[level].push(root,content)
    levels[++level] = content
    
  return res
  

console.log( doTree(data_023c) )
.as-console-wrapper max-height: 100%!important;top:0 

【讨论】:

嗯,它似乎有效!定义关卡时右移有什么作用? @Magnogen 这是一个数学技巧,在计算机科学中,所有数字都以二进制表示。将二进制数除以 2 将始终对应于向右移动。当我们以 10 为底进行计算时也是如此,除以 10 也可以右移,例如:1230/10 = 123 ==> 也有右移。您的缩进值在 2 个字符上,这意味着所有空格计数都有一对值,其中它们的右数字为零。以 10 为底也是一样,所有 10 的倍数都以零结尾。 啊,所以这个解决方案没有考虑更多的缩进类型,比如 4 个空格和制表符?我想知道是否可以通过某种方式对其进行修改来解决这个问题。 @Magnogen 我不明白,你的意思是缩进值不是恒定的?并且同一级别的元素并不总是对齐?并且整个文档中的意图步骤并不总是相同的?这对我来说听起来是个坏主意,还是会产生语法错误? 是的,这会有点奇怪,但如果有人要使用 4 个字符的缩进或制表符,这实际上是不允许的。然而,我已经提出了一个解决方案,因为我已经研究了你的代码,并将用我发现的内容来回答这个问题。感谢您的帮助!

以上是关于如何将字符串的缩进级别解析为 JSON 对象?的主要内容,如果未能解决你的问题,请参考以下文章

使用 AutoHotkey 解析、生成和美化/格式化 Json?

Spark - 如何将 JSON 转义的字符串字段解析为 DataFrames 中的 JSON 对象?

在 iOS 中,如何将 JSON 字符串解析为对象

在我们将其解析为 JSON 之前,Snowflake 如何转义对象数组字符串中的所有特殊字符?

JAVA中如何将一个json形式的字符串转为json对象?

php如何将json对象转字符串