Относительно того, что регулярные выражения оцениваются в java.util.Scanner? - PullRequest
0 голосов
/ 04 июля 2019

Я заметил следующее странное поведение, которое не могу объяснить:

import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    var scanner = new Scanner("ab");

    System.out.println(scanner.findInLine("."));  // output: a
    System.out.println(scanner.findInLine("."));  // output: b
  }
}

, но

import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    var scanner = new Scanner("ab");

    System.out.println(scanner.findInLine("."));  // output: a
    System.out.println(scanner.findInLine("^.")); // output: null
  }
}

Я не понимаю, чем второй фрагмент отличается от первогоone.

Согласно документации , ^ соответствует началу строки, но это не так, поскольку:

  1. a в начале совпадения строки,
  2. a в начале совпадения ввода и
  3. b в положении совпадения сканера.

Если регулярное выражение не оценивается относительно позиции сканера, то как оно оценивается относительно?

Ответы [ 2 ]

0 голосов
/ 07 июля 2019

Это все там, просто плохо документировано.Вот как реализовано findInLine:

public String findInLine(Pattern pattern) {
    // omitted: validate parameters
    // omitted: ensure the internal buffer is large enough

    return findWithinHorizon(pattern, horizonForLine);
}

Источник: java / util / Scanner.java

Вот что говорит документация о findWithinHorizon:

[...] Сканер воспринимает горизонт как прозрачную не привязывающуюся границу [...].

Источник: java.util.Scanner # findWithinHorizon (java.util.regex.Pattern, int)

и границы привязки:

[...] Без привязки границ границы области этого сопоставителя не будут соответствовать якорям, таким как ^ и $.[...]

Источник: java.util.regex.Matcher ## useAnchoringBounds (boolean)

Вот какРеализовано findWithinHorizon:

public String findWithinHorizon(Pattern pattern, int horizon) {
    // omitted: validate parameters

    while (true) {
        if (findPatternInBuffer(pattern, horizon)) {
            matchValid = true;
            return matcher.group();
        }

        // omitted: check if more input is required
    }
    return null;
}

Источник: java / util / Scanner.java

Воткак реализовано findPatternInBuffer:

private boolean findPatternInBuffer(Pattern pattern, int horizon) {
    // omitted: calculating search limit

    matcher.region(position, searchLimit);

    // omitted: matching pattern
}

java / util / Scanner.java

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

Это не означает, что каждое регулярное выражение с ^ не будет работать, будет работать положительный взгляд:

import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    var scanner = new Scanner("ab");

    System.out.println(scanner.findInLine("."));        // output: a
    System.out.println(scanner.findInLine("(?<=^.).")); // output: b
  }
}
0 голосов
/ 05 июля 2019

Что касается обоих фрагментов кода, то у сканера только после a не полная строка. Для перехода на следующую строку необходимо позвонить scanner.nextLine().

Метод findInLine (Pattern pattern) класса java.util.Scanner пытается найти следующее вхождение указанного шаблона, игнорируя разделители. Если шаблон найден перед разделителем следующей строки, Сканер продвигается дальше соответствующего ввода и возвращает строка, которая соответствует шаблону . Если такой шаблон не обнаружен в введите до разделителя следующей строки, затем возвращается ноль и положение сканера не изменилось.

https://www.geeksforgeeks.org/scanner-findinline-method-in-java-with-examples/

Примеры:

    Scanner scanner = new Scanner("abcde\nx");
    System.out.println(scanner.findInLine("."));    // output: a
    System.out.println(scanner.findInLine("."));    // output: b

Здесь сканер сопоставил первый символ (a) и переместился на b, который все еще находится на той же строке.

    Scanner scanner = new Scanner("abcde\nx");
    System.out.println(scanner.findInLine("."));     // output: a
    scanner.nextLine();
    System.out.println(scanner.findInLine("."));     // output: x

Здесь сканер работает так же, как и раньше, но я перешел через разделитель первой строки.

...