問題の名前 : アンエスケープ
問題 : http://nabetani.sakura.ne.jp/hena/orde29unes/
実装リンク集 : https://qiita.com/Nabetani/items/f2db9b916c0a301b744f
次回のイベントは 2/2
see https://yhpg.doorkeeper.jp/events/84247 。
で。
当日、スタート直前に書き上がった、racc による実装。
racc
class E29Parser
rule
result : BOL entries EOL { @ents = val[1] }
entries : entry { result = [val.join] }
| entries SLASH entry { result = val[0] + [val[2]]}
entry : entry_unit { result = val.join }
| entry entry_unit { result = val.join }
entry_unit : ALNUM { result = val[0] }
| SLASH_PAIR { result = "/" }
| dq_unit
| sq_unit
dq_unit : DQ in_dq DQ { result = val[1] }
| DQ DQ { result = "" }
in_dq : in_dq_atom { result = val.join }
| in_dq in_dq_atom { result = val.join }
in_dq_atom : SLASH_PAIR { result = val[0] }
| ALNUM { result = val[0] }
| SLASH { result = val[0] }
| SQ { result = val[0] }
sq_unit : SQ in_sq SQ { result = val[1] }
| SQ SQ { result = "" }
in_sq : in_sq_atom { result = val.join }
| in_sq in_sq_atom { result = val.join }
in_sq_atom : SLASH_PAIR { result = val[0] }
| ALNUM { result = val[0] }
| SLASH { result = val[0] }
| DQ { result = val[0] }
end
---- inner
def parse( src )
@q = [[:BOL, nil]] + src.scan( %r!\w+|\"|\'|//|/! ).to_a.map{ |t|
type = case t
when /\w+/; :ALNUM
when '"'; :DQ
when "'"; :SQ
when "//"; :SLASH_PAIR
when "/"; :SLASH
else; raise "unexpected"
end
[ type, t ]
} + [[:EOL,nil]]
do_parse
@ents
end
def next_token
@q.shift
end
---- footer
require "json"
def solve( src )
begin
parser = E29Parser.new
ents = parser.parse( src )
ents.any?(&:empty?) ? "-" : ents.join(",")
rescue Racc::ParseError => e
return "-"
end
end
def test( src, expected )
actual = solve( src )
okay = actual == expected
puts [
( okay ? "ok" : "**NG**" ),
src, actual, expected
].join(" ")
end
if __FILE__ == $0
data = JSON.parse( File.open( "data.json" ){ |f| f.read } )
data["test_data"].each do |e|
test( e["src"], e["expected"] )
end
end
racc はシンタックスハイライトが効かないのがちょっと残念。
VSCode で書いたんだけど、VSCode でも白黒だった。そういうものか。
テストデータは上記の問題文ページの末尾にある data.json
。
実行方法は、上記の内容を e29.y
として、
racc -g e29.y -o e29.rb && ruby e29.rb
こんな感じ。
生まれて初めて racc 書いたのでちょっと大変だったけど、1時間前後だと思う。
もちろん自分が回答者だったら本番では選ばない選択だけど。
実装にあたっては、
https://qiita.com/lnznt/items/ecbc16cae8ab9c641391
を大いに参考にした。ありがとうございます。
不満は
- dq_unit と sq_unit は大差ないのに両方ベタで書いてしまった
- レキサ(
scan
)で、//
を/
と別のトークンにしたところ
の二点。
両方とも、rule の書き方がわかってないということだと思う。
もうちょっとあがいてみようと思うけれど、今日のところはこれぐらいで。