プログラミング言語のソースコード、メソッドの複合データ型を記述するアノテーション、数式、計算、計算式など、文法を持つ非常に複雑な文字列は正規表現では扱えません。なぜなら、これらは多くの規則を含む複雑な文字列形式であるため、単純に小さな塊で処理しなければならないからである。
例えば、コンピュータがPHPのソースコードを処理する場合、まずソースコードをそれぞれの意味を持つ多くの小さなパーツに分解します。これらの部品は「トークン」と呼ばれ、言語の最小の自己充足的な構成単位を表しています。
文字列・言語処理の原理は、いくつかのフェーズに分けられる。
この方法のもう一つの大きな利点は、トークンを通過する際に、文字列中のトークンの位置(行と特定のトークン開始・終了文字の両方)がわかるので、例外が発生した場合に問題の場所に正確に対処できることです。
例えば、数学の例題を解くためにアルゴリズムを実装することを想像してください。数学には、演算子の優先順位、括弧、関数の呼び出しなど、いろいろなルールがあります。
入力文字列を要素トークンに分割できれば、まったく別の次元で作業ができるようになる。例えば、個々の括弧を見つける、最初の括弧から最後の括弧までトークンを引く、部分式を再帰的な関数に渡して処理する、といったことが簡単にできる。
トークン化によって、複雑な構文解析の問題でも非常にエレガントに解決することができるようになりました。
独自のトークナイザーを書くには、そこまでの知識は必要ないのです。基本的には、正規表現の原理を知って、小さな解析オブジェクトを書けばよいのです。
今回は、この記事のために、Latte(ネット)トークナイザーをベースにした基本版を用意しました。オリジナルの実装の作者はDavid Grudlで、このようなシンプルな関数ですべての問題を解決してくれることに感謝したい。
final class Token{public string $value;public int $offset;public string $type;}final class Tokenizer{public const TokenTypes = ['勢揃い' => '勢揃い','<' => '\<','>' => '\>','{' => '\{','}' => '\}','または' => '\|','リスト' => '\[\]','タイプ' => '[a-zA-Z]+','空間' => '\s+','カンマ' => ',','こと' => '.+?',];/*** @return array<int, Token>.*/public static function tokenize(string $haystack): array{$re = '~(' . implode(')|(', self::TokenTypes) . ')~A';$types = array_keys(self::TokenTypes);preg_match_all($re, $haystack, $tokenMatch, PREG_SET_ORDER);$len = 0;$count = count($types);$tokens = [];foreach ($tokenMatch as $match) {$type = null;for ($i = 1; $i <= $count; $i++) {if (isset($match[$i]) === false) {break;}if ($match[$i] !== '') {$type = $types[$i - 1];break;}}$token = new Token;$token->value = $match[0];$token->offset = $len;$token->type = (string) $type;$tokens[] = $token;$len += strlen($match[0]);}if ($len !== strlen($haystack)) {$text = substr($haystack, 0, $len);$line = substr_count($text, "\n") + 1;$col = $len - strrpos("\n" . $text, "\n") + 1;$token = str_replace("\n", '\n', substr($haystack, $len, 10));throw new \LogicException(sprintf('行 %s、列 %s で予期しない "%s" が発生しました。', $token, $line, $col));}return $tokens;}}
このトークナイザーは、たとえばこのような複雑な文字列を解析することができます(この書式は、このトークナイザーが広い範囲のケースを処理できることを示すために、意図的にスペースを散りばめています)。
array<int, array<bool, array<string, float> >
Jan Barášek Více o autorovi
Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.
Rád vám pomůžu:
Články píše Jan Barášek © 2009-2024 | Kontakt | Mapa webu
Status | Aktualizováno: ... | ja