鉴于以下代码,它输出:
Feed a chunk of data here:
I have found: 0 words; 0 ints; 0 booleans;
如果我输入10个空格并留下两个useDelimiter方法调用注释,并输出:
Feed a chunk of data here:
I have found: 9 words; 0 ints; 0 booleans;
sssssssss
如果我键入相同的10个空格但使用两个useDelimiter调用之一。 为什么会这样?不应该是一样的吗?这是代码,谢谢:
package com.riccardofinazzi.regex;
import java.io.Console;
import java.util.Scanner;
import java.util.regex.Pattern;
import java.util.ArrayList;
class ScanNext {
public static void main(String[] args) {
/* match counters */
int hits_s = 0, hits_i = 0, hits_b = 0;
/* current token value */
String s;
Integer i;
Boolean b;
ArrayList<Object> al = new ArrayList<Object>();
Scanner s1 = new Scanner(System.console().readLine("Feed a chunk of data here: "));
/* not needed as this is def behaviour, I put it here to not forget the method */
//s1.useDelimiter(Pattern.compile("\\s"));
//s1.useDelimiter(" ");
while(s1.hasNext()) {
if ( s1.hasNextInt()) {
al.add(s1.nextInt()); hits_i++;
} else if ( s1.hasNextBoolean()) {
al.add(s1.nextBoolean()); hits_b++;
} else { al.add(s1.next()); hits_s++;
}
}
System.out.println("I have found:\t"+hits_s+" words; "+hits_i+" ints; "+hits_b+" booleans;");
for (Object in : al) {
if (in instanceof String)
System.out.print("s");
if (in instanceof Integer)
System.out.print("i");
if (in instanceof Boolean)
System.out.print("b");
}
System.out.print("\n");
}
}
答案 0 :(得分:4)
让我们说X
是分隔符。
如果我们扫描"aXbXc"
这样的文字,很明显有3个令牌:"a"
"b"
和"c"
。
如果我们扫描"aXXc"
这样的文字,仍有3个令牌,但这次:"a"
""
和"c"
。这是因为我们将分隔符设置为一次只匹配一个X
,因此它不会将另一个X
视为已匹配分隔符的延续,而是另一个分隔符。
(这在分隔符为,
的情况下非常有用,我们会扫描1,2,,,3
之类的数据,因为应代表元素:1
2
{ {1}} noData
noData
)。
如果您希望分隔符代表一个或多个3
,则需要使用X
,因为X+
是表示“一次或多次”的量词。这种方式+
仅代表aXXc
和"a"
元素,因为整个"c"
将被视为一个分隔符。
其他有趣的案例是XX
。如您所见,此处没有aXbX
, 文字以分隔符结尾 。在这种情况下,Scanner不会假设在最后一个分隔符后面有空元素,因此它只看到c
和"a"
作为标记,而不是"b"
。
同样适用于"a", "b", ""
文字以分隔符开头 。扫描仪不会假设它之前有一些空元素。
现在让我们回到你的案例。
如果您打印扫描仪的默认分隔符(使用XbXc
之类的代码),您将看到它是System.out.println(s1.delimiter());
。因此,默认情况下,分隔符为一个或多个空格。但是稍后您将其更改为单个空间或空格族。这意味着对于字符串
\p{javaWhitespace}+
" "
,则整个表达式匹配为一个分隔符,因此分隔符之前,之后和之间没有元素,因此有0个标记(非分隔符元素) )\p{javaWhitespace}+
或" "
作为分隔符,则Scanner会找到10个分隔符(每个空格一个)。由于有10个分隔符,这意味着之间有9个元素(即使是空字符串计数)。文本也以分隔符开头和结尾,这意味着在第一个分隔符之前或最后一个分隔符之后没有令牌。 答案 1 :(得分:3)
我读了一些Scanner documentation,其中包括:
根据分隔模式的类型,可能会返回空标记。例如,模式&#34; \ s +&#34;将返回没有空标记,因为它匹配分隔符的多个实例。划界模式&#34; \ s&#34;可以返回空标记,因为它一次只能传递一个空格。
观察到的行为的原因是默认分隔符,\\p{javaWhitespace}+
正如您在Scanner.WHITESPACE_PATTERN
(code from OpenJDK)和Scanner.reset()
中看到的那样(将分隔符重置为那个模式)。由于+
,它将您的整个输入与一个分隔符匹配。
如果您通过在结尾添加+
来更改自定义分隔符,则它们也会将连续的空格视为一个分隔符。
答案 2 :(得分:1)
您尝试的两个空白模式都没有与默认分隔符匹配,即"\\p{javaWhitespace}+"
。 documentation并没有明确说明:它只是说&#34;扫描程序使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空格相匹配。&#34;俗语&#34;空白&#34;意味着任意数量的连续空白字符。
默认分隔符的明确规范仅在Scanner.reset()的文档中说明,它将分隔符重置为默认值。