
2026/10/18 17:19
パースコンビネータ
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
テキストは、機能プログラミングの概念(例:
Parser<T>)を用いてカスタムパーサーがどのようにルールとして機能し、生の文字列から特定の値を抽出しながら未使用の残りを返すか説明しています。具体的な例には以下が含まれます:
がpInteger
を解析して"10 20 30"
と残り10
を返す。" 20 30"- シーケンスパーサー
がpSeq(pHello, pIgnoreWhitespace, pInteger)
を処理し、空の残りとともにタプル"Hello 100"
を返し、その後["Hello", null, 100]
によって構造化オブジェクトpGreeting
にラップされる。{ greeting: "Hello", who: 100 }
を用いた連続した数値解析で、入力としてpSeq(pNumber, pSemicolon)
などの例を示す。"10;20;30;"
ガイドではさらに、ネットワークの
ping コマンド出力を解析して目標 IP アドレスと詳細な統計情報(例:送信されたパケット 8 つ、受信 7 つ(1.1.1.1 に対して)、平均 RTT 115.880 ms などの RTT メトリック)を抽出し、これらを header および packets アレイを含む構造化オブジェクトに整理する方法を実際の用途によって示しています。Fold(list.reduce を介して)などの関数操作は、解析された要素を集約する例で説明され、Unfold は文字列を要素アレイに戻す逆操作として提示されています。これらのパターンは合わせて、ログ分析から API ハンドリングにいたる幅広いタスクにおいて、生テキストストリームを複雑で実行可能なデータ構造に変換するための信頼性の高い手動不要な方法を 제공합니다。本文
TypeScript パースャー実装と ICMP Ping 結果の解析
基本構造とパーサー型
-
入力文字列の解析
- 文字列
は、以下のようなオブジェクトとして解析されます。"Hello, world!" - プロパティ
:greeting"Hello" - プロパティ
:who"world"
{ greeting: "Hello", who: "world" } - 文字列
-
パーサー型定義
は、入力文字列からParser<T>
のタプルを返す関数を表します。[T, 残りの文字列]
type Parser<T> = (input: string) => [T, string] -
個別のパーサー例
:pInt
を解析し、数字"10 20 30"
と残り10
を返します。" 20 30"- 実行例:
pHello("Hello") // ["Hello", " 100"] pIgnoreWhitespace("null") // [null, "100"] pInt("100") // [100, ""]
パースャーの連鎖処理
-
順次適用による解析
→pHello
→pIgnoreWhitespace
の順に適用し、前回の残りを次の入力として渡します。pInteger- 各ステップの結果:
:pHello
と"Hello"
を返す。" 100"
: 空白を除去した空文字列pIgnoreWhitespace
と""
を返す。"100"
: 数字pInt
と空文字列100
を返す。""
-
実装上の注意点
- 型定義において、戻り値として null や多次元配列などを適切に扱う必要があります。
type pHello = "Hello 100" type pHelloResult = ["Hello", null, 100] -
結合関数
pSeq- 複数のパーサーを順列(シーケンス)として結合する汎用関数です。
const pSeq = <T, U>(first: Parser<T>, second: Parser<U>): Parser<[T, U]> => { // 実装ロジック } -
結合されたパーサーの使用例
、pHello
、pIgnoreWhitespace
をpInt
で結合します。pSeq- 結果として、タプル
の型を持つ新しいパーサーが得られます。[string, null, number]
const pHello100 = pSeq(pHello, pIgnoreWhitespace, pInt); const result = pHello100("Hello 100"); // result: ["Hello", null, 100]
オブジェクト指向な解析への拡張
- 対象オブジェクトの型定義
を使用すると、文字列からpGreeting
のオブジェクトを取得できます。{ greeting: string; who: number }- 戻り値:
{ greeting: "Hello", who: 100 }
リカursive パースャーの実装例
-
半角数字とセミコールの繰り返しパターン
を使用して、pSeq(pInt, pChar(';'))
のようなパターンを解析します。"10;20;30;"- この関数を再帰的に呼び出すことで、リストとして結果を得ることができます。
-
処理の過程
- 最初の呼び出し:
と"10;"
を返す。"20;30;" - 次の呼び出し:
と"20;"
を返す。"30;" - 最後の呼び出し:
と空文字列"30;"
を返す。""
- 最初の呼び出し:
-
実装コード
const pSeqNumberSemicolon = pSeq(pInt, pChar(';')); pSeqNumberSemicolon("10;20;30;") // [ // ["10;", "20;30;"], // ["20;", "30;"], // ["30;", ""] // ]
ICMP Ping 結果のデータ構造
Ping 実行結果(対象:
1.1.1.1)の詳細ログと解析済みデータです。
ログ出力
- PING 1.1.1.1 (1.1.1.1) 56(84) バイトのデータです。
- icmp_seq=1: ttl=52, time=389 ms
- icmp_seq=2: ttl=52, time=68.7 ms
- icmp_seq=3: ttl=52, time=47.1 ms
- icmp_seq=4: ttl=52, time=48.6 ms
- icmp_seq=5: ttl=52, time=85.8 ms
- icmp_seq=6: ttl=52, time=84.8 ms
- icmp_seq=7: ttl=52, time=87.4 ms
統計情報
- 送信: 8 パケット
- 受信: 7 パケット
- 損失率: 12.5%
- 所要時間: 7008ms
- rtt (最小/平均/最大/標準偏差): 47.129 / 115.880 / 388.750 / 112.515 ms
JSON データモデル
解析された結果をオブジェクトとして表現した例です。
{ header: { targetIp: "1.1.1.1", resolvedIp: "1.1.1.1", icmpPayloadSize: 56, totalPacketSize: 84 }, packets: [ { byteCount: 64, from: "1.1.1.1", seq: 1, ttl: 52, time: 389 }, { byteCount: 64, from: "1.1.1.1", seq: 2, ttl: 52, time: 68.7 }, { byteCount: 64, from: "1.1.1.1", seq: 3, ttl: 52, time: 47.1 }, { byteCount: 64, from: "1.1.1.1", seq: 4, ttl: 52, time: 48.6 }, { byteCount: 64, from: "1.1.1.1", seq: 5, ttl: 52, time: 85.8 }, { byteCount: 64, from: "1.1.1.1", seq: 6, ttl: 52, time: 84.8 }, { byteCount: 64, from: "1.1.1.1", seq: 7, ttl: 52, time: 87.4 }, ], statistics: { packetsTransmitted: 8, packetsReceived: 7, packetLoss: 12.5, time: 7008, rtt: { min: 47.129, avg: 115.88, max: 388.75, mdev: 112.515 }, }, }
ユーティリティ関数
-
配列の畳み込み (
)fold- リストを関数で統合して単一値に還元します。
- 例:
を["Hello", " ", 100]
に結合する処理。"Hello 100"
const fold = (list: number[], reduceFunction: (acc: number, n: number) => number) => { return list.reduce(reduceFunction); } -
配列の展開 (
)unfold- パースャーの結果を元の構造(タプルやオブジェクト)に再構築します。
- 例:
を"Hello 100"
に分解する処理。["Hello", " ", 100]
const unfold = (pSeq: Parser<any>, input: string): any[] => { const result = pSeq(input); // 要素に展開するロジック return result; }