regex 使用函数将JavaScript对象解析为JSON

4bbkushb  于 2022-11-18  发布在  Java
关注(0)|答案(2)|浏览(169)

我有一个包含JavaScript对象的字符串,如下所示:

const myString = `[{"url":"https:\/\/audio.ngfiles.com\/1171000\/1171300_small-talk.mp3?f1668090863","is_published":true,"portal_id":2,"file_id":0,"project_id":1973416,"item_id":1171300,"description":"Audio File","width":null,"height":null,"filesize":5776266,"params":{"filename":"https:\/\/audio.ngfiles.com\/1171000\/1171300_small-talk.mp3?f1668090863","name":"small%20talk","length":"145","loop":0,"artist":"arbelamram","icon":"https:\/\/aicon.ngfiles.com\/1171\/1171300.png?f1668090865","images":{"listen":{"playing":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.png?f1668090905","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.png"},"completed":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.completed.png?f1668090905","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.completed.png"}},"condensed":{"playing":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.png?f1668090906","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.png"},"completed":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.completed.png?f1668090906","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.completed.png"}}},"duration":145},"portal_item_requirements":[5],"html":"\n\n<div id=\"audio-listen-player\" class=\"audio-listen-player\">\n\t<div id=\"audio-listen-wrapper\" class=\"audio-listen-wrapper\">\n\n\t\t<div id=\"waveform\" class=\"audio-listen-container\"><\/div>\n\n\t\t<div class=\"outer-frame\"><\/div>\n\n\t\t<p id=\"cant-play-mp3\" style=\"display:none\">Your Browser does not support html5\/mp3 audio playback.!!!<\/p>\n\n\t\t<p id=\"loading-audio\">\n\t\t\t<em class=\"fa fa-spin fa-spinner\"><\/em> LOADING...\n\t\t<\/p>\n\t<\/div>\n\n\t<div class=\"audio-listen-controls\">\n\t\t<div class=\"play-controls\">\n\t\t\t<button class=\"audio-listen-btn\" id=\"audio-listen-play\" disabled>\n\t\t\t\t<i class=\"fa fa-play\"><\/i>\n\t\t\t<\/button>\n\n\t\t\t<button class=\"audio-listen-btn\" id=\"audio-listen-pause\" disabled>\n\t\t\t\t<i class=\"fa fa-pause\"><\/i>\n\t\t\t<\/button>\n\n\t\t<\/div>\n\t\t<div class=\"playback-info\">\n\t\t\t<span id=\"audio-listen-progress\">00.00<\/span>\n\t\t\t\/\n\t\t\t<span id=\"audio-listen-duration\">00.00<\/span>\n\t\t<\/div>\n\t\t<div class=\"sound-controls\">\n\t\t\t<button class=\"audio-listen-btn\" id=\"audio-listen-repeat\">\n\t\t\t\t<i class=\"fa fa-retweet\"><\/i>\n\t\t\t<\/button>\n\n\t\t\t\t\t\t\t<button class=\"audio-listen-btn\" id=\"audio-listen-volumeToggle\">\n\t\t\t\t\t<i class=\"fa fa-volume-off\"><\/i>\n\t\t\t\t<\/button>\n\n\t\t\t\t<div class=\"off\" id=\"audio-listen-volume\"><\/div>\n\t\t\t\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n",
callback:function(){(function($) { var player = NgAudioPlayer.fromListenPage({ 'generic_id': 1171300, 'type_id': 3, 'url': "https:\/\/audio.ngfiles.com\/1171000\/1171300_small-talk.mp3?f1668090863", 'version': 1668090863, 'duration': 145, 'loop': false, 'images': {"listen":{"playing":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.png?f1668090905","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.png"},"completed":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.completed.png?f1668090905","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.completed.png"}},"condensed":{"playing":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.png?f1668090906","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.png"},"completed":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.completed.png?f1668090906","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.completed.png"}}}, 'playlist': 'listen' }, 128);   })(jQuery); }}]`

正如您所看到的,它是JavaScript并具有函数,但我需要一种方法来将对象的其余部分解析为JSON,而不使用eval
它可以返回null(其中有函数),也可以完全删除键和值。
我试过下面的正则表达式,但我不是最好的,所以我只是不断搞乱对象,使其无法解析和运行。

/function\([^()]*\){[^}]*}/gi

然后替换为null

oyxsuwqo

oyxsuwqo1#

您需要一个适当的语言解析器来替换一个空函数。
使用正则表达式的挑战是输入中有嵌套的圆括号和方括号,您需要查找匹配对,以便找到函数的结尾。
使用regex可以通过以下三个步骤完成此操作:
1.使用嵌套级别注解{},例如{~0~ ... {~1~ ... }~1~ ... }~0~
1.通过非贪婪地查找具有相同嵌套级别的右括号(如function() {~1~ ... {~2~ ... }~2~... }~1~),将函数替换为null
1.清除剩余括号的嵌套注解
下面是使用愚蠢的输入来演示这三个步骤的工作代码:

const input = `[{
  name: "jimmy",
  avatar: { size16: "jimmy16.png" },
  callback: function() {
    (function ($) {
      let o = { foo: "bar", sub: { marine: 1 } };
    })(jQuery);
  },
  zzz: "z1"
}]`;
console.log('input: ' + input);
let level = 0;
let inputWithLevel = input.replace(/[\{\}]/g, m => {
  if(m === '{') {
    return '{~' + (level++) + '~';
  } else {
    return '}~' + (--level) + '~';
  }
});
console.log('inputWithLevel: ' + inputWithLevel);
let result = inputWithLevel
  .replace(/\b(\w+: *)function\(\) *\{~(\d+)~[\s\S]*?\}~(\2)~/g, '$1null')
  .replace(/([\{\}])~\d+~/g, '$1');
console.log('result: ' + result);

输出量:

input: [{
  name: "jimmy",
  avatar: { size16: "jimmy16.png" },
  callback: function() {
    (function ($) {
      let o = { foo: "bar", sub: { marine: 1 } };
    })(jQuery);
  },
  zzz: "z1"
}]
inputWithLevel: [{~0~
  name: "jimmy",
  avatar: {~1~ size16: "jimmy16.png" }~1~,
  callback: function() {~1~
    (function ($) {~2~
      let o = {~3~ foo: "bar", sub: {~4~ marine: 1 }~4~ }~3~;
    }~2~)(jQuery);
  }~1~,
  zzz: "z1"
}~0~]
result: [{
  name: "jimmy",
  avatar: { size16: "jimmy16.png" },
  callback: null,
  zzz: "z1"
}]

提醒一句:此正则表达式方法不包括极端情况:

  • 如果输入有非对称括号(例如,不可编译)
  • 如果文本值包含非对称方括号
83qze16e

83qze16e2#

请注意OP和其他想玩这个的人:您不能只用途:

`...`

当您硬编码SO上字符串时,必须用途:

String.raw`...`

否则转义的控制字符将变成控制字符--弄乱JSON.parse。这当然不是问题,如果你收到这个字符串。
修复后,您可以使用以下正则表达式来匹配“garbage”:

/,\s*callback[\s\S]+(?=\}\])/g

替换为空字符串,您将得到有效的JSON。
说明

,\s*callback[\s\S]+(?=\}\])-匹配逗号、可选空格和后跟一个或多个任意字符(greedy)的callback,直到查找}]
这是因为[\s\S]+greedy。它将从匹配文本的其余部分开始,然后向后移动,直到前瞻匹配。

证明(致@PeterThoeny):

const myString = String.raw`[{"url":"https:\/\/audio.ngfiles.com\/1171000\/1171300_small-talk.mp3?f1668090863","is_published":true,"portal_id":2,"file_id":0,"project_id":1973416,"item_id":1171300,"description":"Audio File","width":null,"height":null,"filesize":5776266,"params":{"filename":"https:\/\/audio.ngfiles.com\/1171000\/1171300_small-talk.mp3?f1668090863","name":"small%20talk","length":"145","loop":0,"artist":"arbelamram","icon":"https:\/\/aicon.ngfiles.com\/1171\/1171300.png?f1668090865","images":{"listen":{"playing":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.png?f1668090905","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.png"},"completed":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.completed.png?f1668090905","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.completed.png"}},"condensed":{"playing":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.png?f1668090906","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.png"},"completed":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.completed.png?f1668090906","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.completed.png"}}},"duration":145},"portal_item_requirements":[5],"html":"\n\n<div id=\"audio-listen-player\" class=\"audio-listen-player\">\n\t<div id=\"audio-listen-wrapper\" class=\"audio-listen-wrapper\">\n\n\t\t<div id=\"waveform\" class=\"audio-listen-container\"><\/div>\n\n\t\t<div class=\"outer-frame\"><\/div>\n\n\t\t<p id=\"cant-play-mp3\" style=\"display:none\">Your Browser does not support html5\/mp3 audio playback.!!!<\/p>\n\n\t\t<p id=\"loading-audio\">\n\t\t\t<em class=\"fa fa-spin fa-spinner\"><\/em> LOADING...\n\t\t<\/p>\n\t<\/div>\n\n\t<div class=\"audio-listen-controls\">\n\t\t<div class=\"play-controls\">\n\t\t\t<button class=\"audio-listen-btn\" id=\"audio-listen-play\" disabled>\n\t\t\t\t<i class=\"fa fa-play\"><\/i>\n\t\t\t<\/button>\n\n\t\t\t<button class=\"audio-listen-btn\" id=\"audio-listen-pause\" disabled>\n\t\t\t\t<i class=\"fa fa-pause\"><\/i>\n\t\t\t<\/button>\n\n\t\t<\/div>\n\t\t<div class=\"playback-info\">\n\t\t\t<span id=\"audio-listen-progress\">00.00<\/span>\n\t\t\t\/\n\t\t\t<span id=\"audio-listen-duration\">00.00<\/span>\n\t\t<\/div>\n\t\t<div class=\"sound-controls\">\n\t\t\t<button class=\"audio-listen-btn\" id=\"audio-listen-repeat\">\n\t\t\t\t<i class=\"fa fa-retweet\"><\/i>\n\t\t\t<\/button>\n\n\t\t\t\t\t\t\t<button class=\"audio-listen-btn\" id=\"audio-listen-volumeToggle\">\n\t\t\t\t\t<i class=\"fa fa-volume-off\"><\/i>\n\t\t\t\t<\/button>\n\n\t\t\t\t<div class=\"off\" id=\"audio-listen-volume\"><\/div>\n\t\t\t\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n",
callback:function(){(function($) { var player = NgAudioPlayer.fromListenPage({ 'generic_id': 1171300, 'type_id': 3, 'url': "https:\/\/audio.ngfiles.com\/1171000\/1171300_small-talk.mp3?f1668090863", 'version': 1668090863, 'duration': 145, 'loop': false, 'images': {"listen":{"playing":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.png?f1668090905","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.png"},"completed":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.completed.png?f1668090905","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.listen.completed.png"}},"condensed":{"playing":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.png?f1668090906","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.png"},"completed":{"url":"https:\/\/img.ngfiles.com\/audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.completed.png?f1668090906","rel_path":"audio_peaks\/3\/1171000\/1171300.1668090863-1505287.condensed.completed.png"}}}, 'playlist': 'listen' }, 128);   })(jQuery); }}]`;

    let regex = /,\s*callback[\s\S]+(?=\}\])/g;

    let json = myString.replaceAll(regex, '');

    let myObject = JSON.parse(json);

    console.log(myObject);

相关问题