はじめに
叛逆のニジガサキ、これは、令和のボーボボ!(確信) nikkieです。
私は抽象構文木がけっこう好き1なのですが、PHPカンファレンス小田原2024の発表アーカイブをきっかけに、pyparsingライブラリを触り出しました。
目次
「二郎系ラーメンのコールで学ぶ AST 解析」by めもり〜☆
きっかけは、あすみ様2のアドベントカレンダー。
PHPカンファレンス小田原20243のトークを1本ずつ視聴して記事にされています。
あすみ様アドカレ記事をきっかけにアーカイブを見て4、私もPythonで「ニンニクマシマシ野菜マシマシカラメ」をパースしてみたいと思ったのでした。
よろしくpyparsing
名前だけ知っていたpyparsingをこの機に触ります。
試しにLLM(Gemini)にサンプルコードを書いてもらい、これを手がかりとしてドキュメントに当たりながら手を動かしていきました。
- Python 3.12.6
- pyparsing 3.2.0
「野菜マシマシ」
from pyparsing import one_of topping = one_of("ニンニク 野菜 カラ") amount = one_of("マシマシ マシ メ") jiro_item = topping("topping") + amount("amount") print(jiro_item.parse_string("野菜マシマシ"))
% python script.py ['野菜', 'マシマシ']
one_of
で単語のいずれかを定義topping("topping")
はtopping.set_results_name("topping")
- https://pyparsing-docs.readthedocs.io/en/latest/pyparsing.html#pyparsing.ParserElement.set_results_name
- ニンニク、野菜、カラのいずれかにマッチしたら、
topping
という名前で扱える
parse_string
で文字列をパース
「ニンニクマシ野菜マシマシカラメ」
from pyparsing import ZeroOrMore, one_of topping = one_of("ニンニク 野菜 カラ") amount = one_of("マシマシ マシ メ") jiro_item = topping("topping") + amount("amount") jiro_expr = jiro_item + ZeroOrMore(jiro_item) order = "ニンニクマシ野菜マシマシカラメ" parsed = jiro_item.search_string(order) for p in parsed: print(p.topping, p.amount)
% python script.py ニンニク マシ 野菜 マシマシ カラ メ
ZeroOrMore
を使って、jiro_item
の1個以上の繰り返しを表すsearch_string
で文字列をパースして、マッチするものを全部見つける
pyparsingで作る二郎系ラーメン
% uv run script.py Ramen(toppings=[Topping(item='ニンニク', amount=1), Topping(item='野菜', amount=2), Topping(item='カラ', amount=1)])
終わりに
PHPカンファレンス小田原2024のめもり〜☆さんのトークにインスパイアされ、pyparsingを使って二郎系ラーメンのコールをパースしてみました。
私がまず浮かぶ方法は正規表現だったのですが、こんな方法があるんですね〜5。
なお、pyparsing自体は初見で知らないことが多いので、もっとうまく書ける余地はある気がしています。
触ってみてpyparsingは文法を定義している感がありました。
例:https://pyparsing-docs.readthedocs.io/en/latest/pyparsing.html#pyparsing.indentedBlock
今回定義したのは、二郎系ラーメンのコールの文法だったのです!
最後に、めもりーさん、あすみさん、刺激的なアウトプットをありがとうございます!
P.S. 発売おめでとうございます!
本日発売されました!!!! https://t.co/bTmhX50JYL
— めもりー (@m3m0r7) 2024年12月4日