2010-11-12 59 views
1

Le StreamTokenizer de Java semble être trop gourmand pour identifier les numéros. Il est relativement léger sur les options de configuration, et je n'ai pas trouvé un moyen de le faire faire ce que je veux. Le test suivant passe, IMO montrant un bug dans l'implémentation; ce que j'aimerais vraiment, c'est que le second jeton soit identifié par un mot "20001_to_30000". Des idées?StreamTokenizer divise 001_to_003 en deux jetons; comment puis-je l'empêcher de le faire?

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 je pouvais utiliser un StringTokenizer à la place, mais il faudrait beaucoup de refactoring.

+1

Je suppose que c'est la raison pour laquelle la plupart des langues interdisent que le premier caractère des identifiants soit un nombre ... –

Répondre

0

OMI, la meilleure solution est d'utiliser un scanner, mais si vous voulez forcer le vénérable StreamTokenizer à travailler pour vous, procédez comme suit:

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(); 
} 

Essentiellement, vous déchargeant le tokenizing des valeurs numériques de StreamTokenizer. La correspondance de regex est d'éviter de s'appuyer sur NumericFormatException pour vous dire que Double.parseDouble() ne fonctionne pas sur le jeton donné.