在解析引号和转义时(参见Why does Parslet (in Ruby) return an empty array when parsing an empty string literal?)我在Parslet中遇到了一个奇怪的事:(escape_char.absent? >> str('"')).absent? >> any
看起来Parslet实际上解决了双重否定并期望转义字符在那里
require 'parslet'
require 'rspec'
require 'parslet/rig/rspec'
require 'parslet/convenience'
class Parser < Parslet::Parser
root(:quote)
rule :quote do
quote >> text >> quote
end
rule :text do
(quote.absent? >> any).repeat
end
rule :quote do
escape_char.absent? >> str('"')
end
rule :escape_char do
str('\\')
end
end
describe Parser do
it 'should parse text in quotes' do
is_expected.to parse('"hello"')
end
it 'should parse text in quotes with escaped quote' do
is_expected.to parse('"foo\"bar"')
end
it 'should parse text in quotes with trailing escaped quote' do
is_expected.to parse('"text\""')
end
end
我对如何解决这个问题并不感兴趣,因为它已在上面链接的帖子中描述过,但仅仅是好奇地理解这种行为。一开始似乎违反直觉,但我确信这背后有充分的理由。
答案 0 :(得分:0)
Parslet通过编写较小的解析器来构建解析器......这就是PEG的美妙之处。
“缺席”是一个解析器,需要一个解析器。它尝试将输入流与包装的解析器进行匹配。如果包装的解析器匹配,则Absent报告“不匹配”。如果内部解析器无法匹配,则“Absent”解析器将通过。
所以,你提到的解析器:
(escape_char.absent? >> str('"')).absent? >> any
将匹配单个字符,但仅当(escape_char.absent? >> str('"'))
无法匹配相同的字符时才会匹配。
(escape_char.absent? >> str('"'))
将无法匹配。
测试这个,结果证明是真的。
require 'parslet'
require 'rspec'
require 'parslet/rig/rspec'
require 'parslet/convenience'
class Parser < Parslet::Parser
root(:x)
rule :x do
(escape_char.absent? >> str('"')).absent? >> any
end
rule :escape_char do
str('\\')
end
end
begin
Parser.new.parse('a') # passes
Parser.new.parse('b') # passes
Parser.new.parse('\\') # passes
Parser.new.parse('"') # << this one fails
puts "pass"
rescue Parslet::ParseFailed => error
puts error.cause.ascii_tree
end