字符串标记符的奇怪行为

时间:2015-03-04 06:44:57

标签: java stringtokenizer

我有一个带分隔符的字符串(~

    String str="ABC~DEF~GHI~JKL~~MNO";// Input String
     while(stk.hasMoreTokens()){
            obj[i]=stk.nextToken();
            i++;
        }
        for(Object ob:obj){
            System.out.print(ob+"~>");
        }

我正在使用StringTokenizer将字符串分解为标记,但只要consecutive delimeter之间没有任何SpaceStringTokenizer会跳过它并取下一个标记

实际输出

ABC~>DEF~>GHI~>JKL~>MNO~>null~>

Desired Outupt

ABC~>DEF~>GHI~>JKL~>null~>MNO~> // Don't want to skip consecutive tokens

为什么会这样?

注意:

我知道我可以使用String#split(String delimeter)方法获得所需的输出,但是,我想知道存在奇怪行为的根本原因。

这里已经问过同样的问题(String Tokenizer issue),但没有提供任何理由,只有替代解决方案

4 个答案:

答案 0 :(得分:3)

我假设您使用了new StringTokenizer(str,"~")

StringTokenizer使用令牌的定义:令牌是分隔符之间的最大非空 char序列序列。

由于~~之间的字符串为空,因此它不能是令牌(按此定义)。

我使用以下代码验证:

public static void main(String[] args) {
    List<Object> obj = new ArrayList<>();
    String str = "ABC~DEF~GHI~JKL~~MNO";// Input String
    StringTokenizer stk = new StringTokenizer(str,"~");
    while (stk.hasMoreTokens()) {
        obj.add(stk.nextToken());
    }
    for (Object ob : obj) {
        System.out.print(ob + "~>");
    }
}

实际输出(与令牌的定义一致)

ABC~>DEF~>GHI~>JKL~>MNO~>

如果问题是:为什么这样定义了令牌?看看这个例子:

String str = "ABC DEF GHI"; // two spaces between

Stringtokenizer找到3个令牌。如果你不强制令牌非空,这将返回5个令牌(2个是&#34;&#34;)。如果你编写一个简单的解析器,那么当前的行为就更受欢迎了。

答案 1 :(得分:1)

你不能让StringTokenizer以你想要的方式工作(它永远不会返回空白),但你可以使用String#split()代替:

for (String token : str.split("~")) {
    // there will be a blank token where you expect it
}

此外,这段代码也简单得多。

答案 2 :(得分:0)

nextToken()方法调用skipDelimiter(int startPos)方法来查找下一个标记的索引。

/**
 * Skips delimiters starting from the specified position. If retDelims
 * is false, returns the index of the first non-delimiter character at or
 * after startPos. If retDelims is true, startPos is returned.
 */
private int skipDelimiters(int startPos)

因为~~之间没有字符串,所以行为是正确的。

文件还清楚地说:

StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead. 

答案 3 :(得分:0)

StringTokenizer有一个私有标志(returnDelims),默认为false。它是写的

如果returnDelims标志为true,则分隔符字符也将作为标记返回。每个分隔符都以长度为1的字符串形式返回。如果该标志为false,则跳过分隔符字符,仅用作标记之间的分隔符。

StringTokenizer有另一个用于为其设置值的构造函数。你应该为你的目的传递true到returnDelims标志,比如这个

    String str = "ABC~DEF~GHI~JKL~~MNO";// Input String
    final String token = "~";
    StringTokenizer stk = new StringTokenizer(str, token, true);
    Object[] obj = new Object[10];
    int i = 0;
    String lasToken = "";
    while (stk.hasMoreTokens()) {
        String nexToken = stk.nextToken();
        if (!token.equals(nexToken)) {
            obj[i] = nexToken;
            i++;
        } else if (token.equals(lasToken)) {
            i++;
        }
        lasToken = nexToken;
    }
    for (i = 0; i < obj.length; i++) {
        System.out.print(obj[i] + "~>");
    }