如何在构建JSON字符串时转义特殊字符?

281

这是我的字符串

{
    'user': {
        'name': 'abc',
        'fx': {
            'message': {
                'color': 'red'
            },
            'user': {
                'color': 'blue'
            }
        }
    },
    'timestamp': '2013-10-04T08: 10: 41+0100',
    'message': 'I'mABC..',
    'nanotime': '19993363098581330'
}    

这里的消息包含单引号,与JSON中使用的引号相同。我所做的是从用户输入(如消息)中填写字符串,因此我需要转义那些会破坏代码的特殊情况。但除了字符串替换之外,是否还有其他方法使它们转义但仍允许HTML将它们处理回正确的消息?


71
JSON 只使用双引号而非单引号,详情请见 http://www.json.org/。 - Niels Bom
5
RFC 4627规定解析器必须能够解析符合JSON标准的内容(第4段),也可以支持其他非JSON扩展。然而,第5段强调指出,所有生成者(生成器)只能生成100%符合标准的JSON。生产不需要转义的帧字符的JSON是一个特别糟糕的想法。请考虑将您的撇号替换为引号。 - Luv2code
3
尽管您提到的观点仍然是正确的,但请注意您引用的规范已经过时。在阅读RFC时,请始终使用https://tools.ietf.org/html版本,而不是文本版本。 HTML版本更易于阅读和链接到子部分,并且最重要的是,在HTML版本的顶部,列出了所有更新或废弃您正在阅读的RFC的后续RFC列表。如果您访问了https://tools.ietf.org/html/rfc4627,您将看到RFC 4627已过时,并已由[RFC 7159](https://tools.ietf.org/html/rfc7159)替换。 - Mark Amery
8
对于未来阅读此文的人,RFC 7159已被https://tools.ietf.org/html/rfc8259所取代。 - Joram van den Boezem
8259规范(截至2020年12月)中相关的部分是第7节,它简单地说:“字符串以引号开头和结尾。”它没有说“可以”,“应该”或“必须”——希望这是他们在下一次修订中要解决的问题。第7节还涉及转义字符串中的字符。任何字符“可以”被转义,但引号、反斜杠(“反向实心线”)和控制字符(U+0000到U+001F)“必须”被转义。 - Jeremy
11个回答

515
我对在一个关于基础主题的高浏览量问题中存在高赞误导信息感到震惊。
JSON字符串不能用单引号括起来。规范的各个版本(原始版本由道格拉斯·克罗克福德,ECMA版本IETF版本)都指出字符串必须用双引号括起来。这不是理论问题,也不是像目前被接受的答案所建议的那样是一种观点问题;如果您尝试解析单引号括起来的字符串,则任何现实世界中的JSON解析器都会出错。
克罗克福德和ECMA版本甚至展示了一个漂亮的图片来定义字符串,这应该可以明确无误地说明这一点:

Image showing the definition of a string from the JSON spec

这张漂亮的图片列出了JSON字符串中所有合法的转义序列:
  • \"
  • \\
  • \/
  • \b
  • \f
  • \n
  • \r
  • \t
  • \u后跟四个十六进制数字
请注意,与其他答案中的无意义内容相反,在JSON字符串中\'从不是一个有效的转义序列。这是因为JSON字符串始终使用双引号。

最后,当您使用编程方式生成JSON时,通常不需要自己考虑转义字符(尽管在手动编辑JSON配置文件时会这样做)。相反,使用本地映射、数组、字符串、数字、布尔和null类型构建要编码的数据结构,然后使用JSON编码函数将其编码为JSON。这样的函数可能已经内置在您使用的语言中,例如JavaScript的JSON.stringify,PHP的json_encode或Python的json.dumps。如果您使用的语言没有此类功能,则可以找到一个JSON解析和编码库来使用。如果您只是使用语言或库函数将事物转换为JSON并从JSON中转换,您甚至不需要了解JSON的转义规则。这就是这里误导的问题提问者应该做的。


1
4个十六进制字节还是半字节 - leetbacoon
56
我赞同这篇帖子的不悦情绪。 - Mike Nakis

351

根据规范,JSON字符串必须使用双引号括起来,所以您无需转义'
如果您必须在JSON字符串中使用特殊字符,则可以使用\字符进行转义。

请参阅以下用于JSON的特殊字符列表:

\b  Backspace (ascii code 08)
\f  Form feed (ascii code 0C)
\n  New line
\r  Carriage return
\t  Tab
\"  Double quote
\\  Backslash character

然而,即使完全违反规范,作者也可以使用单引号\'

这是 不好的,因为:

  • 它与规范相悖
  • 它不再是JSON有效字符串

但是,无论你愿意还是不愿意,它确实可以工作。

对于新读者,请始终在JSON字符串中使用双引号。


38
“single quoted json strings”是无意义的;在JSON中,字符串只能使用双引号。例如,在浏览器控制台中尝试JSON.parse("'foo'"),您将看到SyntaxError: Unexpected token '。JSON规范对此非常简单和清晰。在JSON中没有单引号的转义序列,也不能使用单引号来表示JSON字符串。 - Mark Amery
23
即使这个回答的更新看起来是澄清了问题,但它并不好。虽然从技术上讲是正确的,但说你“不需要”转义 ' 是具有误导性的,就像从技术上讲合法,但说你在法律上“不需要”谋杀儿童一样。更准确的说法是你“无法”转义 '\' 是非法的转义序列,如果你使用它,那么你的 JSON 将不是有效的 JSON,任何 JSON 解析器都将出错。(当然 JavaScript 的 JSON.parse 和 Python 的 json.loads 都会出错。) - Mark Amery
3
经过多次编辑,这个答案仍然是一派胡言。你错误地声称在JSON中使用单引号字符串并使用\'转义序列“无论你想不想要都可以工作”。这是错误的。我向你挑战,展示出任何一个流行的JSON解析器不能处理单引号字符串或\'序列。我已经指出,在JavaScript中JSON.parse("'foo'")JSON.parse('"\\\'"')以及在Python中json.loads("'foo'")json.loads('"\\\'"')都会抛出异常。你根据什么依据声称使用这些结构“有效”? - Mark Amery
12
@Luv2code有趣的引用。你有点误解了它;它并不意味着任何字符都可以通过在前面加上反斜杠来转义。更完整的引用是“任何字符都可以被转义。如果该字符在基本多文种平面(U+0000到U+FFFF)中,则可以表示为六个字符序列。……或者,有一些流行字符的两个字符序列转义表示。”(强调是我的)。这是说你可以将'转义为\u0027,而不是将其作为\'进行转义。 - Mark Amery
2
@Luv2code,这并不意味着我被点赞的评论说“你无法逃脱'”(并将此行为与杀害儿童相比!)在技术上是错误的;更准确的说法是,您可以转义它,但不能使用\'。我没有意识到规范的RFC版本将像\u0027这样的序列称为表示它们所代表的字符的一种方式。然而,\'是非法的这个关键点仍然是正确和重要的。 - Mark Amery
显示剩余12条评论

50

现在大家都在讨论如何在单引号字符串字面量中转义 '。但是这里有一个更大的问题: 单引号字符串字面量不是有效的JSON。JSON基于JavaScript,但它并不相同。如果你正在JavaScript代码内部编写一个对象字面量,那很好;但如果你实际上需要JSON,你需要使用 "

使用双引号字符串时,你不需要转义 '。(如果你确实想在字符串中使用文字 ",则应该使用 \"。)


1
你好,你说用双引号括起来的字符串就不需要转义 '。例如,如果我的字符串值是 "Member's_id" : 4,你是说它不需要转义吗?显然我遇到了一个问题,它报错为错误编码:UTF-8,并且被读取为 Member�s。这是一个手动生成的 JSON 文件。 - Shubham
3
在JSON字符串字面量中,'不应该被转义。你是从其他地方复制粘贴的吗?也许它实际上是\u2019,而不是撇号。我猜测:有人在Microsoft Word中输入了它,因为它认为自己知道得最好,将其转换成引号。从语法上讲,旧的ASCII字符撇号(',又称为“单引号”)是你想要的字符。但如果有其他类似问题,修复你的字符编码问题仍然是很好的选择。所以选择一个字符编码,并将其用于读取和写入操作。或者使用\u进行转义。 - David Knipe

7

大多数回答要么没有回答问题,要么解释过于冗长。

好吧,JSON只使用双引号,我们明白了!

我试图使用JQuery AJAX将JSON数据发送到服务器,然后稍后返回相同的信息。 我发现最好的解决方案是使用:

var d = {
    name: 'whatever',
    address: 'whatever',
    DOB: '01/01/2001'
}
$.ajax({
    type: "POST",
    url: 'some/url',
    dataType: 'json',
    data: JSON.stringify(d),
    ...
}

这将为您转义字符。

这也是Mark Amery建议的,顺便说一句,很棒的答案。

希望这能帮助到某些人。


1

也许我来晚了,但这将解析/转义单引号(不想卷入解析 vs 转义的争论)。

JSON.parse("\"'\"")

0

我曾为复杂的字符串、列表和包含在JSON中的字典混合而苦恼。

简单的答案是,什么都不用做!使用:

 json.dumps( item, indent=4 )

这里的item是一个包含字符串和列表的字典嵌套的例子,它将自动为您转义所有内容。同时输出内容也会以易于阅读的方式进行美化。

下面是一个包含特殊正斜杠字符的列表的字典嵌套的部分示例:

        {
            "MEASUREMENT": [
                "1\u20444 cup"
            ],
            "DESCRIPTION": [
                "dried"
            ],
            "INGREDIENT": [
                "cranberries"
            ]
        },

它会正确地将 \n 替换为 \\n 等等。您不希望转义不需要转义的字符串,因此让 dumps 为您完成。


-1

问题是关于JSON的,但您提供的参考资料是关于JavaScript的,并列出了在JavaScript中无效的转义序列,例如\' - Mark Amery
2
谢谢Mark - 我只是想提供一个不同的角度 - 取决于谁来到这里可能会发现这很有用。但我理解你关于JSON和Javascript的观点 - 感谢你在论坛上的专业表现。 - Luigi D'Amico

-2

使用模板字面量...

var json = `{"1440167924916":{"id":1440167924916,"type":"text","content":"It's a test!"}}`;

这不会以任何方式解析或解码字符串。该字符串中也不包含任何 \\ 字符。 - i336_

-4

使用encodeURIComponent()来对字符串进行编码。

Eg.:

var product_list = encodeURIComponent(JSON.stringify(product_list));

你不需要解码它,因为Web服务器会自动执行相同的操作。


1
这个问题是关于在JSON中编码包含引号的字符串,而不是关于编码JSON以便在URL中传递。 - Quentin

-7

3
在 JSON 字符串中,一个单引号翻倍并不会对其进行转义,而只是表示你的字符串包含两个单引号,而不是一个。 - Mark Amery
你似乎把JSON和SQL搞混了。 - Quentin

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