代码之家  ›  专栏  ›  技术社区  ›  Neeraj Jain

字符串标记器的奇怪行为

  •  0
  • Neeraj Jain  · 技术社区  · 10 年前

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

        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 介于两者之间 Space 然后 StringTokenizer 跳过它并获取下一个令牌

    实际产量

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

    期望的中断

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

    为什么会发生这种情况?

    注:

    我知道我可以使用 String#split(String delimeter) 但是,我想知道奇怪行为的根本原因。

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

    4 回复  |  直到 4 年前
        1
  •  3
  •   CoronA    10 年前

    我想你用过 new StringTokenizer(str,"~")

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

    由于字符串介于 ~~ 为空,它不能是令牌(根据此定义)。

    我使用以下代码来验证:

    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个为“”)。如果您编写一个简单的解析器,那么当前的行为更可取。

        2
  •  1
  •   Bohemian    10 年前

    你做不到 StringTokenizer 按照你想要的方式工作(它从不返回空格),但你可以使用 String#split() 而是:

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

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

        3
  •  0
  •   Kedar Parikh    10 年前

    这个 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. 
    
        4
  •  0
  •   mehdinf    10 年前

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

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

    StringTokenizer有另一个用于设置值的构造函数

        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] + "~>");
        }