【问题标题】:Why does Python 3 json.loads("foo.com") not work yet json.loads("123.6") does?为什么 Python 3 json.loads("foo.com") 还不能工作 json.loads("123.6") 呢?
【发布时间】:2018-11-16 05:33:54
【问题描述】:

当我尝试加载“foo.com”时,正如预期的那样,我得到了一个异常;但是,如果我正在加载一个包含浮点数的字符串,它就可以工作。只是想弄清楚为什么会这样。

$ python3
Python 3.6.5 (default, Jun 17 2018, 12:13:06)
[GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>> j = json.loads("foo.com")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
>>> j = json.loads("123.6")
>>>

【问题讨论】:

  • 因为123.6 是有效的JSON,但foo.com(不带引号!)不是?
  • @ForceBru 都被引用,因此都应该是字符串。
  • @DeepSpace,因为语法不允许:tools.ietf.org/html/rfc7159#section-2
  • @FranzKafka,它们是 Python 的字符串,但不是 JSON 解析器。
  • 123.6 是有效的数字文字,"foo.com" 是有效的字符串文字,但 foo.com 不是有效的 json

标签: json python-3.x


【解决方案1】:

引自定义 JSON 的 RFC7159:

这些是六个结构字符:

 begin-array     = ws %x5B ws  ; [ left square bracket
 begin-object    = ws %x7B ws  ; { left curly bracket
 end-array       = ws %x5D ws  ; ] right square bracket
 end-object      = ws %x7D ws  ; } right curly bracket
 name-separator  = ws %x3A ws  ; : colon
 value-separator = ws %x2C ws  ; , comma

JSON 值必须是对象、数组、数字或字符串,或其中之一 以下三个字面名称:

false null true

<...> 不允许使用其他文字名称。

value = false / null / true / object / array / number / string
object = begin-object [ member *( value-separator member ) ]
           end-object
array = begin-array [ value *( value-separator value ) ] end-array
number = [ minus ] int [ frac ] [ exp ]
string = quotation-mark *char quotation-mark

如您所见,输入 foo.com 不满足任何条件:

  • 它不以begin-object 开头
  • 也不以begin-array 开头
  • 也不是数字
  • 也不是字符串,因为它quotation-mark开头

但是,123.6 是一个数字:

123 . 6 == int frac

根据 RFC:

frac = decimal-point 1*DIGIT
int = zero / ( digit1-9 *DIGIT )

因此,123 . 6value,所以没关系。

【讨论】:

    【解决方案2】:

    json.loads 需要一个字符串。当 JSON 解析器处理这个字符串时,剩下的就是 foo.com,这是一个无效的令牌。这是这个例子的一个边缘案例:

    json.loads('{a: 1}')
    

    您不会期望这会起作用,不是吗? a 是无效令牌。

    为此,我们需要另一组引号:

    print(json.loads('"foo.com"'))
    # foo.com
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-02
      • 2017-05-10
      • 2023-03-03
      • 2014-02-08
      • 2015-04-08
      相关资源
      最近更新 更多