Какие существуют методы синтаксического анализа строк в Java?

Для анализа команд проигрывателя я чаще всего использовал метод расколоть, чтобы разделить строку по разделителям, а затем просто вычислить остальное с помощью серии if или switch. Какие существуют способы синтаксического анализа строк в Java?

Я попытался отредактировать вопрос, чтобы он не основывался на мнении, но боюсь, что ответы уже слишком самоуверенны.

agweber 13.05.2014 21:37
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
53
1
65 868
15
Перейти к ответу Данный вопрос помечен как решенный

Ответы 15

Мне очень нравятся регулярные выражения. Пока командные строки довольно просты, вы можете написать несколько регулярных выражений, для ручного анализа которых может потребоваться несколько страниц кода.

Я бы посоветовал вам проверить http://www.regular-expressions.info, чтобы получить хорошее введение в регулярные выражения, а также конкретные примеры для Java.

@Gaurav Vashishta, регулярные выражения могут быть полезны для лексика, но это только первый шаг в синтаксическом анализе.

Mike Samuel 06.05.2012 09:34

Простой строковый токенизатор пробелов должен работать, но есть действительно много способов сделать это.

Вот пример использования токенизатора:

String command = "kick person";
StringTokenizer tokens = new StringTokenizer(command);
String action = null;

if (tokens.hasMoreTokens()) {
    action = tokens.nextToken();
}

if (action != null) {
    doCommand(action, tokens);
}

Затем токены можно использовать в качестве аргументов. Все это предполагает, что в аргументах не используются пробелы ... поэтому вы можете использовать свой собственный простой механизм синтаксического анализа (например, получение первого пробела и использование текста перед в качестве действия или использование регулярного выражения, если вы не возражаете против speed hit), просто абстрагируйте его, чтобы его можно было использовать где угодно.

Насколько я помню, StringTokenizer устарел и настоятельно рекомендуется НЕ использовать его в документах JDK.

Ali Motevallian 23.01.2015 10:17

Я бы посмотрел на Миграции Java из Зорк и склонился к простому Процессор естественного языка (управляемому токенизацией или регулярным выражением), например следующим (из этой ссылки):

    public static boolean simpleNLP( String inputline, String keywords[])
    {
        int i;
        int maxToken = keywords.length;
        int to,from;
        if ( inputline.length() = inputline.length()) return false; // check for blank and empty lines
        while( to >=0 )
        {
            to = inputline.indexOf(' ',from);
            if ( to > 0){
                lexed.addElement(inputline.substring(from,to));
                from = to;
                while( inputline.charAt(from) == ' '
                && from = keywords.length) { status = true; break;}
            }
        }
        return status;
    }

...

Все, что дает программисту повод снова взглянуть на Zork, хорошо в моей книге, только берегитесь Груза.

...

Ответ принят как подходящий

Я предполагаю, что вы пытаетесь сделать командный интерфейс как можно более щадящим. Если это так, я предлагаю вам использовать алгоритм, подобный этому:

  1. Прочтите в строке
    • Разделить строку на токены
    • Используйте словарь, чтобы преобразовать синонимы в общую форму
    • Например, преобразовать все "удар", "удар", "удар" и "удар" в "удар".
    • Выполняйте действия на неупорядоченной, инклюзивной основе
    • Неупорядоченный - «бить обезьяну по морде» то же самое, что «бить обезьяну по морде»
    • Инклюзивный - Если команда должна быть «ударить обезьяну в лицо», и они предоставляют «ударить обезьяну», вы должны проверить, сколько команд это соответствует. Если только одна команда, сделайте это действие. Было бы даже неплохо установить приоритеты команд, и даже если бы были совпадения, он бы выполнял главное действие.

@CodingTheWheel Вот ваш код, немного очистить и пройти через eclipse (ctrl + shift + f) и вставить обратно сюда :)

Включая четыре пробела перед каждой строкой.

public static boolean simpleNLP(String inputline, String keywords[]) {
    if (inputline.length() < 1)
        return false;

    List<String> lexed = new ArrayList<String>(); 
    for (String ele : inputline.split(" ")) {
        lexed.add(ele);
    }


    boolean status = false;
    to = 0;
    for (i = 0; i < lexed.size(); i++) {
        String s = (String) lexed.get(i);
        if (s.equalsIgnoreCase(keywords[to])) {
            to++;
            if (to >= keywords.length) {
                status = true;
                break;
            }
        }
    }
    return status;
}

Когда разделитель String для команды всегда является той же String или char (например, ";") y рекомендуется использовать класс StrinkTokenizer:

StringTokenizer

но когда разделитель меняется или является сложным, рекомендуется использовать обычные выражения, которые могут использоваться самим классом String, метод split, начиная с версии 1.4. Он использует класс Pattern из пакета java.util.regex

Шаблон

Сама Sun рекомендует держаться подальше от StringTokenizer и вместо этого использовать метод String.split.

Вы также захотите взглянуть на класс Pattern.

Парсить вручную очень весело ... вначале :)

На практике, если команды не очень сложные, вы можете обрабатывать их так же, как те, которые используются в интерпретаторах командной строки. Вот список библиотек, которые вы можете использовать: http://java-source.net/open-source/command-line. Думаю, можно начать с Apache Commons CLI или args4j (использует аннотации). Они хорошо документированы и действительно просты в использовании. Они обрабатывают синтаксический анализ автоматически, и единственное, что вам нужно сделать, это прочитать определенные поля в объекте.

Если у вас есть более сложные команды, возможно, лучше будет создать формальную грамматику. Есть очень хорошая библиотека с графическим редактором, отладчиком и интерпретатором грамматик. Он называется ANTLR (и редактор ANTLRWorks), и он бесплатный :) Есть также несколько примеров грамматик и учебных пособий.

Если это нужно для синтаксического анализа командных строк, я бы предложил использовать Commons Cli.

The Apache Commons CLI library provides an API for processing command line interfaces.

Еще одно голосование за ANTLR / ANTLRWorks. Если вы создадите две версии файла, одну с кодом Java для фактического выполнения команд, а другую без (только с грамматикой), то у вас будет исполняемая спецификация языка, которая отлично подходит для тестирования и является благом для документации. , и сэкономит много времени, если вы когда-нибудь решите его портировать.

Попробуйте JavaCC генератор парсера для Java.

Он имеет множество функций для интерпретации языков и хорошо поддерживается в Eclipse.

Если язык настолько прост, как

ГЛАГОЛ СУЩЕСТВИТЕЛЬНОЕ

тогда хорошо работает ручное разделение.

Если это более сложно, вам действительно стоит изучить такой инструмент, как ANTLR или JavaCC.

У меня есть руководство по ANTLR (v2) на http://javadude.com/articles/antlrtut, которое даст вам представление о том, как это работает.

JCommander кажется неплохим, хотя я его еще не тестировал.

Если ваш текст содержит некоторые разделители, вы можете использовать метод split. Если текст содержит неправильные строки, значит в нем другой формат, тогда вы должны использовать regular expressions.

Метод split может разбить строку на массив указанного выражения подстроки regex. Его аргументы представлены в двух формах, а именно: split (String regex) и split (String regex, int limit), причем разбиение (String regex) фактически выполняется путем вызова split (String regex, int limit) для достижения предел 0. Затем, когда предел> 0 и предел представляет что?

Когда поясняется jdk: когда подматрица предел> 0 имеет длину до предела, то есть, если возможно, может быть подразбиением предел-1, оставаясь как подстрока (за исключением случаев, когда limit-1 раз у символа есть конец разделенной строки);

limit указывает на отсутствие ограничения на длину массива;

limit = 0 конец строки пустая строка будет обрезана. Класс StringTokenizer предназначен для совместимости и является устаревшим классом, поэтому мы должны попытаться использовать метод разделения класса String. см. связь

Другие вопросы по теме