2009-10-28 8 views
25

Estoy procesando una cadena delimitada por tabulaciones. Estoy logrando esto usando la función split, y funciona en la mayoría de las situaciones. El problema ocurre cuando falta un campo, por lo que en lugar de obtener un valor nulo en ese campo, obtengo el siguiente valor. Estoy almacenando los valores analizados en una matriz de cadenas.Análisis sintáctico de cadenas en Java con la pestaña delíptica " t" mediante la división

String[] columnDetail = new String[11]; 
columnDetail = column.split("\t"); 

Cualquier ayuda sería apreciada. Si es posible, me gustaría almacenar las cadenas analizadas en una matriz de cadenas para que pueda acceder fácilmente a los datos analizados.

+0

Así 'campo1 \ tfield2 \ t \ tfield4' da que campo1, campo2, campo4 en lugar de campo1, campo2, [nulo], campo4? –

+3

http://stackoverflow.com/questions/1630092/token-parsing-in-java/1630110 ¿duplicado? Esto es lo que sucede cuando NO entiendes las respuestas y solo copias el código. –

+2

No necesita asignar una nueva matriz de cadenas. 'String.split' asigna uno nuevo de todos modos. – Joey

Respuesta

78

String.split usa Regular Expressions, tampoco necesita asignar una matriz extra para su división.

El método de división le dará una lista., el problema es que intenta predefinir cuántas veces tiene una pestaña, pero ¿cómo lo sabría realmente? Intente utilizar Scanner o StringTokenizer y aprenda cómo funcionan las cuerdas de división.

Déjeme explicar Why \ t does not y por qué necesita \\\\ para escapar \\.

Bien, entonces cuando usas Split, en realidad toma una expresión regular (expresión regular) y en la expresión regular quieres definir qué carácter dividir, y si escribes \ t eso en realidad no significa \t y qué QUIERES dividir por es \t, ¿verdad? Entonces, simplemente escribiendo \t le dice a su procesador de expresiones regulares que "hey dividido por el carácter que se escapó t" NO "Oye, dividido por todos los caracteres que se parecen a \t". Observe la diferencia? Usar \ significa escapar de algo. Y \ en expresiones regulares significa algo totalmente diferente de lo que piensas.

Así que esta es la razón por lo que necesita para utilizar este Solución:

\\t 

para decirle al procesador de expresiones regulares para buscar \ t. De acuerdo, ¿por qué necesitarías dos de ellos? Bueno, el primero \ escapa del segundo, lo que significa que se verá así: \ t cuando esté procesando el texto.

Ahora vamos a decir que usted está buscando para dividir \

Bueno, entonces se quedaría con \\ pero a ver, que no funciona! porque \ intentará escapar del char anterior! Es por eso que quiere que la salida sea \\ y, por lo tanto, debe tener \\\\.

Espero que los ejemplos anteriores te ayuden a entender por qué tu solución no funciona y cómo conquistar otras.

Ahora, ya te he dado este answer, quizás deberías empezar a buscarlos ahora.

OTROS MÉTODOS

StringTokenizer

Usted debe mirar en el StringTokenizer, es una herramienta muy útil para este tipo de trabajo.

Ejemplo

StringTokenizer st = new StringTokenizer("this is a test"); 
while (st.hasMoreTokens()) { 
    System.out.println(st.nextToken()); 
} 

Esta es la salida

this 
is 
a 
test 

utiliza el segundo Constructor para StringTokenizer para establecer el delimitador:

StringTokenizer(String str, String delim)

escáner

También es posible usar un Scanner como uno de los comentaristas dijo que esto podría ser algo como esto

Ejemplo

String input = "1 fish 2 fish red fish blue fish"; 

Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*"); 

System.out.println(s.nextInt()); 
System.out.println(s.nextInt()); 
System.out.println(s.next()); 
System.out.println(s.next()); 

s.close(); 

La salida sería

1 
2 
red 
blue 

Lo que significa que cortará la palabra "pez" y le dará el resto, usando "pez" como el delimitador.

examples taken from the Java API

+0

@Filip: ¡lindo! –

+2

Sin embargo, las expresiones regulares no deben morderle cuando se divide en una pestaña. – Joey

+1

Probablemente no, pero si el OP solo intentara leer las respuestas y entenderlas, ya sabría la respuesta a esto. Porque esto es similar a lo que publicó ayer. Diría que SI usó mi método ayer y hoy, no habría tenido este problema. –

4

String.split implementaciones tienen serias limitaciones si los datos de un campo delimitado por tabuladores en sí contiene nueva línea, pestaña y, posiblemente, "caracteres.

formatos delimitado por tabuladores han existido por años de burro, pero el formato no está estandarizado y varía. Muchas implementaciones no escapan a los caracteres (líneas nuevas y pestañas) que aparecen dentro de un campo. Más bien, siguen las convenciones CSV y envuelven los campos no triviales en "comillas dobles". Así que una "línea" podría extenderse sobre múltiples líneas.

Leyendo todo el texto escuché "solo reutilizar las herramientas de Apache", lo que parece un buen consejo.

Al final elegí personalmente opencsv. Lo encontré liviano, y dado que proporciona opciones para los caracteres de escape y comillas, debería cubrir los formatos de datos más populares delimitados por comas y tabuladores.

Ejemplo:

CSVReader tabFormatReader = new CSVReader(new FileReader("yourfile.tsv"), '\t'); 
15

Prueba esto:

String[] columnDetail = column.split("\t", -1); 

Leer el Javadoc en String.split(java.lang.String, int) para una explicación acerca del parámetro de límite de la función de división:

split 

public String[] split(String regex, int limit) 
Splits this string around matches of the given regular expression. 
The array returned by this method contains each substring of this string that is terminated by another substring that matches the given expression or is terminated by the end of the string. The substrings in the array are in the order in which they occur in this string. If the expression does not match any part of the input then the resulting array has just one element, namely this string. 

The limit parameter controls the number of times the pattern is applied and therefore affects the length of the resulting array. If the limit n is greater than zero then the pattern will be applied at most n - 1 times, the array's length will be no greater than n, and the array's last entry will contain all input beyond the last matched delimiter. If n is non-positive then the pattern will be applied as many times as possible and the array can have any length. If n is zero then the pattern will be applied as many times as possible, the array can have any length, and trailing empty strings will be discarded. 

The string "boo:and:foo", for example, yields the following results with these parameters: 

Regex Limit Result 
: 2 { "boo", "and:foo" } 
: 5 { "boo", "and", "foo" } 
: -2 { "boo", "and", "foo" } 
o 5 { "b", "", ":and:f", "", "" } 
o -2 { "b", "", ":and:f", "", "" } 
o 0 { "b", "", ":and:f" } 

Cuando el último pocos los campos (I guest that's your situation) faltan, obtendrá la columna como esta:

field1\tfield2\tfield3\t\t 

Si hay límite se establece para dividir(), el límite es 0, lo que llevará a que las "cadenas vacías se arrastran serán descartados". De modo que puede obtener solo 3 campos, {"campo1", "campo2", "campo3"}.

Cuando el límite se establece en -1, un valor no positivo, las cadenas vacías finales no se descartarán. Entonces puede obtener 5 campos con los dos últimos como cadena vacía, {"campo1", "campo2", "campo3", "", ""}.

+0

También debe explicar por qué su solución funciona (por ejemplo, cómo ayuda '-1 '). – brimborium

+0

¿Está bien ahora? Eso espero. Gracias por tu consejo. – Happy3

+0

@ Happy3: le diste un enlace a java1.4 doc. ¿No deberíamos referirnos a la última versión? :) – nir

6

Bueno, nadie contestó, lo cual es en parte culpa de la pregunta: la cadena de entrada contiene once campos (esto se puede inferir) pero ¿cuántas pestañas? La mayoría posiblemente exactamente 10. Entonces la respuesta es

String s = "\t2\t\t4\t5\t6\t\t8\t\t10\t"; 
String[] fields = s.split("\t", -1); // in your case s.split("\t", 11) might also do 
for (int i = 0; i < fields.length; ++i) { 
    if ("".equals(fields[i])) fields[i] = null; 
} 
System.out.println(Arrays.asList(fields)); 
// [null, 2, null, 4, 5, 6, null, 8, null, 10, null] 
// with s.split("\t") : [null, 2, null, 4, 5, 6, null, 8, null, 10] 

Si los campos pasan a contener pestañas esto no funcionará como se espera, por supuesto.
El medio -1: aplicar el patrón tantas veces como sea necesario, por lo que los campos posteriores (el 11º) se conservarán (como cadenas vacías ("") si están ausentes, que deben cambiarse a null explícitamente).

Si, por otro lado, no hay pestañas para los campos faltantes, entonces "5\t6" es una cadena de entrada válida que contiene los campos 5,6 solamente - no hay forma de obtener el fields[] mediante división.

+0

No está marcado como aceptado porque el OP nunca regresó al sitio después de hacer las preguntas. –

1

Acabo de recibir la misma pregunta y noté la respuesta en algún tipo de tutorial. En general es necesario utilizar la segunda forma del método de división, usando el

split(regex, limit)

Aquí está el tutorial completo http://www.rgagnon.com/javadetails/java-0438.html

Si establece un número negativo para el parámetro de límite obtendrá cadenas vacías en la matriz donde faltan los valores reales. Para usar esto, su cadena inicial debe tener dos copias del delimitador, es decir, debe tener \ t \ t donde faltan los valores.

Espero que esto ayude :)

Cuestiones relacionadas