Ich habe einen einfachen Phrasenanalysator zur Verwendung in meinem eigenen Java-Konsolenprogramm erstellt. Für die Phrasenanalyse ist es einfacher, verschiedene Bibliotheken zu verwenden. Da sie jedoch am Arbeitsplatz verwendet werden, an dem das Herunterladen von externen Websites verboten ist, habe ich sie mit meiner Java8-Funktion von Grund auf neu erstellt.
Beim Erstellen verweise ich auf Implementieren einer einfachen Phrasenanalyse in Java.
Zunächst müssen die Anforderungen für den Phrasenanalysator erstellt werden.
Implementieren Sie nur Java 8-Funktionen.
Da es nicht für die Syntaxanalyse einer vollwertigen Programmiersprache verwendet wird, wird nur eine einfache Phrasenanalyse (etwa auf halber Strecke zwischen der Windows-Befehlszeile und der Unix-Shell) durchgeführt.
Es wurden nur Ein-Buchstaben-Symbole und Zeichenfolgen implementiert, die Token sein können.
Bitte beachten Sie, dass es sich um einen Oleore-Stil handelt, der von der allgemeinen Beschreibung von Java abweicht. Es gibt die folgenden Gründe.
Token.java
package console;
final class Token {
enum Kinds {
Unknown,
Empty,
Ampersand, // "&"
Assign, // "="
Plus, // "+"
Minus, // "-"
Asterisk, // "*"
Slash, // "/"
Separator, // ","
LeftParenthesis, // "("
RightParenthesis, // ")"
LeftCurlyBracket, // "{"
RightCurlyBracket, // "}"
LeftSquareBracket, // "["
RightSquareBracket, // "]"
Colon, // ":"
BackSlash, // "\"
DoubleQuote, // """
SingleQuote, // "'"
String,
}
static Token create(char c) {
final String s = Character.toString(c);
switch(c) {
case '&' : return new Token(s, Kinds.Ampersand );
case '=' : return new Token(s, Kinds.Assign );
case '+' : return new Token(s, Kinds.Plus );
case '-' : return new Token(s, Kinds.Minus );
case '*' : return new Token(s, Kinds.Asterisk );
case '/' : return new Token(s, Kinds.Slash );
case ',' : // down through
case ' ' : return new Token(s, Kinds.Separator );
case '(' : return new Token(s, Kinds.LeftParenthesis );
case ')' : return new Token(s, Kinds.RightParenthesis );
case '{' : return new Token(s, Kinds.LeftCurlyBracket );
case '}' : return new Token(s, Kinds.RightCurlyBracket );
case '[' : return new Token(s, Kinds.LeftSquareBracket );
case ']' : return new Token(s, Kinds.RightSquareBracket);
case ':' : return new Token(s, Kinds.Colon );
case '\\' : return new Token(s, Kinds.BackSlash );
case '\"' : return new Token(s, Kinds.DoubleQuote );
case '\'' : return new Token(s, Kinds.SingleQuote );
}
return unknown_;
}
static Token create(String s) {
if ( s == null || s.trim().isEmpty() ) { return empty_; }
//
if ( s.length() == 1 ) {
Token t = Token.create(s.charAt(0));
if ( t.kind() != Kinds.Unknown ) { return t; }
}
return new Token(s.trim(), Kinds.String);
}
final String value() { return value_; }
final Kinds kind() { return kind_; }
final String kindName() { return kind_.toString(); }
public String toString() {
return String.format("[%-14s: \"%s\"]", kindName(), value());
}
private Token(String s, Kinds k) {
kind_ = k;
value_ = s;
}
private static Token empty_ = new Token("", Kinds.Empty); // empty token
private static Token unknown_ = new Token("**Unknown**", Kinds.Unknown); // unknown token
private final Kinds kind_;
private final String value_;
}
Token-Klasse Zuerst wird der vollständige Text der grundlegenden Token-Klasse angezeigt. oder Leerzeichen Was tun, wenn ein Symbol versehentlich als Zeichenfolge übergeben wird? Es handelt sich um eine kurze Quelle, daher halte ich es für unnötig, dies zu erklären, aber ~~ ich werde es vergessen ~~ Ich werde jeden Teil der Quelle kurz erklären.
Registrieren Sie den Tokentyp im Aufzählungstyp. Dies ist eine Markierung, die in späteren Syntaxanalysen verwendet wird, sodass die Zeichen und Elemente nicht unbedingt eine Eins-zu-Eins-Entsprechung aufweisen müssen.
enum Kinds {
Unknown,
Empty,
Ampersand, // "&"
Assign, // "="
Plus, // "+"
//Unterwegs weggelassen
String,
}
Verwenden Sie die Factory-Methode, um ein Token für das Symbol zu erstellen. Vom Phrasenanalysator wird der gelesene Zeichentyp (Zeichentyp) direkt übergeben, um ihn von der Zeichenfolgen-Token-Factory zu trennen. Wenn ein Zeichen übergeben wird, das von der switch-Anweisung nicht abgefangen werden kann, wird das zuvor erstellte unbekannte Token zurückgegeben. Da Token ein unveränderliches Objekt ist, kann sein Inhalt nicht geändert werden. Daher können Sie die vorab erstellten Objekte sicher wiederverwenden. Wie oben erwähnt, gibt es keine Eins-zu-Eins-Entsprechung zwischen Aufzählungstypen und Zeichen: Kommas und Leerzeichen. (Beide werden als Kinds.Separator erstellt.)
static Token create(char c) {
final String s = Character.toString(c);
switch(c) {
case '&' : return new Token(s, Kinds.Ampersand );
case '=' : return new Token(s, Kinds.Assign );
case '+' : return new Token(s, Kinds.Plus );
case '-' : return new Token(s, Kinds.Minus );
case '*' : return new Token(s, Kinds.Asterisk );
case '/' : return new Token(s, Kinds.Slash );
case ',' : // down through
case ' ' : return new Token(s, Kinds.Separator );
case '(' : return new Token(s, Kinds.LeftParenthesis );
case ')' : return new Token(s, Kinds.RightParenthesis );
case '{' : return new Token(s, Kinds.LeftCurlyBracket );
case '}' : return new Token(s, Kinds.RightCurlyBracket );
case '[' : return new Token(s, Kinds.LeftSquareBracket );
case ']' : return new Token(s, Kinds.RightSquareBracket);
case ':' : return new Token(s, Kinds.Colon );
case '\\' : return new Token(s, Kinds.BackSlash );
case '\"' : return new Token(s, Kinds.DoubleQuote );
case '\'' : return new Token(s, Kinds.SingleQuote );
}
return unknown_;
}
private static Token unknown_ = new Token("**Unknown**", Kinds.Unknown); // unknown token
Als nächstes folgt die Factory-Methode für String-Token. Dies ist ein Phrasenanalysator, der bis zum Ende des Strings liest und ihn dann an die Factory weiterleitet. Im Gegensatz zum Symbol-Token ist er also überladen, um ein String-Argument anzunehmen. Wenn eine leere Zeichenfolge (einschließlich einer Zeichenfolge mit nur Leerzeichen) oder null übergeben wird, wird das zuvor erstellte leere Token zurückgegeben. Dies vermeidet zusätzliche Fehlerprüfungen beim Anrufer. Das Ein-Buchstaben-Symbol soll im Zeichen-Typ übergeben werden. Wenn die übergebene Zeichenfolge jedoch nur als Zeichen besteht, wird die Fabrik des Symbol-Tokens aufgerufen, wenn sie als Zeichenfolge übergeben wird. .. Bei einer Zeichenfolge, die von der Symbol-Token-Factory nicht unterstützt werden kann, wird ein unbekanntes Token zurückgegeben. Erstellen Sie es in diesem Fall erneut als Zeichenfolgen-Token.
Obwohl die Erklärung verwechselt ist, wird der Konstruktor außerdem als privat deklariert, sodass das Objekt nur über die Factory-Methode erstellt wird.
static Token create(String s) {
if ( s == null || s.trim().isEmpty() ) { return empty_; }
//Was tun, wenn Sie einen Fehler machen und das Symbol als Zeichenfolge übergeben wird?
if ( s.length() == 1 ) {
Token t = Token.create(s.charAt(0));
if ( t.kind() != Kinds.Unknown ) { return t; }
}
return new Token(s.trim(), Kinds.String);
}
private Token(String s, Kinds k) {
kind_ = k;
value_ = s;
}
private static Token empty_ = new Token("", Kinds.Empty); // empty token
Es gibt zwei Arten von Token: einen aufgezählten Elementtyp und eine Zeichenfolgendarstellung des Elements ("kind" wird für kinds.Plus zurückgegeben).
final String value() { return value_; }
final Kinds kind() { return kind_; }
final String kindName() { return kind_.toString(); }
public String toString() {
return String.format("[%-14s: \"%s\"]", kindName(), value());
}
Dies ist das Ende der Erklärung der Token-Klasse.
Eigentlich habe ich die Anzahl der Symbol-Token aus dem tatsächlich erstellten Programm erhöht, aber selbst auf dieser Ebene fand ich es ärgerlich, den Aufzählungstyp und die Factory-Switch-Anweisung zu synchronisieren. Ich habe darüber nachgedacht, diesen Teil für allgemeine Zwecke umzugestalten, aber ich habe mich entschlossen, auf diese Zeit zu verzichten, da es aus Zeitgründen schwierig ist, die Anzahl der Klassen zu erhöhen.
Das nächste Mal wird es der Hauptteil des Phrasenanalysators sein.
→ Erstellen einer Phrasenanalyse mit Java 8 (Teil 2) Gepostet.
Recommended Posts