概要
- Parser型 は、文字列を解析して値と残りの文字列を返す関数型
- pSeq や pMap などの関数で複雑なパーサーを合成可能
- 解析の流れは「残り文字列」を次のパーサーに順次渡す方式
- Fold や Unfold の考え方で、値の集約や展開も表現
- pingコマンド出力 のような複雑なテキストも、パーサーで構造化可能
Parser型とパーサー合成の基本
- Parser<T>型 は、
(input: string) => [T, string]という関数型- 入力文字列を受け取り、 T型の値 と 残り文字列 のペアを返却
- 例:
pInteger("10 20 30")→[10, " 20 30"]- "10"を数値として抽出し、残りを返す
- パーサーの合成 は、「残り文字列」を次のパーサーに渡すことで実現
- 例:
pHello→pIgnoreWhitespace→pIntegerの順で解析- "Hello 100" →
["Hello", " 100"]→[" ", "100"]→[100, ""]
- "Hello 100" →
- 例:
- pSeq 関数で複数パーサーを直列合成
- 例:
pSeq(pHello, pIgnoreWhitespace, pInteger)は[string, null, number]のタプルを返す const pHello100 = pSeq(...)のように合成可能
- 例:
- pMap でパース結果を任意のオブジェクト型などに変換
- 例:
pGreeting["Hello 100["Hello", null, 100]{ greeting: "Hello", who: 100 }pMap", ""]
- 例:
パーサー実行例と流れ
"Hello 100"をpHello100で解析pHello100("Hello 100")→["Hello", null, 100], ""
"10;20;30;"をpSeq(pNumber, pSemicolon)で逐次解析- 1回目:
"10;[10, ";"]", "20;30;" - 2回目:
"20;[20, ";"]", "30;" - 3回目:
"30;[30, ";"]", ""
- 1回目:
- 各パーサーが 残り文字列 を次のパーサーに渡し、最終的に全体を解析
Fold・Unfoldによる値の集約と展開
- Fold: リストの値を集約
- 例:
list.reduce((acc, n) => acc + n) ["Hello", " ", 100]→"Hello 100"
- 例:
- Unfold: 値を構造化データに展開
- 例:
pSeq(...)("Hello 100")→["Hello", " ", 100]
- 例:
pingコマンド出力のパース例
- pingコマンドの出力をパーサーで解析し、構造化データに変換
header、packets、statisticsなどのオブジェクトとして抽出
- 例:
header: { targetIp: "1.1.1.1", ... }packets: [{ byteCount: 64, from: "1.1.1.1", seq: 1, ... }, ...]statistics: { packetsTransmitted: 8, packetsReceived: 7, ... }
まとめ
- Parser型 を使うことで、文字列から構造化データへの変換を柔軟かつ再利用可能に設計
- パーサー合成 ・ マッピング ・ Fold/Unfold の発想で、複雑なテキスト解析やデータ変換にも対応可能