Java StreamTokenizer 在 @ 符号处拆分电子邮件地址

Java StreamTokenizer splits Email address at @ sign

我正在尝试解析包含电子邮件地址的文档,但是 StreamTokenizer 将电子邮件地址拆分为两个单独的部分。

我已经将 @ 符号设置为 ordinaryChar 和 space 作为唯一的 whitespace:

StreamTokenizer tokeziner = new StreamTokenizer(freader);
tokeziner.ordinaryChar('@');
tokeziner.whitespaceChars(' ', ' ');

仍然,所有电子邮件地址都分开了。

要解析的行如下所示:

"Student 6 Name6 LastName6 del6@uni.at  Competition speech University of Innsbruck".

分词器将 del6@uni.at 拆分为 "del6""uni.at"

有没有办法告诉分词器不要在 @ 处拆分?

为了简单地拆分 String,请参阅 the answer to this question(针对空白进行了修改):

The best way is to not use a StringTokenizer at all, but use String's split method. It returns an array of Strings, and you can get the length from that.

For each line in your file you can do the following:

String[] tokens = line.split(" +");

tokens will now have 6 - 8 Strings. Use tokens.length() to find out how many, then create your object from the array.

这对于给定的行来说已经足够了,并且可能对所有内容都足够了。下面是一些使用它的代码(显示为 System.in):

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class T {
    public static void main(String[] args) {
        BufferedReader st = new BufferedReader(new InputStreamReader(System.in));

        String line;
        try {
            while ( st.ready() ) {
                line = st.readLine();
                String[] tokens = line.split(" +");
                for( String token: tokens ) {
                    System.out.println(token);
                }
            }
        } catch ( IOException e ) {
            throw new RuntimeException(e); // handle error here
        }
    }
}

这就是为什么它会像现在这样工作:

StreamTokenizer 将其输入视为编程语言分词器。也就是说,它根据程序员为其设置的语法将其分解为 "words"、"numbers"、"quoted strings"、"comments" 等标记。程序员告诉它哪些字符是单词字符、普通字符、注释字符等

所以实际上它进行了相当复杂的分词——识别评论、引用的字符串、数字。请注意,在编程语言中,您可以使用 a = a+b; 这样的字符串。一个简单的 tokenizer 只用空格将文本打断,将把它打断成 a=a+b;。但是 StreamTokenizer 会将其分解为 a=a+b;,并且还会为每个标记提供 "type",因此您的 "language" 解析器可以区分标识符和运算符。 StreamTokenizer 的类型相当基础,但这种行为是理解您的情况的关键。

它没有将 @ 识别为空格。事实上,它正在解析它并将其作为令牌返回。但它的值在 ttype 字段中,您可能只是在查看 sval.

A StreamTokenizer 会将您的台词识别为:

The word Student
The number 6.0
The word Name6
The word LastName6
The word del6
The character @
The word uni.at
The word Competition
The word speech
The word University
The word of
The word Innsbruck

(这是我编写的一个小演示的实际输出,它标记了您的示例行并按类型打印)。

事实上,通过告诉它 @ 是一个 "ordinary character",你是在告诉它把 @ 作为它自己的标记(默认情况下它确实这样做)。 ordinaryChar() documentation告诉你这个方法:

Specifies that the character argument is "ordinary" in this tokenizer. It removes any special significance the character has as a comment character, word component, string delimiter, white space, or number character. When such a character is encountered by the parser, the parser treats it as a single-character token and sets ttype field to the character value.

(我的重点)。

事实上,如果您将它传递给 wordChars(),就像在 tokenizer.wordChars('@','@') 中一样,它会将整个电子邮件放在一起。我添加的小演示给出了:

The word Student
The number 6.0
The word Name6
The word LastName6
The word del6@uni.at
The word Competition
The word speech
The word University
The word of
The word Innsbruck

如果您需要类似编程语言的分词器,StreamTokenizer 可能适合您。否则你的选择取决于你的数据是否是基于行的(每行是一个单独的记录,每行可能有不同数量的标记),你通常会从 reader,然后使用 String.split() 拆分它们,或者如果它只是一个以空格分隔的标记链,其中 Scanner 可能更适合您。