在JavaScript中为键添加双引号的正则表达式

12

我正在使用jQuery的getJSON函数进行请求,并处理JSON响应。问题是我收到的响应格式不正确,我不能更改它。响应内容如下:

{
    aNumber: 200,    
    someText: '\'hello\' world',
    anObject: {
        'foo': 'fooValue',
        'bar': '10.0'
    } 
}

为了是有效的JSON,它应该长成这样:

{
    "aNumber": 200,    
    "someText": "'hello' world",
    "anObject": {
        "foo": "fooValue",
        "bar": "10.0"
    } 
}

我想将返回的文本更改为有效的JSON对象。 我已经使用JavaScript replace函数将单引号转换为双引号,将转义的单引号转换为单引号,但现在我不知道最佳方法是如何在键值周围添加引号。

例如,如何将foo: "fooValue"更改为"foo":"fooValue"? 有没有正则表达式可以使此过程更轻松?

提前感谢!


2
我在另一个问题中编写了一个转换函数,使用简单的正则表达式,不需要eval() - Thai
5个回答

19

这个正则表达式可以解决问题。

$json = preg_replace('/([{,])(\s*)([A-Za-z0-9_\-]+?)\s*:/','$1"$3":',$json);

虽然它是 PHP,但我认为将其转换为 JS 不是问题。


10
完美!对于我的JS朋友,这是一个将"dirtyJSON"中所有的非引号对象键名转换为带引号的JSON格式字符串的正则表达式:JSON.parse(dirtyJSON.replace(/([{,])(\s*)([A-Za-z0-9_\-]+?)\s*:/g, '$1"$3":')) - Kus

13

我试图使用JavaScript中的正则表达式解决同样的问题。我编写了一个用于解析传入JSON的Node.js应用程序,但希望有一个“放松”的解析器版本(请参见以下评论),因为在每个键(名称)周围放置引号很不方便。这是我的解决方案:

var objKeysRegex = /({|,)(?:\s*)(?:')?([A-Za-z_$\.][A-Za-z0-9_ \-\.$]*)(?:')?(?:\s*):/g;// look for object names
var newQuotedKeysString = originalString.replace(objKeysRegex, "$1\"$2\":");// all object names should be double quoted
var newObject = JSON.parse(newQuotedKeysString);

下面是正则表达式的分解:

  • ({|,)寻找对象的开头,{用于浅层对象或嵌套对象时用,
  • (?:\s*)查找但不记住空格
  • (?:')?查找但不记住单引号(稍后将被双引号替换)。这里可能有零或一个。
  • ([A-Za-z_$\.][A-Za-z0-9_ \-\.$]*)为名称(或键)。以任何字母、下划线、$或点开头,后跟零个或多个字母数字字符、下划线、破折号、点或$。
  • 最后一个字符:为限定对象名称和值之间的分隔符。

现在我们可以使用replace()函数并添加一些参数来获取我们新的带引号的键:

originalString.replace(objKeysRegex, "$1\"$2\":")

其中$1可以是{,,具体取决于该对象是否嵌入在另一个对象中。\"添加双引号。$2表示名称。\"再次添加双引号。最后,:结束它。

使用以下代码进行测试:

{keyOne: "value1", $keyTwo: "value 2", key-3:{key4:18.34}}

输出:

{"keyOne": "value1","$keyTwo": "value 2","key-3":{"key4":18.34}}

一些注释:

  • 我没有测试过这种方法的速度,但根据我阅读到的一些条目,使用正则表达式比eval()更快
  • 对于我的应用程序,我使用 ([A-Za-z_$\.][A-Za-z0-9_ \-\.$]*) 限制名称允许具有的字符,作为我“宽松”版本的JSON解析器。如果你想在名称中允许更多的字符(你可以这样做并且仍然拥有有效的JSON),你可以使用 ([^'":]+) 表示除了双引号或单引号或冒号之外的任何内容。这将仍然限制您的字符范围,不如JSON标准(允许名称中出现单引号),但您将无法使用此方法进行解析。您可以在此表达式 ([^'":]+) 中包含各种内容,所以要小心。

希望对您有所帮助。


这是许多情况下的“足够好”的解决方案。但请不要自欺欺人地认为任何正则表达式都能处理所有输入。例如,考虑当此正则表达式接收此输入时会发生什么:“{"sillyValue" : "{hey:there}"}” - Jeremy Frank
{ name : "value"} => { "name_": "value" },同时会留下尾随空格。 - DNV
很好的解决方案@John,它帮助了我的特定情况。您能否指导我如何将相同的解决方案应用于对象的值? - Ryan Penfold

2
UPD 2020: 您所拥有的对象是一个有效的JavaScript对象,但不是100%有效的JSON
将其转换为有效的JSON的简单方法是利用JavaScript提供给您的功能,JSON.stringify
JSON.stringify(object)

你可以在浏览器的JS控制台上运行此代码。
如果你想要格式化输出(即“漂亮打印”),你可以向该函数传递两个参数——替换器(一个允许你过滤掉对象某些属性的函数;如果你不关心,可以直接传递一个null)和空格(一个数字或者字符串,将被放置在你的对象字符串表示的每个键值对之前)。
JSON.stringify(object, null, 4)

在您的情况下,这个调用

JSON.stringify({
    aNumber: 200,    
    someText: '\'hello\' world',
    anObject: {
        'foo': 'fooValue',
        'bar': '10.0'
    } 
}, null, 4)

将会给你

{
    "aNumber": 200,
    "someText": "'hello' world",
    "anObject": {
        "foo": "fooValue",
        "bar": "10.0"
    }
}

您不需要这样做 - 您已经拥有一个有效的JSON对象。在此处阅读有关JSON的信息。
如果您需要获取值,只需编写`data.whatever`即可正常工作。例如:如果您有JSON对象`data`:
{ moo: "foo", foo: "bar" }
所有可能的字段都是`moo`和`foo`,它们的用途分别是`data.moo`和`data.foo`。如果您想将`data`用作jQuery参数,只需按原样传递即可:`$.load("http://my.site.com/moo", data, function(response){ /* ... */ })`。
注意:在上面提到的最后一个示例中,响应将是一个字符串。要使其成为有效的JSON对象,请使用`$.parseJSON(response);`方法。

1
他已经从服务器获取了一个响应字符串。问题是该字符串不是有效的JSON格式,但它是有效的JavaScript代码。 - Pointy
@Pointy,这是一些演示:http://jsfiddle.net/kBZu5/。请告诉我哪里出错了。或者我可能误解了问题? - shybovycha
1
在真正的JSON符号中,属性名称 - 冒号左侧的标识符 - 必须用引号括起来。所有引用都必须使用双引号字符("),而不是单引号字符。有关更多信息,请参见http://json.org。它是JavaScript对象文字语法的子集。 - Pointy
这是一个有帮助的答案。虽然我没有一个有效的JSON对象,但我有有效的Javascript。我不能使用jQuery的parseJSON,因为parseJSON期望格式良好的JSON。但是,我可以通过eval函数运行响应来使用data.moo或data.foo。 - Evil E
@Evil E,很高兴它对你有所帮助!=) - shybovycha

2

编辑 — 首先要指出的是,这不是一个可以用正则表达式解决的问题。

重要的是要区分JSON表示法作为序列化形式和JavaScript对象常量表示法之间的区别。

这个:

{ x: "hello" }

是一个完全有效的JavaScript值(一个表达式片段),因此这样做:

var y = { x: "hello" };

这句话的意思是“与下面代码完全相同”:

var y = { "x": "hello" };

换句话说,在这两种情况下,“y”的值将完全相同。完全一样,以至于永远无法说出使用哪个常量来初始化“y”。
现在,如果您想要将包含JavaScript样式的“JSON简写”转换为有效的JSON字符串,则唯一要做的是解析它,并在属性名称周围重新构造字符串添加引号。也就是说,您要么需要编写自己的“宽松”JSON解析器,可以处理未带引号的标识符作为属性名称,要么需要找到一个可以处理此类宽松语法的现成解析器。
在您的情况下,一旦您有了“宽松”解析器,您就完成了;不需要再进行翻译。值得庆幸的是,您的“无效”JSON响应可以被JavaScript本身完全解释,因此如果您信任数据源(这是一个重大的“如果”),则应该能够使用“eval()”对其进行评估。

0

由于它是一个格式不正确的“JSON”,您将无法使用jQuery.getJSON。

您可以使用

jQuery.ajax({
      url : myUrl,
      data : myParams,
      type : "GET",
      success : function(jsontext)
      {
          // jsontext is in text format
          jsontext = jsontext.replace("'", "\"");
          // now convert text to JSON object
          var jsonData = eval('(' + jsontext+ ')');

          // rest of the code
      }
 });

虽然使用 'eval' 块可能存在漏洞并可能引起安全问题。您可以很好地使用 JSON 解析器,如----JSON.parse(jsontext)代替 eval 来获取 JSON 对象。 - Manish Mulani
问题在于原始文本不是有效的JSON。 - Pointy
这是一个非常好的、可行的解决方案,非常接近我在阅读@Pointy的答案后实现的内容。我使用了jQuery.ajax函数,但明确将dataType定义为'text'。也没有必要替换引号。 - Evil E

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接