为什么除法在 jsonpath-ng 中不起作用?

问题描述

Jsonpath-ng 提供基本的算术,如:

from jsonpath_ng import jsonpath
from jsonpath_ng.ext import parse

jsonpath_expr = parse('$.foo * 2')
target = {'foo': 2}
result = jsonpath_expr.find(target)
result = [match.value for match in result]
print(result)

结果:[4]

但是,如果我将表达式更改为 $.foo / 2,则会出现解析错误

Traceback (most recent call last):
  File "test.py",line 4,in <module>
    jsonpath_expr = parse('$.foo / 2')
  File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\jsonpath_ng\ext\parser.py",line 172,in parse
    return ExtentedJsonPathParser(debug=debug).parse(path)
  File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\jsonpath_ng\parser.py",line 32,in parse
    return self.parse_token_stream(lexer.tokenize(string))
  File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\jsonpath_ng\parser.py",line 55,in parse_token_stream
    return new_parser.parse(lexer = IteratorToTokenStream(token_iterator))
  File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\ply\yacc.py",line 333,in parse
    return self.parSEOpt_notrack(input,lexer,debug,tracking,tokenfunc)
  File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\ply\yacc.py",line 1201,in parSEOpt_notrack
    tok = call_errorfunc(self.errorfunc,errtoken,self)
  File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\ply\yacc.py",line 192,in call_errorfunc
    r = errorfunc(token)
  File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\jsonpath_ng\parser.py",line 69,in p_error
    raise Exception('Parse error at %s:%s near token %s (%s)' % (t.lineno,t.col,t.value,t.type))
Exception: Parse error at 1:6 near token / (SORT_DIRECTION)

有时我可以通过除以倒数来解决这个问题,所以我会执行 $.foo * 0.5 来获得结果 [1.0]。但是,如果等式的两边都是不同类型(int 或 float)的数值,这将不起作用。所以 2 * 0.50.5 * 2 会导致解析错误,但 2.0 * 0.5 不会。

如何让部门工作?为什么我不能将浮点数乘以整数?

解决方法

那些都是语法错误。

  1. 允许扩展的 JSON 路径以包含“排序”列表的方括号表达式为后缀;每种排序都以 /\ 开头。为了完成这项工作,扩展词法分析器将这两个符号识别为标记 SORT_DIRECTION,它优先于将 / 识别为算术运算符。因此,解析器不允许使用 / 作为算术运算符。 (事实上​​,问题比这更深,但这就是本质。)

  2. 出于某种原因,语法作者选择在算术表达式中将 NUMBER(实际上是整数)和 FLOAT 分开,这意味着他们必须枚举可能的组合。他们选择的是:

    jsonpath : NUMBER operator NUMBER
             | FLOAT operator FLOAT
             | ID operator ID
             | NUMBER operator jsonpath
             | FLOAT operator jsonpath
             | jsonpath operator NUMBER
             | jsonpath operator FLOAT
             | jsonpath operator jsonpath
    

    这个语法还有其他问题,但这里的本质是它允许 NUMBER operator NUMBERFLOAT operator FLOAT 但不允许 NUMBER operator FLOATFLOAT operator NUMBER,这就是你观察。但是,路径表达式可以与 NUMBERFLOAT 一起使用。