lunes, 25 de enero de 2010

Uso de StringTokenizer con varios caracteres separadores (Java)

Java
Todos hemos tenido que utilizar alguna vez StringTokenizer para separar subcadenas a partir de una cadena dada. Esto es muy sencillo si esas subcadenas son independientes entre sí. Pero ¿y si se organizan en forma "clave-valor"?. Por ejemplo, la siguiente cadena tiene la forma "jugador-deporte":

"Ronaldo=Futbol;Gasol=Baloncesto;Nadal=Tenis;Jordan=Baloncesto;"

Aquí tendríamos que tener en cuenta dos caracteres separadores: "=" y ";". Además, las subcademas habría que tratarlas teniendo en cuenta que las impares son nombres de deportistas y que las pares son nombres de deportistas. Lo mejor es que veamos un ejemplo:





El código



   import java.util.StringTokenizer;

   class PruebaST{

   static String entrada = "Ronaldo=Futbol;Gasol=Baloncesto;Nadal=Tenis;Jordan=Baloncesto;";

   public static void main(String args[]) {

   StringTokenizer st = new StringTokenizer(entrada, "=;");

   while(st.hasMoreTokens()) {

   String jugador = st.nextToken();

   String deporte = st.nextToken();

   System.out.println(jugador + " " + deporte);

   }

   }

   }





Resultado


La salida que daría ese código sería la siguiente:


   Ronaldo Futbol
   Gasol Baloncesto
   Nadal Tenis
   Jordan Baloncesto




50 Comentarios:

DrJekyll dijo...

amigo se puede hacer eso pero no perder los espacios ni comas, etc, lo que en realidad quiero hacer es dividir todo el contenido y guardarlo en un arreglo, incluidas las comas, dos puntos, parentecis, etc. pero separar las palabras de esos caracteres.

DrJekyll dijo...

ya está solucionado solo tenía q agregar la opción true al constructor:

StringTokenizer tokens = new StringTokenizer(linea, ":;()=><", true);

Felipe dijo...

Hola DrJekyll.

No me ha dado tiempo a contestarte. Efectivamente, poniendo el returnDelims a true, también te devuelve los caracteres separadores:

StringTokenizer(String str, String delim, boolean returnDelims)

Saludos.

Anónimo dijo...

hola nececito ordenar un temario
esta asi
1
1.1
1.1.1
1.1.2 y asi pero cuando llega al 1.1.10
me lo manda hasta debajo del 1.1
ejemplo:
1
1.1
1.1.10
1.1.1
1.1.2
como le hago para que los ponga en orden
es decir ue del 1.1.9
siga el 1.1.10 y no me lo mande abajo del 1.1

Felipe dijo...

Hola.

¿Qué método estás utilizando para ordenar los temas? Pon el código que estás utilizando e intentaré ayudarte.

Saludos.

Anónimo dijo...

Solo estoy utilizando solamente este método que es el que genera el temario.


private void generaTemario(AgregarContenidoTematicoForm form,
HttpServletRequest request) {

AgregarContenidoTematicoForm forma = (AgregarContenidoTematicoForm) form;
Map temario = new TreeMap();

if (request.getSession().getAttribute("Temario") != null) {
temario = (Map) request.getSession().getAttribute("Temario");
}

NuevoModuloForm unidad = new NuevoModuloForm();

if (Integer.valueOf(forma.getNivel()) == 1) {
StringTokenizer tokenAux = new StringTokenizer(forma.getNumero(),
"|");
String numeroUnidadAux2 = tokenAux.nextToken();
unidad.setCvePadre(numeroUnidadAux2);
}
if (Integer.valueOf(forma.getNivel()) == 2) {
StringTokenizer tokenAux = new StringTokenizer(forma
.getUnidadAprendizaje(), "|");
String numeroUnidadAux2 = tokenAux.nextToken();
unidad.setCvePadre(numeroUnidadAux2);
}
if (Integer.valueOf(forma.getNivel()) > 2) {
StringTokenizer tokenAux = new StringTokenizer(forma
.getResultadoAprendizaje(), "|");
String numeroUnidadAux2 = tokenAux.nextToken();
unidad.setCvePadre(numeroUnidadAux2);
unidad.setCvePadre(forma.getResultadoAprendizaje());

}
unidad.setNombreUnidad(forma.getDescripcion());
unidad.setNumeroUnidad(generaNumeroTema(forma, request) + "|");
unidad.setNivel(forma.getNivel());
unidad.setIndex(String.valueOf(temario.size()));
unidad.setModulo(forma.getModulo());


StringTokenizer tokenAux = new StringTokenizer(
unidad.getNumeroUnidad(), "|");
String numeroUnidadAux2 = tokenAux.nextToken();

StringTokenizer token = new StringTokenizer(numeroUnidadAux2, "|");
String numeroUnidadAux = token.nextToken();

unidad.setNombreCompleto(numeroUnidadAux + "."
+ unidad.getNombreUnidad());
unidad.setCveUnidad(forma.getUnidadAprendizaje());

// unidad.setNumeroUnidadAux(String.valueOf(convierteNumero(unidad.getNumeroUnidad())));
int numeroConvertido = convierteNumero(numeroUnidadAux
+ forma.getNivel());

temario.put(numeroConvertido, unidad);

request.getSession().setAttribute("Temario", temario);

}

Anónimo dijo...

por fa si alguien sabe como le puedo hacer digame me urge hacer eso porfa

Felipe dijo...

Buenas.

Mi solución sería la siguiente:

Partiría del argoritmo de ordenación por inserción:


public static void insertSort (int[] v) {
for (int i=1; i=0 && v[j]>aux; j--)
v[j+1] = v[j];
v[j+1] = aux;
}
}


Siendo v un vector que contiene los números del temario. Y sustituiría v[j]>aux; por comparar(v[j],aux). Siendo "comparar" un método que fuese capaz de comparar la numeración de los temarios. Así:

boolean b =comparar(num1,num2);

devolvería true si num1 fuese mayor que num2
devolvería false en caso contrario.

Éste método compararía el primer número antes del punto de num1 con num2, si es mayor devolvería true. Si es menor, devolvería false. Si es igual, tendría que seguir comparando con el siguiente número del temario.


Espero haberte ayudado.

Felipe dijo...

Otra alternativa, quizás más elegante, es implementar las interfaces Comparable y Comparador. Aquí tienes un ejemplo:

https://sites.google.com/site/apuntesdejava/Home/comparator-y-comparable

Anónimo dijo...

Lo que pasa esq estoy trabajando en web.Y los temas los inserto en orden.No entiendo porque en la pagina no me los muestra en el orden de como los fui insertando si ni siquiera tengo un metodo que los ordene. O ese ordenamiento lo hace por default?

Anónimo dijo...

lo que pasa es que lo que quiero ordenar no es un vector, ni un arreglo o lista. Son datos que inserto en la pagina web, es decir inserto un nuevo tema y cuando le doy guardar me manda a otra pagina donde se van mostrando los temas que inserto.

Felipe dijo...

Buenas.

Pero ¿datos de qué tipo? Supongo que serán String. ¿Cómo los insertas en la página?

Anónimo dijo...

Los datos son de tipo String.
Primero estoy en una pagina donde doy click en agregar nuevo tema.De ahi me aparece otra pagina donde lleno los campos del tema.Doy click en guardar y en ese momento se ejecuta el metodo "generar temario".Me regresa a la primer pagina y ahi es donde se van visualzando el tema que inserte.

Pero los temas los inserto de uno en uno, es decir ingreso uno y lo guardo, ingreso otro y lo guardo y asi sucesivamente.

Felipe dijo...

Hola.

Si no te importa, escríbeme a mi correo e intentaré ayudarte.

Saludos.

Anónimo dijo...

Hola, tengo un problema con este Tokenizer...
Es la primera vez que lo utilizo y necesito separar tres variables que me salen juntas porque están en un método....

(String idProducto,String nombreProducto, String descripcion)

Como hago para separarlos¿???????

Felipe dijo...

Hola.

Para separar las variables necesitarías un carácter separador. Si no, no hay forma de determinar donde acaba una y donde empieza otra. Muéstrame el código de ese método para que te pueda ayudar.

Saludos.

Anónimo dijo...

Muchas gracias me sirvio, saludos.

Felipe dijo...

Gracias a tí por comentar.

Saludos.

Anónimo dijo...

¿Como haria para hacer un programa que dada una cadena 12+14+3-8+5-4+1 haga toda esa operatoria. y la cadena siempre se le pueden agregar mas y mas numeros?

Felipe dijo...

Hola.

No lo he probado, pero si tenemos los tokens separados por espacios, así: "8 + 3 - 5 + 4" , haría ésto:




StringTokenizer st = new StringTokenizer(entrada, " ");

int total = Integer.parseInt (st.nextToken());

while(st.hasMoreTokens()) {

operacion = st.nextToken();

numero = Integer.parseInt(st.nextToken());

if (operacion=="+")
total = total + numero;

if (operacion=="-")
total = total - numero;

}


Espero que te sirva.

Saludos.

Kevin Leguizamon dijo...

Hola tengo que hacer un parseo de un .txt Primero tengo que leerlo y dsp hacer el parceo

ej: ponele que tengo asi en el txt

Mariano , Rodriguez , 20
Julian , Leguizamon, 30

Me tiene que salir:

Nombre:Mariano
Apellido: Rodriguez
Edad:20

y asi con el otro nombre.

Estoy perdido al momento de usas el tokenizer.

Gracias

Felipe dijo...

Hola Kevin.

Lo que tu pides sería algo así:


class PruebaST{

static String entrada; // Esta variable contiene la cadena de caracteres.

public static void main(String args[]) {

StringTokenizer st = new StringTokenizer(entrada, ",");

while(st.hasMoreTokens()) {

String nombre = st.nextToken();

String apellido = st.nextToken();

String edad = st.nextToken();



}

}

}


Para leer el archivo de texto desde la aplicación Java debes de utilizar

FileReader. Puedes ver un ejemplo aquí: http://lineadecodigo.com/java/leer-fichero-de-texto-con-java/


Saludos.

Anónimo dijo...

Buen Dia

SOy nuevo en Java y estoy corriendo el codigo expuesto...

Al momento de correrlo me dice que no reconoce la variable val

Gracias

nelcelco

Felipe Martínez D. dijo...

Hola Nelcelco.

Efectivamente, hay un error en el código que ya ha sido corregido. Hay que sustituir "val" por "deporte".

Un saludo y gracias por comentar.

Anónimo dijo...

Ches españoles weyes, el StringTokenizer ya no se debe usar, en lugar de eso usen split. Aquí les va la liga;

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/StringTokenizer.html

Felipe Martínez D. dijo...

Hola.

Efectivamente, en la documentación se indica que:

"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. "


Traduzco:

"StringTokenizer es una clase heredada que se mantiene por razones de compatibilidad, aunque su uso no se recomienda en el nuevo código. Se recomienda que cualquier persona que busque esta funcionalidad utilizar el método split de String o el paquete de java.util.regex lugar."


O sea, que se recomienda utilizar split para nuevo código, pero StringTokenizer no está "deprecated" u obsoleto, por tanto, puede seguir usándose sin problemas. Conclusión: se pueden utilizar los dos, aunque se recomienda usar split.



Saludos.

Anónimo dijo...

alguien puede ayudarme con esta practica, lo que necesito es insertar una cadena donde el mismo numero de paréntesis que abre es el numero de paréntesis que sierra para que diga cadena valida, de lo contrario diga cadena no valida


((()))= cadena valida
((())= cadena no valida

Felipe Martínez D. dijo...

Hola.

El código de lo que pides sería el siguiente:




 import java.util.StringTokenizer;

   class PruebaST{

   static String entrada = "(())";
  

   public static void main(String args[]) {

   StringTokenizer st = new StringTokenizer(entrada, ")",true);
   int i = st.countTokens();
  
   st = new StringTokenizer(entrada, "(",true);
   int j = st.countTokens();
  
   if(i==j)
       System.out.println("Cadena válida");
   else
       System.out.println("Cadena no válida");
  
   }

   }




La clave de ésto es la inicialización del objeto StringTokenizer:

StringTokenizer st = new StringTokenizer(entrada, ")",true);

El último parámetro al estar puesto a true, hace que el carácter separador no solo sirve para separar, sino que también forme parte de la cadena. Ésto nos permitirá contar el número de carartéres "(" y ")".

Espero que te haya servido.

jose albertto dijo...
Este comentario ha sido eliminado por el autor.
jose albertto dijo...

pero por ejemplo si tengo 23+20=0 no me separe el dos y el tres del numero 23

Felipe Martínez D. dijo...

Hola jose albertto.

No se exactamente cual es tu pregunta, pero supongo que quieres separar los números de los signos de operación. En ese caso debes fijar como tokens dichos signos. Así:
 StringTokenizer st = new StringTokenizer(entrada, "+=");

Saludos.

Anónimo dijo...

Hola que tal.
¿Como puedo identificar el ultimo token de una cadena en código?

Felipe Martínez D. dijo...

Hola.

Si estás utilizando el token ; se haría así:

String ultimoToken = cadena.substring(cadena.lastIndexOf(";") + 1);


Saludos.

Andrés Benítez dijo...

Un problema que no puedo solucionar:
la siguiente cadena de campos separados por | (pipe), no es interpretada correctamente por tokenizer.

"campo1||campo3|campo4||campo6"

tokenizer reconoce solo 4 tokens Y no se da cuenta de los que están con separador consecutivo.
Esto es un problema cuando tengo que asociar estos "token" a campos de una tabla, por ejemplo.
Ya que en los archivos de texto cuando se exportan datos de una base de datos, los campos nulos los envía, pero con el separador junto, en este caso "||".

Anónimo dijo...

Amigos, buenas tardes, tengo una pregunta que no se ha mencionado,¿como puedo usar separadores que no sean caracteres , sino palabras : tarjeta aula av avenida ?

Buenisimos los ejemplos ,escribo desde perú.

Felipe Martínez D. dijo...

Hola .

Andrés: Te sugeriría que antes de tratar la cadena sustituyas "||" por "|". De esta forma obviarás los caracteres nulos y no tendrás el problema que mencionas. Puedes utilizar el método replace(char oldChar, char newChar) ..

Anónimo: Puedes utilizar una palabra como separador, declarando esa palabra como separador, al igual que se declaran los caracteres.

Saludos cordiales.

Anónimo dijo...

Necesito hacer un programa en java que me separe palabras agudas graves esdrújulas y sobresdrújulas que me lea los acentos y las separaciones

Anónimo dijo...

alguien podría ayudarme

Felipe Martínez D. dijo...

Hola.

Desconozco si se puede hacer un programa para que separe palabras agudas esdrújulas y sobresdrújulas, ya que no existe un algoritmo que sea capaz determinar de qué tipo son.

Para leer los acentos, puedes utilizar como token las vocales acentuadas, al igual que con las separaciones:
StringTokenizer st = new StringTokenizer(entrada, "áéíóú ");

Saludos cordiales.

Unknown dijo...

Hola, estoy haciendo un comienzo de analizador lexico peroblo que no me sale es que cuando pongas un texto junto con un token por ejemplo hola{ este se separe Me podrias ayudar?
Nota: lo que se tiene que separar es lo dado por el usuario

Felipe Martínez D. dijo...

Hola.

No he entendido muy bien tu pregunta, pero lo que parece que quieres hacer es exactamente lo que se consigue con stringtokenizer. Prueba con el ejemplo de este post u otro cualquiera que haga uso de stringtokenizer. Si tienes dudas, puedes preguntarme.

Saludos.

Anónimo dijo...

Saludos soy Alejandra, quisiera saber como comparo un token con una variable string para hacer determinado proceso?

Felipe Martínez D. dijo...

Hola Alejandra.

Los tokens en este caso son de tipo String, así que puedes compararlos con tu variable como se comparan dos String. Puedes utilizar el método equals() .

Saludos.

Anónimo dijo...

como puedo hacer ingresada una cadena string por ejemplo
"hola como estas" me despliegue "estas como hola" seria que el tokenizer enpiece desde el ultimo ?? eso no se de ante mano gracias

Felipe Martínez D. dijo...

Hola.
Para hacer eso debes de utilizar un estructura de datos de tipo lifo (last in first out), es decir una pila (stack). Debes de insertar cada elemento (en este caso un string) mediante push. Luego los sacas mediante pop y saldrán en orden inverso al que entraron. Puedes ver un ejemplo aquí: http://www.javacoffeebreak.com/faq/faq0037.html .

Saludos.

Anónimo dijo...

Hola, Felipe mi nombre es María.

Lo que yo necesito es hacer un código para poner una coma entre cada caracter. Por ejemplo: yo tengo varios archivos de texto con este formato:

>AM406670.1 azoarcus sp. BH72, complete gameover
QWERREWQWWERRREEWEQEWWEEWRERERWWEEWRRQEWEEWEQRRQRQRWEEWRQEEWEWRRWEQEWERWRWRWEWEWRWREREQRWRWEWERRWEQRWEQRWEQRQRQRRRRRRRRWQRQRQRQRQRQRQRQRQRQRQRRQRQRQRQRQRQRQRQRRQWRQRQRWRWRRQRWRWRWRRQRQRWRWRRWRWRRQRRWRWRQRQRWRRWRWRWRWRWRWRWRRQRWRWRWQRRQ

Necesito hacer un solo archivo de texto quitando la primer linea de los archivos, poniendo una coma entre cada caracter, menos en el último. darle un número consecutivo a cada archivo, debe quedar así:
1=Q,W,E,R,R,E,W,Q,W,W,E,R,R,R,E,E,W,E,Q,E,W,W,E,E,W,R,E,R,E,R,W,W,E,E,W,R,R,Q,E,W,E,E,W,E,Q,R,R,Q,R,Q,R,W,E,E,W,R,Q,E,E,W,E,W,R,R,W,E,Q,E,W,E,R,W,R,W,R,W,E,W,E,W,R,W,R,E,R,E,Q,R,W,R,W,E,W,E,R,Q,R
2=Q,E,W,R,W,E,Q,W,E,Q,E,Q,E,R,W,R,W,E,Q,W,E,Q,E,Q,E,W,E,W,R,W,E,Q,W,E,Q,E,W,R,R,W,E,Q,E,Q,W,Q,W,Q,W,E,W,E,W,E,W,E,Q,R,R,Q,R,W,E,W,E,W,R,E,R,R,W,E,W,E,E,Q,E,Q,E,W,E,W,E,R,E,R,E,R,E,R,R,E,Q,E,Q,E,E,W,R,W
3=Q,E,W,R,W,E,Q,E,E,W,R,Q,E,W,R,W,E,R,W,E,Q,R,R,W,E,E,Q,E,E,E,E,E,E,E,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,R,W,E,W,E,W,R,W,R,E,R,R,W,E,E,W,E,W,E,W,E,W,E,W,E,E,W,E,W,E,W,R,Q,E,W,E,W,R,R,R,R,W,R,W,R,W,R,W,R,E

de todos los archivos debo hacer uno solo poniendo un numero, seguido del signo "=", separando cada letra por una coma solo el ultimo caracter de cada archivo no lleva la coma. y no tiene que haber espacios.

¿me podrás apoyar con esto?

Saludos!

Felipe Martínez D. dijo...

Hola María.

Para resolver lo que pides, yo lo haría en varios pasos:

1. Leer archivo y guardar el contenido en una variable de tipo String (fuente del ejemplo geekytheory.com):

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class LeerFichero {

public static void muestraContenido(String archivo) throws FileNotFoundException, IOException {
String cadena;
FileReader f = new FileReader(archivo);
BufferedReader b = new BufferedReader(f);
while((cadena = b.readLine())!=null) {
System.out.println(cadena);
}
b.close();
}

public static void main(String[] args) throws IOException {
muestraContenido("/home/mario/archivo.txt");
}

}

2. Convertir el String en un array de char:

char[] charArray = cadena.toCharArray();

3. Copiar el array de char a otro array de char intercalando el carácter ",":

int j=0;
for (int i=0; i<charArray.length; i++)
nuevoArray[j]=charArray[i];
j++;
nuevoArray[j]=",";
j++;
}



Esa sería la idea, si tienes alguna duda, pregúntame.

Saludos.

Nancy Lopez dijo...

hola que tal, muy buen aporte de antemano gracias por compartirlo. Tengo duda en como separar esta cadena:
frutasList.get(position - 1).getAlimento()+" = "+frutasList.get(position - 1).getCalorias()+" kcal"

Esta me entrega jicama = 20 kcal, yo solo quieo obtener el 20 que son las calorias, como las declaro, espero puedas apoyarme

ALMA NEREIDA MOLINA SUAREZ dijo...

Hola, como puedo hacer para que entre una palabra y una "," no se agregue un espacio. mi código es este:
StringTokenizer token = new StringTokenizer(entrada,",", true);
el resultado es este;
sol , luna , estrella.
y yo quiero que quede asi:
sol, luna, estrella

Felipe Martínez D. dijo...

Hola.

@Nancy Lopez: En tu caso los caracteres separadores serían "=" y "kcal". Pero hay un problema, stringtokenizer no permite utilizar separadores de más de un carácter y por tanto kcal no serviría como carácter separador. Tendrías que utilizar indexOf() y split(), para obtener la subcadena que tu necesitas. En el siguiente enlace se habla de este tema, si tienes alguna duda, dímelo:

https://www.experts-exchange.com/questions/20080818/How-do-I-use-a-delimiter-with-multiple-characters-in-a-StringTokenizer.html

@ALMA NEREIDA MOLINA SUAREZ: Puedes utilizar ésto: text.replace(" ,",",")


Saludos.


Publicar un comentario

Felinfo: Java, Linux, Virtualización. Open Source.  ©Template Blogger Green by Dicas Blogger .

TOPO