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

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

Ответов (15)

Решение

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

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

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

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

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

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

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

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

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

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

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

Я хотел бы посмотреть на Java миграции в Zork , и склоняются к более простой Natural Language Processor (управляемый либо tokenizing или регулярное выражение) , например, следующее (по этой ссылке):

    общедоступное статическое логическое значение simpleNLP (строка ввода, ключевые слова строки [])
    {
        int i;
        int maxToken = keywords.length;
        int to, from;
        если (inputline.length () = inputline.length ()) вернуть false; // проверяем наличие пустых и пустых строк
        в то время как (чтобы> = 0)
        {
            to = inputline.indexOf ('', от);
            if (to> 0) {
                lexed.addElement (inputline.substring (от, до));
                от = до;
                в то время как (inputline.charAt (from) == ''
                && from = keywords.length) {status = true; перерыв;}
            }
        }
        статус возврата;
    }

...

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

...

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

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

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), просто абстрагируйте его, чтобы его можно было использовать где угодно.

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

StringTokenizer

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

Шаблон

@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;
}

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

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

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

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

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

Библиотека CLI Apache Commons предоставляет API для обработки интерфейсов командной строки.

Попробуйте JavaCC - генератор синтаксического анализатора для Java.

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

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

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

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

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

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

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