【问题标题】:java.io.StreamTokenizer produces null token when encounter an underscorejava.io.StreamTokenizer 遇到下划线时产生空标记
【发布时间】:2015-04-29 05:45:38
【问题描述】:

我有一个用于解析令牌的 StreamTokenizer。当我将以下内容传递给标准输入时:

a b_c d

解析的标记(在标准输出上)是:

a
b
null
c
d

为什么会这样?如果下划线是单词字符,则应该有 3 个标记和第二个“b_c”。如果下划线是分隔符,则应该有 4 个标记。我认为空令牌没有意义。

Q1:为什么会有空令牌?

Q2:为什么有人会设计一个 StreamTokenizer 来生成空令牌?

Ideone 脚本:http://ideone.com/e.js/RFbPpJ

import java.util.*;
import java.lang.*;
import java.io.*;

class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StreamTokenizer st = new StreamTokenizer(br);
        while (st.nextToken() != StreamTokenizer.TT_EOF) {
            System.out.println(st.sval);
        }
    }
}

【问题讨论】:

    标签: java stream null tokenize java-io


    【解决方案1】:

    来自文档:

    如果当前token是单词token,该字段包含字符串 给出单词token的字符。当当前令牌是 带引号的字符串标记,此字段包含字符串的主体。这 当 ttype 字段的值为 TT_WORD 时,当前标记是一个单词。 当前标记是一个带引号的字符串标记,当 ttype 的值 字段是引号字符。

    该字段的初始值为空。

    这意味着不满足任何条件并输出null

    换句话说,下划线的 ttype 既不被视为单词也不被视为带引号的字符串。

    ttype 的文档指定

    在调用 nextToken 方法后,该字段包含的类型 令牌刚刚读取。对于单个字符标记,其值为 单个字符,转换为整数。对于带引号的字符串标记, 它的值是引号字符。否则,它的值是 以下: TT_WORD 表示该标记是一个单词。 TT_NUMBER 表示令牌是一个数字。 TT_EOL 表示结束 行已读。该字段只能具有此值,如果 已使用参数 true 调用 eolIsSignificant 方法。 TT_EOF 表示已到达输入流的末尾。

    该字段的初始值为-4。

    请注意,-4 值等于 TT_NOTHING。

    要将下划线识别为单词,可以使用tokenizer.wordChars('_', '_');

    wordChars 用于指定范围低

    如果您希望下划线是普通字符而不是单词字符,那么还有一个method

    请注意,将 '_' 作为 wordChars 的分隔符将只允许下划线作为单词字符,因此您可能需要设置适合您需要的边界。

    编辑:为了回答您的评论,简而言之,下划线被视为标识符的一部分,这就是为什么它没有映射到任何东西因此返回 null。

    如果您查看 StreamTokenizer 类的未记录的私有构造函数,您将更好地了解每个字符的处理方式:

    private StreamTokenizer() {
        wordChars('a', 'z');
        wordChars('A', 'Z');
        wordChars(128 + 32, 255);
        whitespaceChars(0, ' ');
        commentChar('/');
        quoteChar('"');
        quoteChar('\'');
        parseNumbers();
    }
    

    下划线是 ASCII 码 95,不在边界内。

    【讨论】:

    • 也许我的分词概念有点歪曲,但我认为分词器应该让每个字符都能够决定它是令牌的一部分还是分隔符......(仍然缺失Q2的答案)
    • 几乎...我想知道为什么有人设计了它,所以有些字符不被认为是在标记/分隔符中。有什么目的吗? (除了导致 NullPointerException 让我知道还有另一个未知字符)
    • @mirelon 正如我所说,下划线被设计为标识符的一部分。因此,当满足时,如果没有标识标识符,则不映射任何内容并返回 null。这可能会返回 NPE,但是 NPE 比意外行为更容易测试(例如,如果您输入了错误的标识符)。
    • 好的,所以我显然在字符流的上下文中缺少“标识符”的概念......你能解释一下吗?
    • @mirelon 标识符在这里只是我使用的一个随机术语。您必须了解的是,默认情况下,下划线不在任何范围内(请参阅我发布的构造函数)。因此,如果您不重新定义默认值,它将以这种方式工作,考虑到不应接受下划线。在我看来,这样做的原因不是为了抛出 null 和 NPE,而是为了在读取意外值时使其更加明显。但这并不是很重要,因为 Tokenizer 就像您想要充分使用的任何其他程序一样,应该设置适合您需求的自定义值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-15
    • 2013-05-02
    • 2021-02-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多