Scanner.hasNext (Pattern pattern) не работает должным образом - PullRequest
0 голосов
/ 06 ноября 2018

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

public class StackOverflowExample {
    public static void main(String[] args) {
        // This is a source string example
        StringReader stringReader = new StringReader("\"field_name\":\"field_value\"");
        // The scanner instance with default values
        Scanner scanner = new Scanner(stringReader);
        // Set the scanner delimiter to \b* so it takes blanks as delimiters only if they're there
        scanner.useDelimiter(Pattern.compile("\b*"));
        // Compile the pattern to match field names
        Pattern field_name_pattern = Pattern.compile("\"\\w+\":");
        // Check if scanner finds the first field name
        if (scanner.hasNext(field_name_pattern)) {
            // Field name found, so print it
            System.out.println(scanner.next(field_name_pattern));
        } else {
            // Field name not found, so warn about it
            System.out.println("Oops! It didn't work!");
        }
    }
}

Ожидаемое поведение заключается в том, что сканер сопоставляет первое «field_name»: подстроку в считывателе и, следовательно, возвращает true для scanner.hasNext (field_name_pattern), но фактическое поведение заключается в том, что он не соответствует ему и поэтому возвращает вместо ложного.

Ответы [ 3 ]

0 голосов
/ 06 ноября 2018

Scanner s разбить текст на токены, затем предоставить эти токены или позволить вам работать с этими токенами. Разделитель - это то, что определяет, как разбить токены на части. Из Javadoc :

Сканер разбивает свои входные данные на токены, используя шаблон разделителя, который по умолчанию соответствует пробелу. Полученные токены могут затем быть преобразованы в значения различных типов с использованием различных следующих методов.

В вашем случае ваш разделитель "\b*". С таким дополнительным разделителем я не был уверен, что будет делать Scanner, но ваш тест показывает, что он разбивает текст без пробелов на один токен, который не соответствует указанному шаблону.

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

0 голосов
/ 06 ноября 2018

Хорошо, проблема, на которую указывали другие пользователи, заключается в том, что метод Scanner.hasNext (Pattern pattern) НЕ работает, когда нет конкретного разделителя. Фактически, он нужен для генерации токенов, а при его отсутствии вся строка становится следующим токеном.

Решение состоит в том, чтобы использовать метод Scanner.findInLine (Pattern pattern) взамен следующего:

public class StackOverflowExample {
    public static void main(String[] args) {
        // This is a source string example
        StringReader stringReader = new StringReader("\"field_name\":\"field_value\"");
        // The scanner instance with default values
        Scanner scanner = new Scanner(stringReader);
        // Compile the pattern to match field names
        Pattern field_name_pattern = Pattern.compile("\"\\w+\":");
        // Check if scanner finds the first field name
        String field_name = scanner.findInLine(field_name_pattern);
        if (field_name != null) {
            // Field name found, so print it
            System.out.println(field_name);
        } else {
            // Field name not found, so warn about it
            System.out.println("Oops! It didn't work!");
        }
    }
}

Большое спасибо тем, кто ответил.

0 голосов
/ 06 ноября 2018

Проблема в разделителе вашего сканера, который завершается с ошибкой и возвращает полную входную строку в качестве следующего токена для сканера, в результате чего шаблон "\"\\w+\":" возвращает false.

Согласно Javadoc public boolean hasNext​(Pattern pattern)

Возвращает true, если следующий полный токен соответствует указанному шаблону. Полный токен имеет префикс и постфикс после ввода, который соответствует шаблону разделителя.

Вы можете использовать двоеточие в качестве разделителя, чтобы заставить его работать:

scanner.useDelimiter(Pattern.compile(":"));

Полный код:

// This is a source string example
StringReader stringReader = new StringReader("\"field_name\":\"field_value\"");
// The scanner instance with default values
Scanner scanner = new Scanner(stringReader);
// Set the scanner delimiter to \b* so it takes blanks as delimiters only if they're there
scanner.useDelimiter(Pattern.compile(":"));
// Compile the pattern to match field names
Pattern field_name_pattern = Pattern.compile("\"\\w+\"");
// Check if scanner finds the first field name
if (scanner.hasNext(field_name_pattern)) {
    // Field name found, so print it
    System.out.println(scanner.next(field_name_pattern));
} else {
    // Field name not found, so warn about it
    System.out.println("Oops! It didn't work!");
}
scanner.close();

Вывод:

"field_name"
...