2012-05-22 52 views
7

Quiero dividir una cadena con un espacio en blanco delimitador. pero debe manejar cadenas citadas inteligentemente. P.ej. para una cadena comoDividir una cadena entre comillas con un delimitador

"John Smith" Ted Barry 

Debería devolver tres cuerdas John Smith, Ted y Barry.

+2

Probablemente necesite dividir primero las comillas entrecomilladas, luego dividir el resto de la cadena por espacios en blanco. Debe haber algunas preguntas aquí acerca de cómo hacer el primer paso. El segundo paso es trivial. – jahroy

+1

¿Y qué has intentado? –

+2

Una decente biblioteca de analizadores CSV funcionaría bien para usted. La mayoría permitirá la selección del delimitador y respetará y evitará dividir el texto entre comillas. –

Respuesta

10

Después de jugar con eso, puede usar Regex para esto. Ejecutar el equivalente a "coincidir con todos" en:

((?<=("))[\w ]*(?=("(\s|$))))|((?<!")\w+(?!")) 

Un ejemplo de Java:

import java.util.regex.Pattern; 
import java.util.regex.Matcher; 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     String someString = "\"Multiple quote test\" not in quotes \"inside quote\" \"A work in progress\""; 
     Pattern p = Pattern.compile("((?<=(\"))[\\w ]*(?=(\"(\\s|$))))|((?<!\")\\w+(?!\"))"); 
     Matcher m = p.matcher(someString); 

     while(m.find()) { 
      System.out.println("'" + m.group() + "'"); 
     } 
    } 
} 

Salida:

'Multiple quote test' 
'not' 
'in' 
'quotes' 
'inside quote' 
'A work in progress' 

El desglose de expresiones regulares con el ejemplo utilizado anteriormente se puede ver aquí :

http://regex101.com/r/wM6yT9


Con todo lo dicho, las expresiones regulares no deberían ser la solución para todo: me estaba divirtiendo. Este ejemplo tiene muchos casos extremos, como el manejo de caracteres Unicode, símbolos, etc. Sería mejor utilizar una biblioteca probada y verdadera para este tipo de tareas. Eche un vistazo a las otras respuestas antes de usar esta.

+0

No estoy seguro de si la entrada contiene Unicode o no, pero su código no podrá para manejarlo – nhahtdh

+0

este es un buen ejemplo. +1, ¿por qué no pones un if para comprobar si m.group() devuelve un espacio en blanco, de esa manera no tienes que dar salida a los espacios en blanco. –

+0

Brilliant ... +1 –

4

Prueba este feo bit de código.

String str = "hello my dear \"John Smith\" where is Ted Barry"; 
    List<String> list = Arrays.asList(str.split("\\s")); 
    List<String> resultList = new ArrayList<String>(); 
    StringBuilder builder = new StringBuilder(); 
    for(String s : list){ 
     if(s.startsWith("\"")) { 
      builder.append(s.substring(1)).append(" "); 
     } else { 
      resultList.add((s.endsWith("\"") 
        ? builder.append(s.substring(0, s.length() - 1)) 
        : builder.append(s)).toString()); 
      builder.delete(0, builder.length()); 
     } 
    } 
    System.out.println(resultList);  
+0

Mucho mejor que mi código. +1 –

+0

El espacio en blanco excesivo hará que el programa genere cadenas vacías. – nhahtdh

+0

@nhahtdh: O'yeah. Acabo de dar una pista, en realidad. No es una solución al 100% de trabajo. Trevor Senior, lo clavó bien. Eso también tiene un mismo problema de espacios en blanco. Pero eso no es un problema real y se puede solucionar fácilmente. –

1

commons-lang tiene una clase StrTokenizer a hacer esto para usted, y también hay biblioteca de java-csv.

Ejemplo con StrTokenizer:

String params = "\"John Smith\" Ted Barry" 
// Initialize tokenizer with input string, delimiter character, quote character 
StrTokenizer tokenizer = new StrTokenizer(params, ' ', '"'); 
for (String token : tokenizer.getTokenArray()) { 
    System.out.println(token); 
} 

Salida:

John Smith 
Ted 
Barry 
+0

@BasilioGerman Agregué un ejemplo para que pueda considerar eliminar su comentario. –

3

bien, hice una pequeña snipet que hace lo que quiere y algunas cosas más. ya que no especificó más condiciones, no tuve problemas. Sé que esto es una manera sucia y probablemente puedas obtener mejores resultados con algo que ya está hecho. pero para la diversión de la programación aquí está el ejemplo:

String example = "hello\"John Smith\" Ted Barry lol\"Basi German\"hello"; 
    int wordQuoteStartIndex=0; 
    int wordQuoteEndIndex=0; 

    int wordSpaceStartIndex = 0; 
    int wordSpaceEndIndex = 0; 

    boolean foundQuote = false; 
    for(int index=0;index<example.length();index++) { 
     if(example.charAt(index)=='\"') { 
      if(foundQuote==true) { 
       wordQuoteEndIndex=index+1; 
       //Print the quoted word 
       System.out.println(example.substring(wordQuoteStartIndex, wordQuoteEndIndex));//here you can remove quotes by changing to (wordQuoteStartIndex+1, wordQuoteEndIndex-1) 
       foundQuote=false; 
       if(index+1<example.length()) { 
        wordSpaceStartIndex = index+1; 
       } 
      }else { 
       wordSpaceEndIndex=index; 
       if(wordSpaceStartIndex!=wordSpaceEndIndex) { 
        //print the word in spaces 
        System.out.println(example.substring(wordSpaceStartIndex, wordSpaceEndIndex)); 
       } 
       wordQuoteStartIndex=index; 
       foundQuote = true; 
      } 
     } 

     if(foundQuote==false) { 
      if(example.charAt(index)==' ') { 
       wordSpaceEndIndex = index; 
       if(wordSpaceStartIndex!=wordSpaceEndIndex) { 
        //print the word in spaces 
        System.out.println(example.substring(wordSpaceStartIndex, wordSpaceEndIndex)); 
       } 
       wordSpaceStartIndex = index+1; 
      } 

      if(index==example.length()-1) { 
       if(example.charAt(index)!='\"') { 
        //print the word in spaces 
        System.out.println(example.substring(wordSpaceStartIndex, example.length())); 
       } 
      } 
     } 
    } 

esto también comprueba si hay palabras que no fueron separados con un espacio antes o después de las comillas, como por ejemplo las palabras "hola" antes de "John Smith" y después de "Basi alemán".

cuando la cadena se modifica para "John Smith" Ted Barry la salida es de tres cuerdas, 1) "John Smith" 2) Ted 3) Barry

La cadena en el ejemplo es hola "John Smith" Ted Barry lol "Basi alemán" hola y grabados 1) hola 2) "John Smith" 3) Ted 4) Barry 5) lol 6) "Basi alemán" 7) hola

creo que sirve

+1

Este es el mejor código entre todos estos. Puede encargarse de la entrada Unicode y no genera cadenas vacías cuando hay espacios excesivos. Mantendrá intacto todo dentro de la cita (bueno, esto puede ser un más o un menos). Creo que el código se puede modificar un poco para eliminar las comillas. La expansión adicional puede ser: agregar soporte para la comilla escapada. – nhahtdh

+0

Claro, las citas se pueden quitar. solo lo logré en pupose para guardar las citas. He añadido comentarios sobre dónde eliminar las comillas. –

1

Esta es mi propia versión, limpiar desde http://pastebin.com/aZngu65y (publicado en el comentario). Puede ocuparse de Unicode. Limpiará todos los espacios excesivos (incluso en el presupuesto); esto puede ser bueno o malo dependiendo de la necesidad. No hay soporte para la cita escapada.

private static String[] parse(String param) { 
    String[] output; 

    param = param.replaceAll("\"", " \" ").trim(); 
    String[] fragments = param.split("\\s+"); 

    int curr = 0; 
    boolean matched = fragments[curr].matches("[^\"]*"); 
    if (matched) curr++; 

    for (int i = 1; i < fragments.length; i++) { 
    if (!matched) 
     fragments[curr] = fragments[curr] + " " + fragments[i]; 

    if (!fragments[curr].matches("(\"[^\"]*\"|[^\"]*)")) 
     matched = false; 
    else { 
     matched = true; 

     if (fragments[curr].matches("\"[^\"]*\"")) 
     fragments[curr] = fragments[curr].substring(1, fragments[curr].length() - 1).trim(); 

     if (fragments[curr].length() != 0) 
     curr++; 

     if (i + 1 < fragments.length) 
     fragments[curr] = fragments[i + 1]; 
    } 
    } 

    if (matched) { 
    return Arrays.copyOf(fragments, curr); 
    } 

    return null; // Parameter failure (double-quotes do not match up properly). 
} 

de entrada de muestra para la comparación:

"sdfskjf" sdfjkhsd "hfrif ehref" "fksdfj sdkfj fkdsjf" sdf sfssd 


asjdhj sdf ffhj "fdsf fsdjh" 
日本語 中文 "Tiếng Việt" "English" 
    dsfsd  
    sdf  " s dfs fsd f " sd f fs df fdssf "日本語 中文" 
"" ""  "" 
" sdfsfds " "f fsdf 

(segunda línea está vacía, tercera línea es espacios, última línea es incorrecto). Por favor juzgue con su propio resultado esperado, ya que puede variar, pero la línea de base es eso, el primer caso debería devolver [sdfskjf, sdfjkhsd, hfrif ehref, fksdfj sdkfj fkdsjf, sdf, sfssd].

Cuestiones relacionadas