为何Python无法解析含转义引号的合法JSON?
问题:Python JSON模块无法解析验证合法的JSON字符串
以下是测试用的日志字符串:
TEST_LINE = """Oct 21 22:39:28 GMT [TRACE] (Carlos-288) org.some.awesome.LoggerFramework RID=8e9076-4dd9-ec96-8f35-bde193498f: { "service": "MyService", "operation": "queryShowSize", "requestID": "8e9076-4dd9-ec96-8f35-bde193498f", "timestamp": 1634815968000, "parameters": [ { "__type": "org.some.awsome.code.service#queryShowSizeRequest", "externalID": { "__type": "org.some.awsome.code.common#CustomerID", "value": "48317" }, "CountryID": { "__type": "org.some.awsome.code.common#CountryID", "value": "125" }, "operationOriginalDate": 1.63462085667E9, "operationType": "MeasureWithToes", "measureInstrumentIdentifier": "595909-48d2-6115-85e8-b3aa7b" } ], "output": { "__type": "org.some.awsome.code.common#queryShowSizeReply", "shoeSize": { "value": "$ion_1_0 'org.some.awsome.model.processing.ShoeMeasurementBI@1.0'::'org.some.awsome.model.processing.FeetScience@1.0'::{customer_id:\"983017317\",measureInstrumentIdentifierTilda:\"595909-48d2-6115-85e8-b3aa7b\",foot_owner:\"Oedipus\",toe_code:\"LR2X10\",account_number_token:\"1234-2838316-1298470\",token_status:VALID,country_code:GRC,measure_store_format:METRIC}" } } } """
我用正则提取出其中的JSON部分,验证为合法JSON,但Python的JSON模块解析失败,报错信息如下:
Exception has occurred: JSONDecodeError Expecting ',' delimiter: line 25 column 156 (char 992) File "/Users/decoder/Downloads/json-problem.py", line 44, in read_json d = json.loads(line) ^^^^^^^^^^^^^^^^ File "/Users/decoder/Downloads/json-problem.py", line 48, in <module> print(read_json(TEST_LINE)) ^^^^^^^^^^^^^^^^^^^^ json.decoder.JSONDecodeError: Expecting ',' delimiter: line 25 column 156 (char 992)
错误指向output.shoeSize.value中的第一个\",该嵌入的类JSON结构应作为普通字符串处理,且引号已转义,不应提前终止字符串。我的解析代码如下:
import re import json FIND_JSON = re.compile( r"\w{3} \d{2} (\d{2}[: ]){3}GMT \[[^]]+\] \([^)]+\) " r"org.some.awesome.LoggerFramework RID=[^:]+: " ) def read_json(line: str) -> str | None: if not (m := FIND_JSON.match(line)): return None line = line[m.end(0) :] d = json.loads(line) return d print(read_json(TEST_LINE))
尝试过raw_decode()方法,同样失败。
更新1:有评论指出存在未转义的双引号,但我看到的都是冒号后紧跟反斜杠加双引号,且验证合法,怀疑是复制粘贴时的格式转换问题。
更新2:补充了可复现问题的完整代码。
解决方案
问题出在Python字符串的转义处理逻辑上:在Python的三重引号字符串中,\"会被自动解析为单个双引号,而非保留\和"的组合。也就是说,当你定义TEST_LINE时,里面的\"已经被转成了",导致提取后的JSON字符串出现未转义的双引号,触发了解析错误。
举个例子,value字段的内容在Python实际存储时变成了:
$ion_1_0 'org.some.awsome.model.processing.ShoeMeasurementBI@1.0'::'org.some.awsome.model.processing.FeetScience@1.0'::{customer_id:"983017317",...}
这里的"983017317"没有被转义,直接终止了外层字符串,引发报错。
有两种解决方法:
方法1:使用原始字符串定义TEST_LINE
在三重引号前加r,让Python不处理字符串内的转义字符:
TEST_LINE = r"""Oct 21 22:39:28 GMT [TRACE] (Carlos-288) org.some.awesome.LoggerFramework RID=8e9076-4dd9-ec96-8f35-bde193498f: { "service": "MyService", "operation": "queryShowSize", "requestID": "8e9076-4dd9-ec96-8f35-bde193498f", "timestamp": 1634815968000, "parameters": [ { "__type": "org.some.awsome.code.service#queryShowSizeRequest", "externalID": { "__type": "org.some.awsome.code.common#CustomerID", "value": "48317" }, "CountryID": { "__type": "org.some.awsome.code.common#CountryID", "value": "125" }, "operationOriginalDate": 1.63462085667E9, "operationType": "MeasureWithToes", "measureInstrumentIdentifier": "595909-48d2-6115-85e8-b3aa7b" } ], "output": { "__type": "org.some.awsome.code.common#queryShowSizeReply", "shoeSize": { "value": "$ion_1_0 'org.some.awsome.model.processing.ShoeMeasurementBI@1.0'::'org.some.awsome.model.processing.FeetScience@1.0'::{customer_id:\"983017317\",measureInstrumentIdentifierTilda:\"595909-48d2-6115-85e8-b3aa7b\",foot_owner:\"Oedipus\",toe_code:\"LR2X10\",account_number_token:\"1234-2838316-1298470\",token_status:VALID,country_code:GRC,measure_store_format:METRIC}" } } } """
方法2:对转义符进行二次转义
把字符串中的\"替换为\\",让Python解析后保留\"的组合:
TEST_LINE = """Oct 21 22:39:28 GMT [TRACE] (Carlos-288) org.some.awesome.LoggerFramework RID=8e9076-4dd9-ec96-8f35-bde193498f: { "service": "MyService", "operation": "queryShowSize", "requestID": "8e9076-4dd9-ec96-8f35-bde193498f", "timestamp": 1634815968000, "parameters": [ { "__type": "org.some.awsome.code.service#queryShowSizeRequest", "externalID": { "__type": "org.some.awsome.code.common#CustomerID", "value": "48317" }, "CountryID": { "__type": "org.some.awsome.code.common#CountryID", "value": "125" }, "operationOriginalDate": 1.63462085667E9, "operationType": "MeasureWithToes", "measureInstrumentIdentifier": "595909-48d2-6115-85e8-b3aa7b" } ], "output": { "__type": "org.some.awsome.code.common#queryShowSizeReply", "shoeSize": { "value": "$ion_1_0 'org.some.awsome.model.processing.ShoeMeasurementBI@1.0'::'org.some.awsome.model.processing.FeetScience@1.0'::{customer_id:\\\"983017317\\\",measureInstrumentIdentifierTilda:\\\"595909-48d2-6115-85e8-b3aa7b\\\",foot_owner:\\\"Oedipus\\\",toe_code:\\\"LR2X10\\\",account_number_token:\\\"1234-2838316-1298470\\\",token_status:VALID,country_code:GRC,measure_store_format:METRIC}" } } } """
两种方法都能让提取后的JSON字符串保留正确的转义引号,从而被Python的json模块正常解析。
内容的提问来源于stack exchange,提问作者primfaktor
相关产品推荐
相关产品推荐

