将垂直空格字符用作Java扫描程序分隔符可在每个结束行扫描空白字符串

时间:2019-05-19 20:58:58

标签: java regex java.util.scanner

我正在尝试使用Java中的Scanner类扫描数据字段以'@'或'endline'分隔的文件。这是一个示例输入文件:

Student @ Codey @ Huntting
Student @ Sarah @ Honsinger

要正确扫描如下所示的输入文件,我尝试将Java扫描程序上的分隔符更改为正则表达式"[@\\v]",该表达式应与@或任何垂直空白匹配,根据{{​​3}}

包括\n\r

这是我用来测试的代码:

Scanner scanner = new Scanner(new File("data/initialize.txt"));
int tokenNum = 0;

scanner.useDelimiter("[@\\v]");

while(scanner.hasNext()) {
    System.out.println("Token #" + tokenNum++ + ": " + scanner.next());
}

scanner.close();

我希望扫描的令牌是:

Token #1: Student
Token #2:  Codey 
Token #3:  Huntting
Token #4: Student
Token #5:  Sarah
Token #6:  Honsinger

但是实际收到的令牌是:

Token #1: Student
Token #2:  Codey 
Token #3:  Huntting
Token #4
Token #5: Student
Token #6:  Sarah
Token #7:  Honsinger
Token #8: 

我希望扫描仪在扫描Huntting之后,在Huntting之后会上升到换行符,并且在下次调用input.next()时跳过该换行符,但是由于某种原因,扫描仪似乎在行尾抓住了一个空字符串。

我已经检查了多次,文件在任何行之后都没有空格。我尝试了[@[\\v]][@][\\v]之类的不同模式,但是这些模式始终会给数据带来相同的空字符串错误,或者输出完全不正确。

3 个答案:

答案 0 :(得分:0)

如果我理解正确,我们可能只想删除@和其后的空格,然后用新行替换并在其前面添加文本。也许此表达式会有所帮助:

([\S\s]*?)(?:@\s|$)

enter image description here

RegEx

如果不需要此表达式,则可以在regex101.com中修改/更改表达式。

RegEx电路

您还可以在jex.im中可视化您的表达式:

enter image description here

JavaScript演示

此代码段表明我们可能有一个有效的表达式:

const regex = /([\S\s]*?)(?:@\s|$)/gm;
const str = `Student @ Codey @ Huntting
Student @ Sarah @ Honsinger`;
const subst = `\n$1`;

// The substituted value will be contained in the result variable
const result = str.replace(regex, subst);

console.log('Substitution result: ', result);

Java测试

import java.util.regex.Matcher;
import java.util.regex.Pattern;

final String regex = "([\\S\\s]*?)(?:@\\s|$)";
final String string = "Student @ Codey @ Huntting\n"
     + "Student @ Sarah @ Honsinger";
final String subst = "$1\\n";

final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);

// The substituted value will be contained in the result variable
final String result = matcher.replaceAll(subst);

System.out.println("Substitution result: " + result);

如果我们希望删除新行,则可能希望将其添加到第二个捕获组中,并且可以解决该问题:

([\s\S]+?)(@\s|\n\s|\n|$)

在这里,在第二个捕获组(@\s|\n\s|\n|$)中,使用逻辑或,我们可以排除我们不希望拥有的字符:

enter image description here

Demo

const regex = /([\s\S]+?)(@\s|\n\s|\n|$)/gm;
const str = `Student @ Codey @ Huntting

Student @ Sarah @ Honsinger                     
`;
const subst = `Token #: $1\n`;

// The substituted value will be contained in the result variable
const result = str.replace(regex, subst);

console.log('Substitution result: ', result);

Java测试

import java.util.regex.Matcher;
import java.util.regex.Pattern;

final String regex = "([\\s\\S]+?)(@\\s|\\n\\s|\\n|$)";
final String string = "Student @ Codey @ Huntting\n\n"
     + "Student @ Sarah @ Honsinger                     \n";
final String subst = "Token #: $1\\n";

final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);

// The substituted value will be contained in the result variable
final String result = matcher.replaceAll(subst);

System.out.println("Substitution result: " + result);

答案 1 :(得分:0)

您的文件可能包含\r\n格式的换行符。 在这种情况下,扫描仪会找到定界符\r并输出\r之前的任何内容。然后,它找到定界符\n,并在\r\n之间输出空令牌,然后在\n之后继续。

为了允许\r\n中断,我建议您以完全相同的顺序使用\r\n|[@\v]作为分隔符正则表达式。当然,转义后变成"\r\n|[@\\v]"

正如Andreas提到的,您可以使用的另一个正则表达式是@|\R,因为\R与任何Unicode换行符都匹配,包括\r\n。这甚至可能是最好的解决方案。

答案 2 :(得分:0)

您的问题是换行符是一对maven-antlr-plugin,并且\r\n分别匹配它们。要复制此代码,让我们更改代码以将内联字符串用于测试数据:

\v

输出

String input = "Student @ Codey @ Huntting\r\n" +
               "Student @ Sarah @ Honsinger\r\n";
try (Scanner scanner = new Scanner(input).useDelimiter("[@\\v]")) {
    for (int tokenNum = 0; scanner.hasNext(); tokenNum++) {
        System.out.println("Token #" + tokenNum + ": \"" + scanner.next() + "\"");
    }
}

一种解决方法是尝试首先匹配Token #0: "Student " Token #1: " Codey " Token #2: " Huntting" Token #3: "" Token #4: "Student " Token #5: " Sarah " Token #6: " Honsinger" Token #7: "" 对:

\r\n

输出

useDelimiter("\r\n|[@\\v]")

但是,这将花费时间检查Token #0: "Student " Token #1: " Codey " Token #2: " Huntting" Token #3: "Student " Token #4: " Sarah " Token #5: " Honsinger" 两次,因此最好使用内置的\R (任何Unicode换行符序列都等效于\r)< / em>:

\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]

相同的结果,但更清楚地反映出您想要匹配的方式。


您当然可以使用useDelimiter("@|\\R") trim()删除前导和尾随空格,但是为什么不让strip()起作用呢?使用Scanner需要一个(非捕获)组,以使其与空白匹配区分开:

|

输出

useDelimiter("\\s*(?:@|\\R)\\s*")