Création d'une analyse de phrase dans Java 8 (partie 1)

introduction

J'ai créé un analyseur de phrases simple à utiliser dans mon propre programme de console Java. Pour l'analyse de phrases, il est plus facile d'utiliser diverses bibliothèques, mais comme il est utilisé sur le lieu de travail où le téléchargement à partir de sites externes est interdit, je l'ai créé à partir de zéro en utilisant la fonction Java8 que j'ai.

En le créant, je me réfère à Implémentation d'une analyse de phrase simple en Java.

point important

Exigences

Tout d'abord, les exigences pour l'analyseur de phrases à créer.

--Implémenter uniquement les fonctions Java 8.

Style de programme

Veuillez noter qu'il s'agit d'un style oléore qui s'écarte de la description générale de Java. Il y a les raisons suivantes.

Classe de jeton

Tout d'abord, je vais vous montrer le texte complet de la classe de jeton de base.

Token.java


package console;

final class Token {
    enum Kinds {
        Unknown,
        Empty,
        Ampersand,          // "&"
        Assign,             // "="
        Plus,               // "+"
        Minus,              // "-"
        Asterisk,           // "*"
        Slash,              // "/"
        Separator,          // ","ou caractère vide
        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_; }
        //Que faire si vous faites une erreur et que le symbole est passé sous forme de chaîne
        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_;
}

Commentaire

C'est une source courte, donc je ne pense pas qu'il soit nécessaire de l'expliquer, mais ~~ Je l'oublierai ~~ Je vais expliquer brièvement chaque partie de la source.

Type de jeton

Enregistrez le type de jeton dans le type d'énumération. Il s'agit d'un marqueur qui sera utilisé dans une analyse syntaxique ultérieure, de sorte que les caractères et les éléments ne doivent pas nécessairement avoir une correspondance biunivoque.

    enum Kinds {
        Unknown,
        Empty,
        Ampersand,          // "&"
        Assign,             // "="
        Plus,               // "+"
        //Omis en chemin
        String,
    }

Méthode d'usine

Utilisez la méthode de fabrique pour créer un jeton pour le symbole. À partir de l'analyseur de phrases, le type de caractère lu (type char) est transmis directement pour le séparer de la fabrique de jetons de chaîne de caractères. Si un caractère qui ne peut pas être intercepté par l'instruction switch est passé, le jeton inconnu créé à l'avance est renvoyé. Étant donné que Token est un objet immuable, son contenu ne peut pas être modifié. Par conséquent, vous pouvez réutiliser les objets pré-créés en toute confiance. Comme mentionné ci-dessus, il n'y a pas de correspondance univoque entre les types d'énumération et les caractères: virgules et espaces. (Les deux sont créés en tant que Kinds.Separator)

    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

Vient ensuite la méthode de fabrique de jetons de chaîne. Il s'agit d'un analyseur de phrases qui lit jusqu'à la fin de la chaîne, puis la transmet à l'usine, donc contrairement au jeton de symbole, il est surchargé pour accepter un argument String. Si une chaîne de caractères vide (y compris une chaîne de caractères avec uniquement des espaces) ou null est passée, le jeton vide créé à l'avance est renvoyé. Cela évite une vérification supplémentaire des erreurs sur l'appelant. Le symbole à une lettre est censé être passé en type char, mais comme assurance lorsqu'il est passé en type chaîne, si la chaîne transmise ne contient qu'un seul caractère, la fabrique du jeton de symbole est appelée. .. Dans le cas d'une chaîne de caractères qui ne peut pas être prise en charge par la fabrique de jetons de symboles, un jeton inconnu est renvoyé, donc dans ce cas, créez-le à nouveau en tant que jeton de chaîne de caractères.

De plus, bien que l'explication soit mélangée, le constructeur est déclaré privé de sorte que l'objet est créé uniquement via la méthode factory.

    static Token create(String s) {
        if ( s == null  ||  s.trim().isEmpty() ) { return empty_; }
        //Que faire si vous faites une erreur et que le symbole est passé sous forme de chaîne
        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

Enquête

Il existe deux types de jetons: un type d'élément énuméré et une représentation sous forme de chaîne de l'élément ("Plus" est renvoyé pour kinds.Plus).

    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());
    }

Résumé

C'est la fin de l'explication de la classe de jeton.

En fait, j'ai augmenté le nombre de jetons de symboles du programme que j'ai créé, mais même à ce niveau, j'ai trouvé ennuyeux de synchroniser le type d'énumération et l'instruction de commutation d'usine. J'ai pensé à remodeler cette partie à des fins générales, mais en raison du temps et des efforts nécessaires pour augmenter le nombre de cours, j'ai décidé de renoncer à cette fois.

La prochaine fois, ce sera le corps principal de l'analyseur de phrases.

Création d'une analyse de phrase avec Java 8 (Partie 2) Publié.

Recommended Posts

Faire une analyse de phrase en Java 8 (partie 2)
Création d'une analyse de phrase dans Java 8 (partie 1)
1 Implémentez une analyse de phrase simple en Java
Création d'une classe de matrice dans Java Partie 1
Analyse morphologique en Java avec Kuromoji
Création d'une classe pour une matrice en Java Partie 2-A propos d'une matrice (algèbre linéaire) -
Utilisez OpenCV_Contrib (ArUco) avec Java! (Partie 2-Programmation)
[Création] Un mémorandum sur le codage en Java
Partition en Java
Changements dans Java 11
Janken à Java
java pratique partie 1
Taux circonférentiel à Java
FizzBuzz en Java
Utilisez OpenCV_Contrib (ArUco) avec Java! (Partie 1-Construire) (OpenCV-3.4.4)
Ce que j'ai appris en Java (partie 2) Que sont les variables?
NLP4J [001b] Analyse morphologique en Java (utilisant kuromoji)
[LeJOS] Programmons mindstorm-EV3 avec Java [Construction de l'environnement partie 2]
Implémentation de l'interpréteur par Java
Faites un blackjack avec Java
Application Janken en Java
Programmation par contraintes en Java
Mettez java8 dans centos7
NVL-ish guy en Java
"Hello World" en Java
Interface appelable en Java
Un examen rapide de Java appris en classe part4
Commentaires dans la source Java
Fonctions Azure en Java
Formater XML en Java
Simple htmlspecialchars en Java
Implémentation Boyer-Moore en Java
Utiliser OpenCV avec Java
Mémorandum WebApi avec Java
Ce que j'ai appris en Java (partie 3) Déclaration d'exécution des instructions
Détermination de type en Java
Exécuter des commandes en Java (ping)
Implémentation du tri de tas (en java)
API Zabbix en Java
Art ASCII à Java
Comparer des listes en Java
POST JSON en Java
Étudier Java ~ Partie 8 ~ Cast
Un examen rapide de Java appris en classe part3
Exprimer l'échec en Java
Un examen rapide de Java appris en classe part2
Créer JSON en Java
Nouveautés de Java 8
Utiliser PreparedStatement en Java
Nouveautés de Java 9,10,11
Exécution parallèle en Java
JSON en Java et Jackson Partie 1 Renvoyer JSON à partir du serveur
[LeJOS] Programmons mindstorm-EV3 avec Java [Construction de l'environnement première partie]
Agrégation et analyse de journaux (utilisation d'AWS Athena en Java)
Ce que j'ai appris en Java (partie 4) Branchement conditionnel et répétition
45 Techniques d'optimisation des performances Java (partie 1)
Essayez d'utiliser RocksDB avec Java
Lire des fichiers binaires en Java 1
Évitez l'erreur que Yuma a donnée en Java
Obtenir des informations EXIF en Java