Reguläre Ausdrücke können nicht verwendet werden, um sehr komplexe Zeichenketten mit Grammatik zu behandeln, wie z. B. Quellcode von Programmiersprachen, Anmerkungen, die zusammengesetzte Datentypen für Methoden beschreiben, mathematische Ausdrücke, Berechnungen, Formeln und mehr. Der Grund dafür ist, dass es sich um so komplexe Zeichenfolgen handelt, die viele Regeln enthalten, dass wir sie einfach in kleineren Stücken verarbeiten müssen.
Wenn ein Computer zum Beispiel PHP-Quellcode verarbeitet, zerlegt er ihn zunächst in viele kleine Teile, die ihre eigene Bedeutung haben. Diese Teile werden "Token" genannt und sind die kleinsten in sich geschlossenen Bausteine der Sprache.
Das Prinzip der String-/Sprachverarbeitung ist in mehrere Phasen unterteilt:
Ein weiterer großer Vorteil dieses Ansatzes ist, dass wir die Position des Tokens in der Zeichenkette kennen (sowohl die Zeile als auch das spezifische Start- und Endzeichen des Tokens), während wir durch das Token gehen, so dass wir den Ort des Problems genau bestimmen können, wenn eine Ausnahme ausgelöst wird.
Stellen Sie sich zum Beispiel vor, Sie implementieren einen Algorithmus zur Lösung eines mathematischen Beispiels. In der Mathematik gibt es viele Regeln, z. B. Prioritäten der Operatoren, Klammern, Funktionsaufrufe usw.
Wenn wir die Eingabezeichenfolge in elementare Token aufteilen können, können wir auf einer ganz anderen Ebene mit ihr arbeiten. So können wir beispielsweise leicht einzelne Klammern finden, Token von der ersten bis zur letzten Klammer subtrahieren, einen Unterausdruck zur Verarbeitung an eine rekursive Funktion übergeben usw.
Die Tokenisierung ermöglicht es uns, selbst komplexe Parsing-Probleme sehr elegant zu lösen.
Wir brauchen nicht so viel Wissen, um unseren eigenen Tokenizer zu schreiben. Im Grunde müssen wir nur das Prinzip der regulären Ausdrücke kennen und ein kleines Parsing-Objekt schreiben.
Für die Zwecke dieses Artikels habe ich eine Basisversion eines Tokenizers auf der Grundlage des Latte (Nette) Tokenizers vorbereitet. Der Autor der ursprünglichen Implementierung ist David Grudl, dem ich für eine so einfache Funktion danken möchte, die alle Probleme für Sie löst.
final class Token{public string $value;public int $offset;public string $type;}final class Tokenizer{public const TokenTypes = ['Array' => 'Array','<' => '\<','>' => '\>','{' => '\{','}' => '\}','oder' => '\|','Liste' => '\[\]','Typ' => '[a-zA-Z]+','Raum' => '\s+','Komma' => ',','andere' => '.+?',];/*** @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('Unerwarteter "%s" in Zeile %s, Spalte %s.', $token, $line, $col));}return $tokens;}}
Dieser Tokenizer kann z. B. eine solche komplexe Zeichenkette analysieren (das Format ist absichtlich mit Leerzeichen durchsetzt, um zu zeigen, dass der Tokenizer eine große Bandbreite von Fällen verarbeiten kann):
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: ... | de