Elettracompany.com

Компьютерный справочник
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Java scanner usedelimiter

Использование класса Scanner в Java — примеры и методы

Это руководство по посвящено использованию класса Scanner в Java пакета java.util. Мы будем показывать базовое применение класса Scanner до самых расширенных функций этого класса, используя примеры.

Класс Scanner имеет богатый набор API, который обычно используется для разбиения входных данных конструктора Scanner на токены. Входные данные разбиваются на токены с помощью разделителя, определенного в классе Scanner с использованием метода radix, или могут быть определены.

Объявление:
public final class Scanner
extends Object
implements Iterator, Closeable

Конструкторы класса Scanner — public Scanner(Readable source)

Создает новый сканер, который создает значения, отсканированные из указанного источника.

Параметры: source — источник символов, реализующий интерфейс Readable

Не путайте с типом объекта, доступным для чтения в качестве параметра конструктора. Readable — это интерфейс, который был реализован с помощью BufferedReader, CharArrayReader, CharBuffer, FileReader, FilterReader, InputStreamReader, LineNumberReader, PipedReader, PushbackReader, Reader, StringReader.

Это означает, что мы можем использовать любой из этих классов в Java при создании экземпляра объекта Scanner.

public Scanner(InputStream source)

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

Параметры: источник — входной поток для сканирования.

Метод ввода этого конструктора — InputStream. Класс InputStream является одним из классов верхнего уровня в пакете java.io, и его использование будет проблемой.

Однако мы можем использовать подклассы InputStream, как показано ниже. Мы использовали FileInputStream, поскольку он является подклассом InputStream, при его включении проблем не возникнет.

public Scanner(File source) выдает исключение FileNotFoundException

Байты из файла преобразуются в символы с кодировкой по умолчанию базовой платформы.
Параметры: источник — файл для сканирования

Этот конструктор очень прост. Просто требует источник файла. Единственной целью этого конструктора является создание экземпляра объекта Scanner для сканирования через файл.

public Scanner(Path source) throws IOException

источник — путь к файлу для сканирования. Для параметра конструктора требуется источник Path, который используется редко.

public Scanner(String source)

Создает новый сканер, который выдает значения, отсканированные из указанной строки.

Источник — строка для сканирования.

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

Scanner в Java для чтения файлов

Считать файл очень легко, используя класс Scanner. Нам просто нужно объявить это с помощью конструктора Scanner, например:

Хитрость в итерации по токену Scanner состоит в том, чтобы применять те методы, которые начинаются с hasNext, hasNextInt и т.д. Давайте сначала остановимся на чтении файла построчно.

В приведенном выше фрагменте кода мы использовали флаг scan.hasNextLine() как средство проверки наличия токена, который в этом примере доступен на входе сканера. Метод nextLine() возвращает текущий токен и переходит к следующему.

Комбинации hasNextLine() и nextLine() широко используются для получения всех токенов на входе сканера. После этого мы вызываем метод close(), чтобы закрыть объект и тем самым избежать утечки памяти.

Считать строку из консоли ввода, используя Scanner Class

Класс Scanner принимает также InputStream для одного из своих конструкторов. Таким образом, ввод можно сделать с помощью:

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

Важные советы

Недавно я обнаружил одну проблему. Допустим, что мы просим пользователя ввести идентификатор сотрудника и имя сотрудника из консоли.

После чего мы будем читать ввод с консоли, используя сканер. Идентификатор сотрудника будет читаться с nextInt(), а имя сотрудника будет читаться как nextLine(). Это довольно просто, но это не сработает.

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

Использование класса Scanner в Java — примеры и методы

Это руководство по посвящено использованию класса Scanner в Java пакета java.util. Мы будем показывать базовое применение класса Scanner до самых расширенных функций этого класса, используя примеры.

Класс Scanner имеет богатый набор API, который обычно используется для разбиения входных данных конструктора Scanner на токены. Входные данные разбиваются на токены с помощью разделителя, определенного в классе Scanner с использованием метода radix, или могут быть определены.

Объявление:
public final class Scanner
extends Object
implements Iterator, Closeable

Конструкторы класса Scanner — public Scanner(Readable source)

Создает новый сканер, который создает значения, отсканированные из указанного источника.

Параметры: source — источник символов, реализующий интерфейс Readable

Не путайте с типом объекта, доступным для чтения в качестве параметра конструктора. Readable — это интерфейс, который был реализован с помощью BufferedReader, CharArrayReader, CharBuffer, FileReader, FilterReader, InputStreamReader, LineNumberReader, PipedReader, PushbackReader, Reader, StringReader.

Это означает, что мы можем использовать любой из этих классов в Java при создании экземпляра объекта Scanner.

public Scanner(InputStream source)

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

Параметры: источник — входной поток для сканирования.

Метод ввода этого конструктора — InputStream. Класс InputStream является одним из классов верхнего уровня в пакете java.io, и его использование будет проблемой.

Однако мы можем использовать подклассы InputStream, как показано ниже. Мы использовали FileInputStream, поскольку он является подклассом InputStream, при его включении проблем не возникнет.

public Scanner(File source) выдает исключение FileNotFoundException

Байты из файла преобразуются в символы с кодировкой по умолчанию базовой платформы.
Параметры: источник — файл для сканирования

Этот конструктор очень прост. Просто требует источник файла. Единственной целью этого конструктора является создание экземпляра объекта Scanner для сканирования через файл.

public Scanner(Path source) throws IOException

источник — путь к файлу для сканирования. Для параметра конструктора требуется источник Path, который используется редко.

public Scanner(String source)

Создает новый сканер, который выдает значения, отсканированные из указанной строки.

Источник — строка для сканирования.

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

Scanner в Java для чтения файлов

Считать файл очень легко, используя класс Scanner. Нам просто нужно объявить это с помощью конструктора Scanner, например:

Хитрость в итерации по токену Scanner состоит в том, чтобы применять те методы, которые начинаются с hasNext, hasNextInt и т.д. Давайте сначала остановимся на чтении файла построчно.

В приведенном выше фрагменте кода мы использовали флаг scan.hasNextLine() как средство проверки наличия токена, который в этом примере доступен на входе сканера. Метод nextLine() возвращает текущий токен и переходит к следующему.

Комбинации hasNextLine() и nextLine() широко используются для получения всех токенов на входе сканера. После этого мы вызываем метод close(), чтобы закрыть объект и тем самым избежать утечки памяти.

Считать строку из консоли ввода, используя Scanner Class

Класс Scanner принимает также InputStream для одного из своих конструкторов. Таким образом, ввод можно сделать с помощью:

Читать еще:  Проги для восстановления данных с жесткого диска

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

Важные советы

Недавно я обнаружил одну проблему. Допустим, что мы просим пользователя ввести идентификатор сотрудника и имя сотрудника из консоли.

После чего мы будем читать ввод с консоли, используя сканер. Идентификатор сотрудника будет читаться с nextInt(), а имя сотрудника будет читаться как nextLine(). Это довольно просто, но это не сработает.

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

java.util.Scanner’s useDelimiter(» «) or useDelimiter(Pattern.compile(«\s»)) work different than standard behaviour

Given the code below, it outputs:

if I type 10 spaces and leave the two useDelimiter method invokations commented, and outputs:

if I type the very same 10 spaces but do use one of the two useDelimiter invocations. Why is it like this? Shouldn’t be the same? Here is the code, thank you:

3 ответа

I read some of the Scanner documentation, which says among other things:

Depending upon the type of delimiting pattern, empty tokens may be returned. For example, the pattern «s+» will return no empty tokens since it matches multiple instances of the delimiter. The delimiting pattern «s» could return empty tokens since it only passes one space at a time.

The reason for the observed behavior is the default delimiter, which is \p+ as you can see in Scanner.WHITESPACE_PATTERN (code from OpenJDK) and Scanner.reset() (which resets the delimiter to that pattern). Because of the + , it matches your whole input as one delimiter.

If you change your custom delimiters by adding a + at the end, they will also treat consecutive whitespace as one delimiter.

+1, but could you please edit the link to the [documentation](https://docs.oracle.com/javase/8/docs/api/java/util/Scanner.html) back in? This serves both as a source for your quote and helps people to read more. – Just a student 11 май. 17 2017-05-11 12:20:43

In particular, can you please link to the documentation for ‘Scanner.WHITESPACE_PATTERN’. – Klitos Kyriacou 11 май. 17 2017-05-11 12:22:11

@Justastudent sorry, I think you did that edit just before I clicked submit on my own edit, hence I overwrote your change. I have added the links again. – Malte Hartwig 11 май. 17 2017-05-11 12:23:17

Yes, that’s what I thought. No worries! I commented in case you were still editing, probably should have done that in the first place. Thanks 🙂 – Just a student 11 май. 17 2017-05-11 12:24:07

Lets say that X is delimiter.

If we scan text like «aXbXc» it is clear that there are 3 tokens: «a» «b» and «c» .

If we scan text like «aXXc» there are still 3 tokens, but this time: «a» «» and «c» . That is because we set delimiter to match only one X at a time so it doesn’t see another X as continuation of already matched delimiter but as separate one.
(This is very useful in cases like when delimiter is , and we scan data like 1,2. 3 because it should represent elements: 1 2 noData noData 3 ).
If you would like delimiter to represent one or more X you would need to use X+ since + is quantifier representing «once or more». This way aXXc would represent only «a» and «c» elements since whole XX would be seen as one delimiter.

Other interesting case is aXbX . As you see there is no c here, text ends with delimiter. In such case Scanner doesn’t assume that there is empty element after last delimiter so it sees only «a» and «b» as tokens, not «a», «b», «» .

Same applies for XbXc where text starts with delimiter. Scanner doesn’t assume that there is some empty element before it.

Now lets go back to your case.

If you print Scanner’s default delimiter (using code like System.out.println(s1.delimiter()); ) you will see that it is p+ . So by default delimiter is one or more whitespaces. But later you change it to single space or family of whitespaces. This means that for string

  • if delimiter is p+ then the whole expression is matched as one delimiter so there are no elements before, after, and between delimiter, so there are 0 tokens (non-delimiter elements)
  • but if we use » » or «\s» as delimiter then Scanner will find 10 delimiters (each space is one of them). Since there are 10 delimiters, this means that there are 9 elements between them (even empty strings count). Also text starts and ends with delimiter, which means there are no tokens before first delimiter, or after last one.

Создан 11 май. 17 2017-05-11 12:22:47 Pshemo

It doesn’t seem to behave the way you describe. With ‘useDelimiter(» «)’, and an input starting with and ending with multiple spaces, it will return empty strings at both the start and the end. – Klitos Kyriacou 11 май. 17 2017-05-11 14:33:57

@KlitosKyriacou I am not sure what you mean. If we try to scan ‘»___a___»‘ and set delimiter ‘_’ (I replaced spaces with ‘_’, otherwise comment would show them as single space) like in https://ideone.com/xOSdYg you will see that we are getting tokens ‘»»‘ ‘»»‘ ‘»a»‘ ‘»»‘ ‘»»‘. Empty strings come from places marked with ‘|’: so they come from between delimiters ‘_|_|_a_|_|_’ without empty strings ‘|___a___|’ which are before starting or after trailing delimiter. – Pshemo 11 май. 17 2017-05-11 16:54:39

Your reply to my comment seems to be a direct contradiction to what you wrote in your answer: ‘Other interesting case is aXbX. As you see there is no c here, text ends with delimiter. In such case Scanner doesn’t assume that there is empty element after last delimiter so it sees only «a» and «b» as tokens, not «a», «b», «»‘. In fact, in agreement with your reply to my comment, it sees the tokens «a», «b», «». Not just «a» and «b». – Klitos Kyriacou 12 май. 17 2017-05-12 06:26:05

@KlitosKyriacou I still don’t see contradiction. I didn’t say that there are no empty strings before or after delimiters, I said that scanner doesn’t see them (in sense as valid tokens — maybe that needs clarification). Here is example confirming that: https://ideone.com/FhMNn1 – Pshemo 12 май. 17 2017-05-12 11:09:28

I see, you’re right, but there seems to be some unintuitive behaviour here: Scanner doesn’t remove all empty tokens at the start and end – if you have N empty tokens at the start or end, Scanner sees N-1 empty tokens. https://ideone.com/qxChPs. Also, the behaviour differs from ‘String.split()’. – Klitos Kyriacou 12 май. 17 2017-05-12 11:34:23

@KlitosKyriacou It is easier to understand Scanner when we understand that delimiter is different than separator and terminator (these are not synonyms). In short if we have text like ‘,a,,’ then if ‘,’ is delimiter then we have 2 elements ‘»a»‘ and ‘»»‘. If ‘,’ is separator we have 3 elements ‘»»‘ ‘»a»‘ and ‘»»‘. If ‘,’ is terminator we have 4 elements: ‘»»‘, ‘»a»‘ ‘»»‘ ‘»»‘. In Scanner we are using delimiters. And yes, Scanner is different than ‘split()’ since it doesn’t remove all trailing empty strings, but only one which is after last delimiter. – Pshemo 12 май. 17 2017-05-12 12:29:26

That’s a good explanation — Scanner uses a delimiter, whereas ‘String.split’ uses a separator (e.g. ‘»,a,,».split(«,», -1).length == 4’ whereas with Scanner it’s 2.) So the important thing is to understand the subtle difference between delimiter and separator. But then Oracle calls Sting.split’s argument a delimiter in its documentation, not a separator. – Klitos Kyriacou 12 май. 17 2017-05-12 12:34:51

@KlitosKyriacou Yes, which is why I can’t say that documentation is perfect. Most often after reading it I still need to write some simple tests to check cases which ware not explained fully. – Pshemo 12 май. 17 2017-05-12 12:42:53

Indeed, sometimes we need to write code to check the behaviour of badly explained methods; but that worries me since if a behaviour is not documented, there is a small possibility it can change in a new release. – Klitos Kyriacou 12 май. 17 2017-05-12 12:56:57

@KlitosKyriacou Update: I mixed terminator with separator in my previous comment. So for ‘,a,,’ if ‘,’ is terminator we would get 3 elements, and in case of separator 4 elements. – Pshemo 20 май. 17 2017-05-20 13:35:43

Neither of the two whitespace patterns that you attempted match the default delimiter, which is «\p+» . The documentation doesn’t make this clear: it simply says «A Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespace.» Colloquially «whitespace» implies any number of consecutive whitespace characters.

java.util.Scanner’s useDelimiter(» «) or useDelimiter(Pattern.compile(«\s»)) work different than standard behaviour

Given the code below, it outputs:

if I type 10 spaces and leave the two useDelimiter method invokations commented, and outputs:

if I type the very same 10 spaces but do use one of the two useDelimiter invocations. Why is it like this? Shouldn’t be the same? Here is the code, thank you:

3 ответа

I read some of the Scanner documentation, which says among other things:

Depending upon the type of delimiting pattern, empty tokens may be returned. For example, the pattern «s+» will return no empty tokens since it matches multiple instances of the delimiter. The delimiting pattern «s» could return empty tokens since it only passes one space at a time.

The reason for the observed behavior is the default delimiter, which is \p+ as you can see in Scanner.WHITESPACE_PATTERN (code from OpenJDK) and Scanner.reset() (which resets the delimiter to that pattern). Because of the + , it matches your whole input as one delimiter.

If you change your custom delimiters by adding a + at the end, they will also treat consecutive whitespace as one delimiter.

+1, but could you please edit the link to the [documentation](https://docs.oracle.com/javase/8/docs/api/java/util/Scanner.html) back in? This serves both as a source for your quote and helps people to read more. – Just a student 11 май. 17 2017-05-11 12:20:43

In particular, can you please link to the documentation for ‘Scanner.WHITESPACE_PATTERN’. – Klitos Kyriacou 11 май. 17 2017-05-11 12:22:11

@Justastudent sorry, I think you did that edit just before I clicked submit on my own edit, hence I overwrote your change. I have added the links again. – Malte Hartwig 11 май. 17 2017-05-11 12:23:17

Yes, that’s what I thought. No worries! I commented in case you were still editing, probably should have done that in the first place. Thanks 🙂 – Just a student 11 май. 17 2017-05-11 12:24:07

Lets say that X is delimiter.

If we scan text like «aXbXc» it is clear that there are 3 tokens: «a» «b» and «c» .

If we scan text like «aXXc» there are still 3 tokens, but this time: «a» «» and «c» . That is because we set delimiter to match only one X at a time so it doesn’t see another X as continuation of already matched delimiter but as separate one.
(This is very useful in cases like when delimiter is , and we scan data like 1,2. 3 because it should represent elements: 1 2 noData noData 3 ).
If you would like delimiter to represent one or more X you would need to use X+ since + is quantifier representing «once or more». This way aXXc would represent only «a» and «c» elements since whole XX would be seen as one delimiter.

Other interesting case is aXbX . As you see there is no c here, text ends with delimiter. In such case Scanner doesn’t assume that there is empty element after last delimiter so it sees only «a» and «b» as tokens, not «a», «b», «» .

Same applies for XbXc where text starts with delimiter. Scanner doesn’t assume that there is some empty element before it.

Now lets go back to your case.

If you print Scanner’s default delimiter (using code like System.out.println(s1.delimiter()); ) you will see that it is p+ . So by default delimiter is one or more whitespaces. But later you change it to single space or family of whitespaces. This means that for string

  • if delimiter is p+ then the whole expression is matched as one delimiter so there are no elements before, after, and between delimiter, so there are 0 tokens (non-delimiter elements)
  • but if we use » » or «\s» as delimiter then Scanner will find 10 delimiters (each space is one of them). Since there are 10 delimiters, this means that there are 9 elements between them (even empty strings count). Also text starts and ends with delimiter, which means there are no tokens before first delimiter, or after last one.

Создан 11 май. 17 2017-05-11 12:22:47 Pshemo

It doesn’t seem to behave the way you describe. With ‘useDelimiter(» «)’, and an input starting with and ending with multiple spaces, it will return empty strings at both the start and the end. – Klitos Kyriacou 11 май. 17 2017-05-11 14:33:57

@KlitosKyriacou I am not sure what you mean. If we try to scan ‘»___a___»‘ and set delimiter ‘_’ (I replaced spaces with ‘_’, otherwise comment would show them as single space) like in https://ideone.com/xOSdYg you will see that we are getting tokens ‘»»‘ ‘»»‘ ‘»a»‘ ‘»»‘ ‘»»‘. Empty strings come from places marked with ‘|’: so they come from between delimiters ‘_|_|_a_|_|_’ without empty strings ‘|___a___|’ which are before starting or after trailing delimiter. – Pshemo 11 май. 17 2017-05-11 16:54:39

Your reply to my comment seems to be a direct contradiction to what you wrote in your answer: ‘Other interesting case is aXbX. As you see there is no c here, text ends with delimiter. In such case Scanner doesn’t assume that there is empty element after last delimiter so it sees only «a» and «b» as tokens, not «a», «b», «»‘. In fact, in agreement with your reply to my comment, it sees the tokens «a», «b», «». Not just «a» and «b». – Klitos Kyriacou 12 май. 17 2017-05-12 06:26:05

@KlitosKyriacou I still don’t see contradiction. I didn’t say that there are no empty strings before or after delimiters, I said that scanner doesn’t see them (in sense as valid tokens — maybe that needs clarification). Here is example confirming that: https://ideone.com/FhMNn1 – Pshemo 12 май. 17 2017-05-12 11:09:28

I see, you’re right, but there seems to be some unintuitive behaviour here: Scanner doesn’t remove all empty tokens at the start and end – if you have N empty tokens at the start or end, Scanner sees N-1 empty tokens. https://ideone.com/qxChPs. Also, the behaviour differs from ‘String.split()’. – Klitos Kyriacou 12 май. 17 2017-05-12 11:34:23

@KlitosKyriacou It is easier to understand Scanner when we understand that delimiter is different than separator and terminator (these are not synonyms). In short if we have text like ‘,a,,’ then if ‘,’ is delimiter then we have 2 elements ‘»a»‘ and ‘»»‘. If ‘,’ is separator we have 3 elements ‘»»‘ ‘»a»‘ and ‘»»‘. If ‘,’ is terminator we have 4 elements: ‘»»‘, ‘»a»‘ ‘»»‘ ‘»»‘. In Scanner we are using delimiters. And yes, Scanner is different than ‘split()’ since it doesn’t remove all trailing empty strings, but only one which is after last delimiter. – Pshemo 12 май. 17 2017-05-12 12:29:26

That’s a good explanation — Scanner uses a delimiter, whereas ‘String.split’ uses a separator (e.g. ‘»,a,,».split(«,», -1).length == 4’ whereas with Scanner it’s 2.) So the important thing is to understand the subtle difference between delimiter and separator. But then Oracle calls Sting.split’s argument a delimiter in its documentation, not a separator. – Klitos Kyriacou 12 май. 17 2017-05-12 12:34:51

@KlitosKyriacou Yes, which is why I can’t say that documentation is perfect. Most often after reading it I still need to write some simple tests to check cases which ware not explained fully. – Pshemo 12 май. 17 2017-05-12 12:42:53

Indeed, sometimes we need to write code to check the behaviour of badly explained methods; but that worries me since if a behaviour is not documented, there is a small possibility it can change in a new release. – Klitos Kyriacou 12 май. 17 2017-05-12 12:56:57

@KlitosKyriacou Update: I mixed terminator with separator in my previous comment. So for ‘,a,,’ if ‘,’ is terminator we would get 3 elements, and in case of separator 4 elements. – Pshemo 20 май. 17 2017-05-20 13:35:43

Neither of the two whitespace patterns that you attempted match the default delimiter, which is «\p+» . The documentation doesn’t make this clear: it simply says «A Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespace.» Colloquially «whitespace» implies any number of consecutive whitespace characters.

Java.util.Scanner useDelimiter ( «) или useDelimiter (Pattern.compile(» \ s»)) отличаются от стандартного поведения

Учитывая приведенный ниже код, он выводит:

если я набираю 10 пробелов и оставляю два обработчика метода useDelimiter комментариями и выводит:

если я нахожу те же самые 10 пробелов, но использую одну из двух попыток useDelimiter. Почему так? Не должно быть одинаковым? Вот код, спасибо:

java java.util.scanner delimiter

3 ответа

4 Pshemo [2017-05-11 15:22:00]

Предположим, что X является разделителем.

Если мы сканируем текст как «aXbXc» , то ясно, что есть 3 жетона: «a» «b» и «c» .

Если мы сканируем текст, например «aXXc» , еще есть 3 жетона, но на этот раз: «a» «» и «c» . Это связано с тем, что мы ограничиваем ограничитель только одним X за раз, поэтому он не видит другого X в качестве продолжения уже сопоставленного разделителя, но как отдельный.
(Это очень полезно в случаях, когда разделитель , , и мы сканируем такие данные, как 1,2. 3 , потому что они должны представлять элементы: 1 2 noData noData 3 ).
Если вы хотите, чтобы разделитель представлял один или несколько X , вам нужно было бы использовать X+ , поскольку + является квантификатором, представляющим «один или несколько раз». Таким образом, aXXc будет представлять только элементы «a» и «c» , поскольку целые XX будут рассматриваться как один разделитель.

Другим интересным случаем является aXbX . Как видите, здесь нет c , текст заканчивается разделителем. В таком случае Сканер не предполагает, что после последнего разделителя существует пустой элемент, поэтому он видит только теги «a» и «b» как токены, а не «a», «b», «» .

То же самое относится к XbXc , где текст начинается с разделителя. Сканер не предполагает, что перед ним есть пустой элемент.

Теперь вернемся к вашему делу.

Если вы напечатаете разделитель по умолчанию для сканера (с использованием кода типа System.out.println(s1.delimiter()); ), вы увидите, что это p+ . Таким образом, по умолчанию разделитель один или несколько пробелов. Но позже вы измените его на одно пространство или семейство пробелов. Это означает, что для строки

  • если разделитель p+ , тогда все выражение сопоставляется как один разделитель, поэтому нет элементов до, после и между разделителями, поэтому есть 0 токенов (элементы без разделителя)
  • но если мы используем » » или «\s» в качестве разделителя, тогда сканер найдет 10 разделителей (каждое из них является одним из них). Поскольку существует 10 разделителей, это означает, что между ними есть 9 элементов (даже пустые строки). Также текст начинается и заканчивается разделителем, что означает, что перед первым разделителем или после последнего нет токенов.

Я прочитал часть Документация сканера, в которой говорится, среди прочего:

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

Причиной наблюдаемого поведения является разделитель по умолчанию, который равен \p+ , как вы можете видеть в Scanner.WHITESPACE_PATTERN (код из OpenJDK) и Scanner.reset() (который сбрасывает разделитель на этот шаблон). Из-за + он соответствует вашему вводу в качестве одного разделителя.

Если вы измените свои пользовательские разделители, добавив в конце + , они также будут рассматривать последовательные пробелы как один разделитель.

Ни один из двух шаблонов пробелов, которые вы пытались совместить с разделителем по умолчанию, который является «\p+» . документация не делает этого ясно: просто сказано: «Сканер разбивает свой вход на токены, используя шаблон разделителя, который по умолчанию соответствует пробелу». В простом «пробеле» подразумевается любое количество последовательных символов пробелов.

Ссылка на основную публикацию
Adblock
detector