最新消息: 电脑我帮您提供丰富的电脑知识,编程学习,软件下载,win7系统下载。

如何将不可预测的JSON解析为字符串?

IT培训 admin 5浏览 0评论

如何将不可预测的JSON解析为字符串?

假设我有一个node.js应用程序,它以一种奇怪的格式接收输入:带有JSON的字符串随意洒入其中,如下所示:

This is a string {"with":"json","in":"it"} followed by more text {"and":{"some":["more","json"]}} and more text

我对这个输入文本有几个保证:

  1. JSON对象之间的文字文本位总是没有花括号。
  2. 推入文本的顶级JSON对象始终是对象文字,而不是数组。

我的目标是将其拆分为一个数组,单独保留文字文本并解析出JSON,如下所示:

[
    "This is a string ",
    {"with":"json","in":"it"},
    " followed by more text ",
    {"and":{"some":["more","json"]}},
    " and more text"
]

到目前为止,我已经编写了一个naive solution,它只是计算花括号来决定JSON的起点和终点。但是,如果JSON包含带有花括号的字符串{"like":"this one } right here"},则无法使用。我可以尝试通过类似的引用计数数学来解决这个问题,但是我还必须考虑转义的报价。在那一刻,我觉得我正在重做太多JSON.parse的工作。有没有更好的方法来解决这个问题?

回答如下:

这是一个相对简单的蛮力方法:将整个输入字符串拆分为花括号,然后按顺序逐步遍历数组。每当遇到一个开放式大括号时,从成功解析为JSON的起点找到数组中最长的一块。冲洗并重复。

如果输入包含无效的JSON和/或不平衡的大括号,则无效(请参阅下面的最后两个测试用例。)

const tryJSON = input => {
  try {
    return JSON.parse(input);
  } catch (e) {
    return false;
  }
}

const parse = input => {
  let output = [];
  let chunks = input.split(/([{}])/);

  for (let i = 0; i < chunks.length; i++) {
    if (chunks[i] === '{') {
      // found some possible JSON; start at the last } and backtrack until it works.
      for (let j = chunks.lastIndexOf('}'); j > i; j--) {
        if (chunks[j] === '}') {
          // Does it blend?
          let parsed = tryJSON(chunks.slice(i, j + 1).join(""))
          if (parsed) {
            // it does! Grab the whole thing and skip ahead
            output.push(parsed);
            i = j;
          }
        }
      }
    } else if (chunks[i]) {
      // neither JSON nor empty
      output.push(chunks[i])
    }
  }

  console.log(output)
  return output
}

parse(`{"foo": "bar"}`)
parse(`test{"foo": "b}ar{{[[[{}}}}{}{}}"}`)
parse(`this {"is": "a st}ri{ng"} with {"json": ["in", "i{t"]}`)
parse(`{}`)
parse(`this {"i{s": invalid}`)
parse(`So is {this: "one"}`)

如何将不可预测的JSON解析为字符串?

假设我有一个node.js应用程序,它以一种奇怪的格式接收输入:带有JSON的字符串随意洒入其中,如下所示:

This is a string {"with":"json","in":"it"} followed by more text {"and":{"some":["more","json"]}} and more text

我对这个输入文本有几个保证:

  1. JSON对象之间的文字文本位总是没有花括号。
  2. 推入文本的顶级JSON对象始终是对象文字,而不是数组。

我的目标是将其拆分为一个数组,单独保留文字文本并解析出JSON,如下所示:

[
    "This is a string ",
    {"with":"json","in":"it"},
    " followed by more text ",
    {"and":{"some":["more","json"]}},
    " and more text"
]

到目前为止,我已经编写了一个naive solution,它只是计算花括号来决定JSON的起点和终点。但是,如果JSON包含带有花括号的字符串{"like":"this one } right here"},则无法使用。我可以尝试通过类似的引用计数数学来解决这个问题,但是我还必须考虑转义的报价。在那一刻,我觉得我正在重做太多JSON.parse的工作。有没有更好的方法来解决这个问题?

回答如下:

这是一个相对简单的蛮力方法:将整个输入字符串拆分为花括号,然后按顺序逐步遍历数组。每当遇到一个开放式大括号时,从成功解析为JSON的起点找到数组中最长的一块。冲洗并重复。

如果输入包含无效的JSON和/或不平衡的大括号,则无效(请参阅下面的最后两个测试用例。)

const tryJSON = input => {
  try {
    return JSON.parse(input);
  } catch (e) {
    return false;
  }
}

const parse = input => {
  let output = [];
  let chunks = input.split(/([{}])/);

  for (let i = 0; i < chunks.length; i++) {
    if (chunks[i] === '{') {
      // found some possible JSON; start at the last } and backtrack until it works.
      for (let j = chunks.lastIndexOf('}'); j > i; j--) {
        if (chunks[j] === '}') {
          // Does it blend?
          let parsed = tryJSON(chunks.slice(i, j + 1).join(""))
          if (parsed) {
            // it does! Grab the whole thing and skip ahead
            output.push(parsed);
            i = j;
          }
        }
      }
    } else if (chunks[i]) {
      // neither JSON nor empty
      output.push(chunks[i])
    }
  }

  console.log(output)
  return output
}

parse(`{"foo": "bar"}`)
parse(`test{"foo": "b}ar{{[[[{}}}}{}{}}"}`)
parse(`this {"is": "a st}ri{ng"} with {"json": ["in", "i{t"]}`)
parse(`{}`)
parse(`this {"i{s": invalid}`)
parse(`So is {this: "one"}`)
发布评论

评论列表 (0)

  1. 暂无评论