Peg 解析器 - 支持转义字符
Peg parser - support for escape characters
我正在研究 Peg 解析器。在其他结构中,它需要解析标记指令。标签可以包含任何字符。如果您希望标签包含大括号 }
,您可以使用反斜杠将其转义。如果你需要一个文字反斜杠,那也应该被转义。我试图通过 JSON 的 Peg 语法来实现这一点:https://github.com/pegjs/pegjs/blob/master/examples/json.pegjs
有两个问题:
- 转义的反斜杠会导致两个反斜杠字符,而不是一个。输入示例:
{ some characters but escape with a \ }
- 解析器在转义卷曲时中断
\}
。输入示例:
{ some characters but escape \} with a \ }
相关语法为:
Tag
= "{" _ tagContent:$(TagChar+) _ "}" {
return { type: "tag", content: tagContent }
}
TagChar
= [^\}\r\n]
/ Escape
sequence:(
"\" { return {type: "char", char: "\"}; }
/ "}" { return {type: "char", char: "\x7d"}; }
)
{ return sequence; }
_ "whitespace"
= [ \t\n\r]*
Escape
= "\"
您可以使用在线 PegJS 沙箱轻松测试语法和测试输入:https://pegjs.org/online
我希望有人有办法解决这个问题。
这些错误基本上都是拼写错误。
第一个问题是标记字符的正则表达式中的 class 字符。在字符 class 中,\
继续作为转义字符,因此 [^\}\r\n]
匹配除 }
以外的任何字符(使用不必要的反斜杠转义),回车 return 或换行符。 \
就是这样一个字符,所以用字符class来匹配,而Escape
从来没有尝试过。
由于您的标记字符模式未能成功将 \
识别为 Escape
,因此标记 { \ }
被解析为四个字符(space、反斜杠, 反斜杠, space) 并且标记 { \} }
被解析为在第一个 }
处终止,造成语法错误。
所以你应该把字符class固定为[^}\\r\n]
(我把右大括号放在前面是为了更容易阅读落木。顺序无关紧要。)
完成后,您会发现解析器 return 的字符串中的反斜杠仍然完好无损。这是因为 Tag
模式中的 $
:"{" _ tagContent:$(TagChar+) _ "}"
。根据the documentation,$
运算符的含义是:(强调)
$ expression
Try to match the expression. If the match succeeds, return the matched text instead of the match result.
供参考,正确的语法如下:
Tag
= "{" _ tagContent:TagChar+ _ "}" {
return { type: "tag", content: tagContent.map(c => c.char || c).join('') }
}
TagChar
= [^}\\r\n]
/ Escape
sequence:(
"\" { return {type: "char", char: "\"}; }
/ "}" { return {type: "char", char: "\x7d"}; }
)
{ return sequence; }
_ "whitespace"
= [ \t\n\r]*
Escape
= "\"
使用以下输入时:
{ some characters but escape \} with a \ }
会 return:
{
"type": "tag",
"content": "some characters but escape } with a \ "
}
我正在研究 Peg 解析器。在其他结构中,它需要解析标记指令。标签可以包含任何字符。如果您希望标签包含大括号 }
,您可以使用反斜杠将其转义。如果你需要一个文字反斜杠,那也应该被转义。我试图通过 JSON 的 Peg 语法来实现这一点:https://github.com/pegjs/pegjs/blob/master/examples/json.pegjs
有两个问题:
- 转义的反斜杠会导致两个反斜杠字符,而不是一个。输入示例:
{ some characters but escape with a \ }
- 解析器在转义卷曲时中断
\}
。输入示例:
{ some characters but escape \} with a \ }
相关语法为:
Tag
= "{" _ tagContent:$(TagChar+) _ "}" {
return { type: "tag", content: tagContent }
}
TagChar
= [^\}\r\n]
/ Escape
sequence:(
"\" { return {type: "char", char: "\"}; }
/ "}" { return {type: "char", char: "\x7d"}; }
)
{ return sequence; }
_ "whitespace"
= [ \t\n\r]*
Escape
= "\"
您可以使用在线 PegJS 沙箱轻松测试语法和测试输入:https://pegjs.org/online
我希望有人有办法解决这个问题。
这些错误基本上都是拼写错误。
第一个问题是标记字符的正则表达式中的 class 字符。在字符 class 中,\
继续作为转义字符,因此 [^\}\r\n]
匹配除 }
以外的任何字符(使用不必要的反斜杠转义),回车 return 或换行符。 \
就是这样一个字符,所以用字符class来匹配,而Escape
从来没有尝试过。
由于您的标记字符模式未能成功将 \
识别为 Escape
,因此标记 { \ }
被解析为四个字符(space、反斜杠, 反斜杠, space) 并且标记 { \} }
被解析为在第一个 }
处终止,造成语法错误。
所以你应该把字符class固定为[^}\\r\n]
(我把右大括号放在前面是为了更容易阅读落木。顺序无关紧要。)
完成后,您会发现解析器 return 的字符串中的反斜杠仍然完好无损。这是因为 Tag
模式中的 $
:"{" _ tagContent:$(TagChar+) _ "}"
。根据the documentation,$
运算符的含义是:(强调)
$ expression
Try to match the expression. If the match succeeds, return the matched text instead of the match result.
供参考,正确的语法如下:
Tag
= "{" _ tagContent:TagChar+ _ "}" {
return { type: "tag", content: tagContent.map(c => c.char || c).join('') }
}
TagChar
= [^}\\r\n]
/ Escape
sequence:(
"\" { return {type: "char", char: "\"}; }
/ "}" { return {type: "char", char: "\x7d"}; }
)
{ return sequence; }
_ "whitespace"
= [ \t\n\r]*
Escape
= "\"
使用以下输入时:
{ some characters but escape \} with a \ }
会 return:
{
"type": "tag",
"content": "some characters but escape } with a \ "
}