【问题标题】:Extract JSON from text从文本中提取 JSON
【发布时间】:2012-05-21 10:01:00
【问题描述】:

AJAX 调用正在返回包含 JSON 字符串的响应文本。我需要:

  1. 提取 JSON 字符串
  2. 修改它
  3. 然后重新插入以更新原始字符串

我不太担心第 2 步和第 3 步,但我不知道如何执行第 1 步。我正在考虑使用正则表达式,但我不知道如何因为我的 JSON 可能有多个级别嵌套对象或数组。

【问题讨论】:

  • 你不是新来的。你试过什么?您的反应如何?
  • 另外,RegEx 可能不是这项工作的正确工具。
  • @Truth 到目前为止,我唯一的解决方法是在响应文本中包含标记以显示 JSON 字符串的开头和结尾。没有什么值得骄傲的,也没有什么可以指导答案。

标签: javascript regex json


【解决方案1】:

您不能使用正则表达式从任意文本中提取 JSON。由于正则表达式通常是not powerful enough to validate JSON(除非您可以使用 PCRE),因此它们也无法匹配 - 如果可以,它们也可以验证 JSON。

但是,如果您知道 JSON 的顶级元素始终是对象或数组,则可以采用以下方法:

  • 在字符串中找到第一个开头({[)和最后一个结尾(}])大括号。
  • 尝试使用JSON.parse() 解析该文本块(包括大括号)。如果成功,完成并返回解析结果。
  • 使用前一个右大括号并尝试解析该字符串。如果成功,您将再次完成。
  • 重复此操作,直到没有大括号或在当前开口大括号之前出现一个大括号。
  • 在第 1 步中找到第一个左大括号。如果没有找到,则字符串不包含 JSON 对象/数组,您可以停止。
  • 转到第 2 步。

这是一个提取 JSON 对象并返回对象及其位置的函数。如果你真的也需要顶级数组,那应该是扩展:

function extractJSON(str) {
    var firstOpen, firstClose, candidate;
    firstOpen = str.indexOf('{', firstOpen + 1);
    do {
        firstClose = str.lastIndexOf('}');
        console.log('firstOpen: ' + firstOpen, 'firstClose: ' + firstClose);
        if(firstClose <= firstOpen) {
            return null;
        }
        do {
            candidate = str.substring(firstOpen, firstClose + 1);
            console.log('candidate: ' + candidate);
            try {
                var res = JSON.parse(candidate);
                console.log('...found');
                return [res, firstOpen, firstClose + 1];
            }
            catch(e) {
                console.log('...failed');
            }
            firstClose = str.substr(0, firstClose).lastIndexOf('}');
        } while(firstClose > firstOpen);
        firstOpen = str.indexOf('{', firstOpen + 1);
    } while(firstOpen != -1);
}

var obj = {'foo': 'bar', xxx: '} me[ow]'};
var str = 'blah blah { not {json but here is json: ' + JSON.stringify(obj) + ' and here we have stuff that is } really } not ] json }} at all';
var result = extractJSON(str);
console.log('extracted object:', result[0]);
console.log('expected object :', obj);
console.log('did it work     ?', JSON.stringify(result[0]) == JSON.stringify(obj) ? 'yes!' : 'no');
console.log('surrounding str :', str.substr(0, result[1]) + '<JSON>' + str.substr(result[2]));

Demo(在 nodejs 环境中执行,但也应该在浏览器中运行):https://paste.aeum.net/show/81/

【讨论】:

  • 有趣...您的链接指向一个页面,上面写着“是的,可以进行完整的正则表达式验证”!
  • 哦,嘿,没有滚动过去接受的答案 - 但是,PCRE 非常强大。我认为这些功能在 JavaScript 中不可用。
【解决方案2】:

对于其他正在寻找(和我一样)从一般文本中提取 JSON 字符串(即使它们无效)的人,您可以查看这个 Gulp 插件 https://www.npmjs.com/package/gulp-extract-json-like。它会搜索所有格式类似于 JSON 字符串的字符串。

创建一个文件夹并安装包。

mkdir project && cd project
npm install gulp gulp-extract-json-like

创建一个文件./gulpfile.js并将以下内容放入其中:

var gulp = require('gulp');
var extractJsonLike = require('gulp-extract-json-like');

gulp.task('default', function () {
  return gulp.src('file.txt')
    .pipe(extractJsonLike())
    .pipe(gulp.dest('dist'));
});

创建一个名为 ./file.txt 的文件,其中包含您的文本并运行以下命令。

gulp

找到的 JSON 字符串将在 ./dist/file.txt 中。

【讨论】:

    【解决方案3】:

    如果 JSON 作为 ajax 响应的一部分返回,为什么不使用浏览器原生 JSON 解析(注意 gotchas)?还是jQuery JSON Parsing

    如果 JSON 完全与文本混淆,恕我直言,这确实是设计问题 - 如果您可以更改它,我强烈建议您这样做(即返回单个 JSON 对象作为响应,文本为对象的属性)。

    如果不是,那么使用 RegEx 将是一场绝对的噩梦。 JSON 天生就非常灵活,确保准确解析不仅费时,而且浪费。我可能会在开始/结束时放置内容标记,并希望最好。但是你会对验证错误等持开放态度。

    【讨论】:

    • 不幸的是我无法改变它。我在响应中得到的实际上是一个完整的脚本,其中包含 JSON 文字中的参数。
    • 我很困惑,因为在您对问题的评论中,您在 JSON 字符串的开头/结尾添加了标记?在无法更改响应的情况下,您是如何做到的?
    • 对不起,我的意思是我不能阻止JSON与“文本”混合,文本实际上是一个脚本。
    • 好的,我看到你已经接受了答案。如果这对您有用,那就太棒了,否则 Q 中的示例响应将使我们有机会创建一个可行的解决方案。
    猜你喜欢
    • 2018-12-09
    • 1970-01-01
    • 1970-01-01
    • 2018-01-10
    • 1970-01-01
    • 2018-04-30
    • 1970-01-01
    • 1970-01-01
    • 2016-11-23
    相关资源
    最近更新 更多