1. Introducción
En este tutorial, mostraremos cómo analizar un flujo de caracteres en tokens usando la clase Java StreamTokenizer .
2. StreamTokenizer
La clase StreamTokenizer lee el flujo carácter por carácter. Cada uno de ellos puede tener cero o más de los siguientes atributos: espacio en blanco, alfabético, numérico, comillas de cadena o carácter de comentario.
Ahora, debemos comprender la configuración predeterminada. Tenemos los siguientes tipos de personajes:
- Caracteres de palabras : rangos como 'a' a 'z' y 'A' a 'Z
- Caracteres numéricos : 0,1,…, 9
- Caracteres de espacio en blanco : valores ASCII de 0 a 32
- Carácter de comentario : /
- Caracteres de comillas de cadena : "y"
Tenga en cuenta que los extremos de las líneas se tratan como espacios en blanco, no como tokens separados, y los comentarios de estilo C / C ++ no se reconocen por defecto.
Esta clase posee un conjunto de campos importantes:
- TT_EOF : una constante que indica el final de la transmisión
- TT_EOL : una constante que indica el final de la línea
- TT_NUMBER : una constante que indica un token numérico
- TT_WORD : una constante que indica un token de palabra
3. Configuración predeterminada
Aquí, crearemos un ejemplo para comprender el mecanismo StreamTokenizer . Comenzaremos creando una instancia de esta clase y luego llamaremos al método nextToken () hasta que devuelva el valor TT_EOF :
private static final int QUOTE_CHARACTER = '\''; private static final int DOUBLE_QUOTE_CHARACTER = '"'; public static List streamTokenizerWithDefaultConfiguration(Reader reader) throws IOException { StreamTokenizer streamTokenizer = new StreamTokenizer(reader); List tokens = new ArrayList(); int currentToken = streamTokenizer.nextToken(); while (currentToken != StreamTokenizer.TT_EOF) { if (streamTokenizer.ttype == StreamTokenizer.TT_NUMBER) { tokens.add(streamTokenizer.nval); } else if (streamTokenizer.ttype == StreamTokenizer.TT_WORD || streamTokenizer.ttype == QUOTE_CHARACTER || streamTokenizer.ttype == DOUBLE_QUOTE_CHARACTER) { tokens.add(streamTokenizer.sval); } else { tokens.add((char) currentToken); } currentToken = streamTokenizer.nextToken(); } return tokens; }
El archivo de prueba simplemente contiene:
3 quick brown foxes jump over the "lazy" dog! #test1 //test2
Ahora, si imprimimos el contenido de la matriz, veríamos:
Number: 3.0 Word: quick Word: brown Word: foxes Word: jump Word: over Word: the Word: lazy Word: dog Ordinary char: ! Ordinary char: # Word: test1
Para comprender mejor el ejemplo, debemos explicar los campos StreamTokenizer.ttype , StreamTokenizer.nval y StreamTokenizer.sval .
El campo ttype contiene el tipo de token que se acaba de leer. Podría ser TT_EOF , TT_EOL , TT_NUMBER , TT_WORD . Sin embargo, para un token de cadena entre comillas, su valor es el valor ASCII del carácter de comillas. Además, si la ficha es un carácter ordinario como '!' , sin atributos, el ttype se completará con el valor ASCII de ese carácter.
A continuación, usamos el campo sval para obtener el token, solo si es un TT_WORD , es decir, un token de palabra. Pero, si estamos tratando con un token de cadena entre comillas, digamos "perezoso", entonces este campo contiene el cuerpo de la cadena.
Por último, usamos el campo nval para obtener el token, solo si es un token de número, usando TT_NUMBER .
4. Configuración personalizada
Aquí, cambiaremos la configuración predeterminada y crearemos otro ejemplo.
Primero, vamos a establecer algunos caracteres de palabras adicionales usando el método wordChars (int low, int hi) . Luego, haremos que el carácter de comentario ('/') sea normal y promocionaremos '#' como el nuevo carácter de comentario.
Finalmente, consideraremos el final de la línea como un carácter simbólico con la ayuda del método eolIsSignificant (bandera booleana) .
Solo necesitamos llamar a estos métodos en el objeto streamTokenizer :
public static List streamTokenizerWithCustomConfiguration(Reader reader) throws IOException { StreamTokenizer streamTokenizer = new StreamTokenizer(reader); List tokens = new ArrayList(); streamTokenizer.wordChars('!', '-'); streamTokenizer.ordinaryChar('/'); streamTokenizer.commentChar('#'); streamTokenizer.eolIsSignificant(true); // same as before return tokens; }
Y aquí tenemos una nueva salida:
// same output as earlier Word: "lazy" Word: dog! Ordinary char: Ordinary char: Ordinary char: / Ordinary char: / Word: test2
Tenga en cuenta que las comillas dobles se convirtieron en parte del token, el carácter de nueva línea ya no es un carácter de espacio en blanco, sino un carácter ordinario y, por lo tanto, un token de un solo carácter.
Además, los caracteres que siguen al carácter '#' ahora se omiten y el '/' es un carácter ordinario.
También podríamos cambiar el carácter de cita con el método quoteChar (int ch) o incluso los caracteres de espacio en blanco llamando al método whitespaceChars (int low, int hi) . Por lo tanto, se pueden realizar más personalizaciones llamando a los métodos de StreamTokenizer en diferentes combinaciones .
5. Conclusión
En este tutorial, hemos visto cómo analizar un flujo de caracteres en tokens usando la clase StreamTokenizer . Aprendimos sobre el mecanismo predeterminado y creamos un ejemplo con la configuración predeterminada.
Finalmente, cambiamos los parámetros predeterminados y nos dimos cuenta de lo flexible que es la clase StreamTokenizer .
Como de costumbre, el código se puede encontrar en GitHub.