Pythonの構文解析ライブラリLarkを使って遊んでみました

katsura

概要

こんにちは、トライコーンでシステムの開発・運用を行っている katsura です。
最近、日曜プログラミングで Python をさわる機会があったのですが、その中で見つけた構文解析ライブラリ Lark が面白かったので紹介しようと思います。

構文解析とは

構文解析といっても馴染みがないかもしれませんが、構文解析器の英訳であるパーサー(parser)という言葉であれば、ピンとくる人も多いでしょう。
構文解析とは入力されたテキストを分析することであり、構文解析器は入力されたテキストを分析するプログラムのことです。
例えば、Javascript で json をプログラム内で使うとき、JSON.parse() という関数を利用して json 文字列をオブジェクトへ変換しますが、この parse は構文解析のことです。

Lark とは

今回紹介する Lark とは、Python で利用できる構文解析のライブラリです。
EBNFをベースとした記法で文法を定義すると、その文法に従ってテキストを解析してくれるツールです。
例えば、json のパーサー相当の処理を自分で書く、なんてことも出来たりします。

構文解析ライブラリには様々なものがありますが、今回紹介する Lark は比較的最近開発されたライブラリであり、表現の自由度が高く、使いやすいのが特徴です。

Lark の使い方

では、早速Larkの使い方を紹介していきます。

Lark は pip でインストール可能です。

Shell

Lark を使う際、まず、文法を定義する必要があります。

.lark という拡張子の文法ファイルで作成し定義すると、VS Code や vim の Larkのプラグインがシンタックスハイライトしてくれるので便利です。

今回は、わかりやすいサンプルとして加算・乗算のテキストを解析し、計算結果を返すような構文解析器を作成しました。

Plain Text
calc_grammar.lark

Lark の記法は、左側に定義、右側にその内容を書くような形式です。

Lark の記法は EBNF をベースにしつつ、正規表現も利用可能なので正規表現に慣れている人でも書きやすいかと思います

Python
sample1.py

calc_grammar.lark で定義した文法を元に、それぞれの文法で実際に行う作業を定義したのが CalcTransformer クラスとなります。

expr や term のように、文法ファイルで定義した文法に対応したメソッドを用意することで、加算・乗算の文法が現れたときに実行する内容を定義できます。

そして、これを実行すると以下のように計算結果が出てくるようになりました。

Shell

Lark の活用法

ここまで、構文解析ライブラリ Lark の紹介をしてきましたが、これを読んで「これって何の役に立つの?」と思った人もいるかもしれません。

構文解析という技術は、最初に紹介した json のパーサーや、プログラミング言語のコンパイラ・インタプリタを作成するのに役立つ技術です。
それゆえ、構文解析のライブラリを紹介する記事では、電卓を作るサンプルや独自のプログラミング言語を作成するサンプルが紹介されるケースが多いです。
しかし、業務や趣味のプログラミングで電卓や自作の言語処理系を作るケースはあまりないので、これだけだと、構文解析ライブラリの使いみちのイメージがつかない人が多いでしょうし、自分もそう感じていました。

そこで、次は、少し役立ちそうなシチュエーションとして、メールアドレスのバリデーションチェックに構文解析を利用する方法を紹介しようと思います。

Lark を使ったメールアドレス判定

メールアドレスの定義は、RFC5321 や RFC5322 といった国際規格で定められています。
今回は、RFC5322 内で定義されているメールアドレスの文法定義(addr-spec)を元にLarkの文法ファイルを作成しました。

なお、メールアドレスの正式な定義に準拠しようとすると複雑になってしまいますので、今回はよく使われるメールアドレスに対応した簡易的なチェックとしています※1

Plain Text
mail_address_grammar.lark

今回はメールアドレスかどうかの判定を行いたいので、対象の文字列がメールアドレスであれば address、合致しなければ ng が呼ばれるようにしました。
python 側では、address が見つかれば True、ng が見つかれば False を返すようにしています。

Python
sample2.py

ちなみに、これと同じ判定を正規表現で行おうとすると以下のような表記となります。

Plain Text

正規表現で判定するよりも Lark の文法のほうがボリュームが多く、慣れていないと特に時間がかかるかもしれません。

一方で、Lark 文法ファイルのほうが、メールアドレスでどのような文字列が使われているかわかりやすいというメリットがあります。
また、一度作成したメールアドレスの文法定義は、別の文法内で再利用が可能なのです。
例えば、メールサーバのログを解析するパーサーを書く際に、今回定義した address_spec を再利用するということも可能です。

まとめ

今回は、構文解析というあまり普段利用しない技術について紹介しました。
あまり出番の多い技術ではありませんが、特定のシチュエーションでは大いに活躍できる可能性を秘めた技術です。

業務や趣味で、複雑なテキストを解析しないといけなくなったときは、ぜひ構文解析ライブラリ Lark のことを思い出してもらえればと思います。


※1.RFC5322 では、ダブルクォートで囲むようなメールアドレス形式も定義されていますが、あまり使われない表記なので今回は省略しています。また、メールアドレスのローカルパート・ドメインパートについてはそれぞれ文字数制限がありますが、こちらも今回の記事ではチェックを省略しています。

katsura

Posted by katsura