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

3
我正在尝试解析一个包含电子邮件地址的文档,但是StreamTokenizer将电子邮件地址分成了两个独立的部分。
我已经将@符号设置为ordinaryChar,并将空格设置为唯一的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"。有没有办法告诉分词器不要在@符号处分割?

2
你使用 StreamTokenizer 的特定原因是什么,而不是逐行读取文件并拆分或使用 Scanner - RealSkeptic
没有任何特定的原因,我只是认为使用分词器进行分词会很好。并且想知道这是一个错误还是我的操作有误。 - Dennis Beier
1
@DennisBeier:String.split非常好用且易于使用...请参见http://stackoverflow.com/a/236425/1587329 - serv-inc
2个回答

2
所以这就是它为什么像它所做的那样工作的原因:StreamTokenizer把它的输入视为编程语言标记化器。也就是说,它根据程序员为其设置的语法将其分解为“单词”、“数字”、“引号字符串”、“注释”等标记。程序员告诉它哪些字符是单词字符、普通字符、注释字符等。
事实上,它进行了相当复杂的标记化——识别注释、引用字符串、数字。请注意,在编程语言中,您可以有一个类似于a = a+b;的字符串。一个简单的标记化器只能通过空格将文本分割成a=a+b;。但是StreamTokenizer会将其分解为a=a+b;,并且还会为每个这些标记提供“类型”,因此您的“语言”解析器可以区分标识符和运算符。 StreamTokenizer的类型非常基本,但是这种行为是理解在您的情况中发生了什么的关键。
它没有将@识别为空格。实际上,它正在解析它并将其作为标记返回。但是它的值在ttype字段中,您可能只看了svalStreamTokenizer会将您的行识别为:
单词Student
数字6.0
单词Name6
单词LastName6
单词del6
字符@
单词uni.at
单词Competition
单词speech
单词University
单词of
单词Innsbruck
(这是我编写的一个小演示的实际输出,用于标记化您的示例行并按类型打印)。
实际上,通过告诉它@是一个“普通字符”,您告诉它将@作为自己的标记(无论如何,默认情况下都会这样做)。ordinaryChar()文档告诉您,此方法:

指定字符参数在此标记化程序中为“普通”。 它消除了字符作为注释字符、单词组件、字符串分隔符、空格或数字字符的任何特殊意义。当解析器遇到这样的字符时,解析器将其视为单个字符标记,并将ttype字段设置为字符值。

(我的强调)。
实际上,如果您改为将其传递给wordChars(),例如tokenizer.wordChars('@','@'),它将保持整个电子邮件。我添加了这个的小演示如下:
单词 学生
数字 6.0
单词 名字6
单词 姓氏6
单词 del6@uni.at
单词 竞赛
单词 演讲
单词 大学
单词 的
单词 因斯布鲁克

如果您需要类似编程语言的标记器,StreamTokenizer可能适合您。否则,您的选择取决于您的数据是否以行为基础(每行是一个单独的记录,每行可能有不同数量的令牌),在这种情况下,您通常会从读取器逐行读取行,然后使用String.split()分割它们;如果它只是一个由空格分隔的一系列令牌,则Scanner可能更适合您。


1
为了简单地分割一个字符串,请参见答案中对空格进行调整的此问题(不使用StringTokenizer):
最好的方法是根本不使用StringTokenizer,而是使用String的split方法。它返回一个字符串数组,你可以从中获取长度。
对于文件中的每一行,您可以执行以下操作:
String[] tokens = line.split(" +");
tokens现在将有6-8个字符串。使用tokens.length()找出有多少个字符串,然后从数组创建对象。
这对于给定的行足够了,可能对于其他所有情况也足够了。这里是一些使用它的代码(它读取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
        }
    }
}

1
请注意,StringTokenizerStreamTokenizer非常不同。 - RealSkeptic
非常感谢您提供如此详细的描述。 - serv-inc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接