正規表現より優れたパーサコンビネータという選択肢
Parser Combinators

テキストを構造化データに変換するパースは、正規表現では複雑な処理で破綻し、tree-sitterでは大げさすぎる。その中間を埋めるのがパーサコンビネータだ。入力文字列を「値と残りの文字列のタプル」に変換する小さな関数を組み合わせ、順に適用していくことで、PINGの出力のような複雑なテキストもオブジェクトへと変換できる。
正規表現は複雑な処理ではすぐに散らかり、tree-sitterはしばしば大げさすぎる。その中間こそ、パーサコンビネータがうってつけだ。
HNでの議論
77- ArneCode
アニメーションはとても気に入っています。何が起きているのか直感的に理解できますね!
パーサコンビネータの欠点として、たとえばパーサジェネレータライブラリ(別の文法ファイルからパーサを生成するもの)と比べると、マッピングやアンラップのコードをたくさん書かなければならない点があると思います。私の意見では、これがパーサを読みにくくしています。
これを改善する試みとして、Rustでパーサコンビネータライブラリを開発しています。
2つの追加コンビネータ(captureとbind)を加えていて、これらはパーサの結果をバケツ(bind)に保存し、後でそのバケツに保存された値を使って結果を構築(capture)できます。
これによりアンラップ/マッピングのコードを排除し、文法と結果の構築を分離できます。
お時間があれば、これについてフィードバックをいただけるととても嬉しいです!
こちらにあります: https://github.com/ArneCode/marser
- marginalia_nu
なぜこれを1ページにまとめられないのか理解できません。スライドショー形式だと新しい情報が出てきたときに前の「章」を参照するのがとても難しくなります。検索もできません。
奇妙な美的理由のために、紙媒体の制約をデジタルメディアには存在しないのに不要に再導入しているように思えます。
- akst
これは本当にクールなウェブサイトだと思いますし、このトピックも大好きです。
ただ、小さい画面でこのページをテストしてみたほうがいいかもしれません。関心のあるコンテンツに使える画面領域が非常に限られていて、右上の半分は余白が多く、スクロール可能なコンテンツは実質的に利用可能な画面スペースの1/3しかなく、左側もまた1/3を占めている感じです。
あなたのウェブサイトはあなたのビジョンですし、UIで何か違うことを試みているのは理解していますし尊敬します。でも、ここでの目標があなたのアイデアを伝えることなら、読者としてはコンテンツにもっと画面スペースがあるとありがたいです。この特定の投稿を見るためにリンクをクリックしたとき、あなたの他の投稿には興味がありません(少なくとも、わざわざ読みに来た投稿を読み終えるまでは)。
ちなみに、今はMacBook Airを使っています。
- BoppreH
Pythonを使っていて、問題が単一の正規表現には大きすぎるが、記事のような本格的なパーサには小さすぎる場合、組み込みのre.Scanner[0]をお勧めします。これは`re`モジュールにある正規表現ベースのトークナイザ[1](つまり再帰的なパースはしない)で、なぜか公式ドキュメントには完全に欠けています。
各トークンタイプのパターンと、各マッチを処理する関数を渡すと、処理済みトークンのリストが返ってきます。
重要なのは、リストを1パスで処理し、マッチが連続していることを保証する点です。キャプチャグループ付きの素朴な`re.findall`では、マッチしない文字は無視されてしまいます。また、実行中のスキャナへの参照も得られるので、エラー報告のためにマッチの位置を記録できます。
import re
# スキャナを初期化します。
scanner = re.Scanner([
(r"\d+", lambda scanner, token: ('COUNT', int(token))),
(r"\w+", lambda scanner, token: ('ANIMAL', token.removesuffix('s'))),
(r"[,. ]", None), # None -> トークンをスキップ。
])
# サンプル文字列をスキャンします。
results, remainder = scanner.scan("45 pigeons, 23 cows, 11 spiders.")
# 全体をパースしたことを確認します。
assert not remainder
print(results)
# [('COUNT', 45),
# ('ANIMAL', 'pigeon'),
# ('COUNT', 23),
# ('ANIMAL', 'cow'),
# ('COUNT', 11),
# ('ANIMAL', 'spider')]
[0]: https://stackoverflow.com/a/693818/252218
[1]: https://en.wikipedia.org/wiki/Lexical_analysis#Tokenization
- boomlinde
最初のアドレスはホスト名にもなり得るので、IPアドレスとしてパースすべきではないでしょう。些細な指摘に見えるかもしれませんが、複数の種類の構文のどちらかを期待する場合にどうするかを示す機会になります。
本文に割り当てられた領域が限られているため、記事はやや読みにくかったです。章が短いのに何ページもスクロールしなければなりませんでした。