原始字符串文本¶
- JEP
12
- 作者
道林
- 状态
认可的
- 创建
2015年4月9日
摘要¶
为了提高语言的可用性并简化解析器的实现,JEP建议对JMESPath进行以下修改:
添加 原始字符串文本 允许表达式包含未被JSON转义序列(例如“\n”、“\r”、“\u005C”)改变的原始字符串的JMESPath。
不赞成当前的文本解析行为,该行为允许将未加引号的JSON字符串解析为JSON字符串,从而消除JMESPath语法中的歧义,并有助于确保实现之间的一致性。
此建议旨在为JMESPath添加以下语法:
'foobar'
'foo\'bar'
`bar` -> Parse error/warning (implementation specific)
动机¶
中提供了原始字符串文本 various programming languages 为了防止特定于语言的解释(即JSON解析)并消除转义的需要,避免了一个称为 leaning toothpick syndrome (LTS) . 倾斜牙签综合症是一个问题,在这种情况下,为了避免分隔符冲突,字符串由于过度使用转义字符而变得不可读(例如。, \\\\\\
)
在计算JMESPath表达式时,通常需要使用不是从被计算的数据中提取的字符串文字,而是静态地使用编译的JMESPath表达式的一部分。字符串文字在许多领域都很有用,但在调用函数或建立多选列表和散列时最为明显。
以下表达式返回在字符串中找到的字符数 foo
. 解析此表达式时, `"foo"
被解析为JSON值,该值生成 ``foo` ::
`"foo"`
下面的表达式在功能上是等价的。注意,JSON文本中省略了引号:
`foo`
这些字符串文本使用JSON解析器进行解析,根据 RFC 4627 ,它将扩展unicode转义序列、换行符和rfc4627第2.5节中记录的其他几个转义序列。
例如,使用转义的unicode值 \u002B
扩展为 +
在以下JMESPath表达式中::
`"foo\u002B"` -> "foo+"
您可以在JSON文本中转义转义序列,以防止转义序列被展开:
`"foo\\u002B"` -> "foo\u002B"
`foo\\u002B` -> "foo\u002B"
虽然这允许您提供文本字符串,但它存在以下问题:
导致额外的JSON解析惩罚。
如果您确实希望数据按字面上提供的方式表示(这可能导致LTS),则需要转义转义字符的认知开销。如果要转义的数据要与另一种使用
\
作为转义符,反斜杠字符的数量将加倍。向JMESPath语法引入了一个模糊规则,该规则需要基于散文的规范来解决解析器实现中的歧义。
目前相关的字面语法规则定义如下:
literal = "`" json-value "`" literal =/ "`" 1*(unescaped-literal / escaped-literal) "`" unescaped-literal = %x20-21 / ; space ! %x23-5B / ; # - [ %x5D-5F / ; ] ^ _ %x61-7A ; a-z %x7C-10FFFF ; |}~ ... escaped-literal = escaped-char / (escape %x60) json-value = false / null / true / json-object / json-array / json-number / json-quoted-string false = %x66.61.6c.73.65 ; false null = %x6e.75.6c.6c ; null true = %x74.72.75.65 ; true json-quoted-string = %x22 1*(unescaped-literal / escaped-literal) %x22 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 ws = *(%x20 / ; Space %x09 / ; Horizontal tab %x0A / ; Line feed or New line %x0D ; Carriage return ) json-object = begin-object [ member *( value-separator member ) ] end-object member = quoted-string name-separator json-value json-array = begin-array [ json-value *( value-separator json-value ) ] end-array json-number = [ minus ] int [ frac ] [ exp ] decimal-point = %x2E ; . digit1-9 = %x31-39 ; 1-9 e = %x65 / %x45 ; e E exp = e [ minus / plus ] 1*DIGIT frac = decimal-point 1*DIGIT int = zero / ( digit1-9 *DIGIT ) minus = %x2D ; - plus = %x2B ; + zero = %x30 ; 0
这个
literal
模棱两可的规则是因为unescaped-literal
包括所有相同的字符json-value
匹配,允许任何有效的JSON值在unescaped-literal
或json-value
.
理论基础¶
在为JMESPath实现解析器时,由于允许JSON字符串文本加上省略引号(例如。, `foo
`). JMESPath的这一特定方面不能在上下文无关语法中明确地描述,并且可能成为实现JMESPath解析器时出现错误的常见原因。
解析JSON文本还有其他复杂的问题。以下是当前在JMESPath中解析JSON文本值所需的步骤:
当A
`
遇到标记,请开始分析JSON文本。收集开头之间的每个字符
`
结束了`
令牌,包括任何逃犯`
字符(即。,\
)并将字符存储在一个变量中(我们称之为 ``$lexeme` )复制的内容
$lexeme
删除所有前导空格和尾随空格的临时值。我们称之为$temp
(目前没有记录,但在 JMESPath compliance tests )如果
$temp
可以解析为有效的JSON,然后将解析的结果用作文本标记的值。如果
$temp
无法分析为有效的JSON,然后包装$lexeme
在双引号中,并将包装的值解析为JSON字符串,使以下表达式等效:`foo
` ==`"foo"
‘和`[1, ]
` ==`"[1, ]"
'.
可以合理地假设,JMESPath表达式中JSON文本的最常见用例是为函数参数提供字符串值,或者为多选列表或多选哈希中的值提供文本字符串值。为了更容易地提供字符串值,决定JMESPath应该允许省略字符串周围的引号。
这项建议认为,不赞成在解析JSON文本时省略引号,而应该向JMESPath添加一个适当的字符串文本规则。
规范¶
原始字符串文字是以单引号开头和结尾的值,不解释转义字符,并且可以包含转义单引号以避免分隔符冲突。
实例¶
以下是几个有效的原始字符串文本及其解析方式的示例:
一个基本的原始字符串文本,解析为
foo bar
::'foo bar'
转义单引号,解析为
foo'bar
::'foo\'bar'
包含新字符串的原始字符串:
'foo bar baz!'
上面的表达式将被解析为包含新行的字符串::
foo baz bar!
包含转义字符的原始字符串文本,解析为
foo\nbar
::foo\nbar
ABNF¶
将添加以下ABNF语法规则,并且在允许表达式的任何位置都允许:
raw-string = "'" *raw-string-char "'"
; The first grouping matches any character other than "\"
raw-string-char = (%x20-26 / %x28-5B / %x5D-10FFFF) / raw-string-escape
raw-string-escape = escape ["'"]
此规则允许原始字符串中的任何字符,包括转义单引号。
除了添加 raw-string
规则,那个 literal
ABNF中的规则将更新为:
literal = "`" json-value "`"
影响¶
对JMESPath现有用户的影响是,删除引号的JSON文本的使用应该转换为使用语法的字符串文本规则。这种转换是否绝对必要,将取决于具体的JMESPath实现。
实现可以选择支持在JSON文本表达式中允许省略引号的旧语法。如果一个实现选择了这种方法,那么该实现应该向用户发出某种警告,让他们知道这是不可取的,以及可能与其他JMESPath实现不兼容的情况。
为了支持JMESPath实现中的这种差异,必须删除所有涉及省略引号的JSON文本符合性测试用例,并且除非放在JEP 12特定的测试套件中,否则不允许在符合性测试中使用无效的未加引号的JSON值的测试用例,允许支持JSON文本中省略引号的实现过滤掉jep12特定的测试用例。
替代方法¶
有几种可供选择的方法。
保持原样¶
这是一个合理有效的建议。保持JMESPath不变将避免对语法的破坏性更改,用户可以继续使用多个转义字符来避免分隔符冲突。
此建议的目标不是向JMESPath添加功能,而是使该语言更易于使用、更易于推理和更易于实现。目前,JSON解析的行为是不明确的,在实现JMESPath解析器时需要特殊的大小写。由于这种模糊性,它还允许实现中的细微差异。
举个例子:
`[1`
一个实现可以将此表达式解释为字符串值为的JSON字符串 "[1"
,而其他实现可能会引发解析错误,因为表达式的第一个字符似乎是有效的JSON。
通过更新语法以在JSON文本标记中要求有效的JSON,我们可以完全消除这种歧义,从而从各种JMESPath实现中消除潜在的不一致源。
不允许在原始字符串中使用单引号¶
此建议指出原始字符串文字中的单引号必须用反斜杠转义。另一种方法是不允许在原始字符串文本中使用单引号。这会简化 raw-string
语法规则会严重限制 raw-string
规则,强制用户使用 literal
规则。
使用可自定义的分隔符¶
有几种语言允许在原始字符串周围放置自定义分隔符。例如,Lua允许 long bracket 原始字符串用 [[]]
任何数量的平衡 = 括号内的字符:
[==[foo=bar]==] -- parsed as "foo=bar"
这种方法非常灵活,无需转义任何字符;但是,这不能用常规语法表示。解析器需要跟踪打开的分隔符的数量,并确保使用适当数量的匹配字符关闭分隔符。
在这个JEP中描述的字符串文本的添加并不排除以后添加由Lua等语言提供的heredoc或定界符样式的字符串文本, D , C++ 等。