2009-05-10 18 views
5


Me pregunto si alguien me podría ayudar a encontrar la manera de analizar una cadena que tiene el siguiente formato:analizar una cadena que contiene caracteres de escape utilizando Java

;field1-field2-fieldN;field1-field2-fieldN; 

Cada registro está delimitado por ';' y cada campo dentro de un registro está delimitado por '-'. La complicación es que los campos individuales pueden contener caracteres delimitadores escapados como "\;" o "-". Esto hace que mi código de análisis simple a continuación falle. Entonces, lo que trato de hacer es encontrar expresiones regulares que coincidan con los delimitadores pero que no coincidan con los delimitadores que se han escapado. Mi conocimiento de expresiones regulares no es tan bueno, pero esperaba que haya una forma de combinar "([^ \;])" y "([;])" para obtener lo que necesito.

public static List<ParsedRecord> parse(String data) { 
    List<ParsedRecord> parsedRecords = new List<ParsedRecord>(); 
    String[] records = data.split(";"); 
    for (String record : records) { 
     String[] fields = data.split("-"); 
     parsedRecords.add(new parsedRecord(fields)); 
    } 
    return parsedRecords; 
} 

Muchas gracias de antemano.

Respuesta

7

tal vez podría refinar su expresión regular utilizada con split de esta manera:

split("[^\\];") 

Para dividir a todo lo que es un ";". pero no si antes hay una "\". Y lo mismo para los guiones:

split("[^\\]-") 
+0

Gracias! Usé una combinación de tu respuesta y la de Jon para que el analizador funcione. ¡Muy apreciado! –

+2

Esto no es del todo correcto ... la expresión regular definida anteriormente tendrá el carácter que precede al delimitador para ser eliminado también. Entonces "hola, mundo" se convierte en [infierno, mundo]. La mejor manera es usar el mecanismo de mirada negativa detrás de Regex: http://stackoverflow.com/questions/820172/how-to-split-a-comma-separated-string-while-ignoring-escaped-commas – Alvin

7

Es probable que sea mejor que realice el desempañado y la división en el mismo pase. Sé que se siente mal en términos de separar las dos piezas separadas de funcionalidad, pero evita algunos casos de esquina incómodos (imagine "foo \; bar" por ejemplo, donde; sigue una barra diagonal inversa pero sigue siendo un delimitador).

Aquí hay un código extremadamente simplista para hacer el análisis sintáctico: supone que cualquier barra invertida básicamente significa "tratar al siguiente carácter como entrada simple", pero eso es todo.

import java.util.*; 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     List<String> parsed = parse(args[0]); 
     for (String x : parsed) 
     { 
      System.out.println(x); 
     } 
    } 

    public static List<String> parse(String text) 
    { 
     List<String> ret = new ArrayList<String>(); 
     StringBuilder current = new StringBuilder(); 
     boolean escaping = false; 

     for (int i=0; i < text.length(); i++) 
     { 
      char c = text.charAt(i); 
      if (escaping) 
      { 
       current.append(c); 
       escaping = false; 
      } 
      else 
      { 
       if (c == '\\') 
       { 
        escaping = true; 
       } 
       else if (c == ';') 
       { 
        ret.add(current.toString()); 
        current = new StringBuilder(); 
       } 
       else 
       { 
        current.append(c); 
       } 
      } 
     } 
     if (escaping) 
     { 
      throw new IllegalArgumentException("Ended in escape sequence"); 
     } 
     ret.add(current.toString()); 
     return ret; 
    } 
} 

(Tenga en cuenta que esto no hace el negocio de la división de cada registro en múltiples campos, pero sólo había necesidad de cambiar lo que haces con ';' y también reaccionan a '-' - el principio es lo mismo)

Cuestiones relacionadas