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

我已经将@符号设置为ordinaryChar,并将空格设置为唯一的whitespace:

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

尽管如此,所有电子邮件地址仍被拆分。

要解析的行如下所示:
"Student 6 Name6 LastName6 [email protected]  Competition speech University of Innsbruck".

标记器将[email protected]分为"del6""uni.at"

有没有办法告诉 token 生成器不要在@符号处拆分?

最佳答案

所以这就是为什么它像以前那样工作:
StreamTokenizer将其输入视为编程语言标记器。即,根据程序员为其设置的语法,将其分解为“单词”,“数字”,“带引号的字符串”,“注释”等的标记。程序员告诉它哪些字符是文字​​字符,普通字符,注释字符等。

因此,实际上,它确实进行了相当复杂的标记化-识别注释,带引号的字符串,数字。请注意,在一种编程语言中,您可以拥有一个类似于a = a+b;的字符串。一个简单的 token 生成器(仅用空格将文本拆分)会将其拆分为a=a+b;。但是StreamTokenizer会将其分解为a=a+b;,并且还将为您提供每个 token 的“类型”,因此您的“语言”解析器可以将标识符与运算符区分开。 StreamTokenizer的类型相当基本,但是此行为是了解您的情况的关键。

它没有将@识别为空格。实际上,它正在解析它并将其作为 token 返回。但是它的值在ttype字段中,您可能只是在看sval
StreamTokenizer将您的行识别为:

学生一词
数6.0
单词Name6
姓氏LastName6
单词del6
人物 @
uni.at一词
竞争一词
言语一词
大学一词
的字
因斯布鲁克一词

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

实际上,通过告诉@是一个“普通字符”,您就是在告诉它将@当作自己的 token (无论如何默认情况下都会这样做)。 ordinaryChar() documentation告诉您该方法:

指定此分词器中的字符参数为“普通”。
它删除了角色作为注释的任何特殊含义
字符,单词组成部分,字符串定界符,空格或数字
字符。 当解析器遇到这样的字符时,
解析器将其视为单字符 token ,并将ttype字段设置为
字符值。


(我的重点)。

实际上,如果您改为像wordChars()那样将其传递给tokenizer.wordChars('@','@'),它将把整个电子邮件保持在一起。我添加的小演示给出了:

学生一词
数6.0
单词Name6
姓氏LastName6
单词[email protected]
竞争一词
言语一词
大学一词
的字
因斯布鲁克一词

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

10-06 04:50