StreamTokenizer разделяет 001_to_003 на два токена; как я могу предотвратить это? - PullRequest
1 голос
/ 12 ноября 2010

Java StreamTokenizer, кажется, слишком жадный в идентификации чисел. Это относительно легкий вариант конфигурации, и я не нашел способа заставить его делать то, что я хочу. Следующий тест проходит, IMO показывает ошибку в реализации; то, что я действительно хотел бы, чтобы второй токен был идентифицирован как слово "20001_to_30000". Есть идеи?

public void testBrokenTokenizer()
        throws Exception
{
    final String query = "foo_bah 20001_to_30000";

    StreamTokenizer tok = new StreamTokenizer(new StringReader(query));
    tok.wordChars('_', '_');       
    assertEquals(tok.nextToken(), StreamTokenizer.TT_WORD);
    assertEquals(tok.sval, "foo_bah");
    assertEquals(tok.nextToken(), StreamTokenizer.TT_NUMBER);
    assertEquals(tok.nval, 20001.0);
    assertEquals(tok.nextToken(), StreamTokenizer.TT_WORD);
    assertEquals(tok.sval, "_to_30000");
}

FWIW Я мог бы вместо этого использовать StringTokenizer, но это потребовало бы большого рефакторинга.

1 Ответ

0 голосов
/ 13 ноября 2010

IMO, лучшее решение - использовать сканер, но если вы хотите заставить почтенный StreamTokenizer работать на вас, попробуйте следующее:

import java.util.regex.*;
...

final String query = "foo_bah 20001_to_30000\n2.001 this is line number 2 blargh";

StreamTokenizer tok = new StreamTokenizer(new StringReader(query));

// recreate standard syntax table
tok.resetSyntax();
tok.whitespaceChars('\u0000', '\u0020');
tok.wordChars('a', 'z');
tok.wordChars('A', 'Z');
tok.wordChars('\u00A0', '\u00FF');
tok.commentChar('/');
tok.quoteChar('\'');
tok.quoteChar('"');
tok.eolIsSignificant(false);
tok.slashSlashComments(false);
tok.slashStarComments(false);
//tok.parseNumbers();  // this WOULD be part of the standard syntax

// syntax additions
tok.wordChars('0', '9');
tok.wordChars('.', '.');
tok.wordChars('_', '_');

// create regex to verify numeric conversion in order to avoid having
// to catch NumberFormatException errors from Double.parseDouble()
Pattern double_regex = Pattern.compile("[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?");

try {
    int type = StreamTokenizer.TT_WORD;

    while (type != StreamTokenizer.TT_EOF) {
        type = tok.nextToken();

        if (type == StreamTokenizer.TT_WORD) {
            String str = tok.sval;
            Matcher regex_match = double_regex.matcher(str);

            if (regex_match.matches()) {  // NUMBER
                double val = Double.parseDouble(str);
                System.out.println("double = " + val);
            }
            else {  // WORD
                System.out.println("string = " + str);
            }
        }
    }
}
catch (IOException err) {
    err.printStackTrace();
}

По сути, вы снимаете токенизацию числовыхзначения от StreamTokenizer.Соответствие регулярному выражению состоит в том, чтобы не полагаться на NumericFormatException, чтобы сказать вам, что Double.parseDouble () не работает на данном токене.

...