Cómo determinar el delimitador en el archivo CSV

Univocity-parsers admite la detección automática del delimitador (también terminaciones de línea y comillas). Solo úsalo en lugar de pelear con tu código:

CsvParserSettings settings = new CsvParserSettings();
settings.detectFormatAutomatically();

CsvParser parser = new CsvParser(settings);
List<String[]> rows = parser.parseAll(new File("/path/to/your.csv"));

// if you want to see what it detected
CsvFormat format = parser.getDetectedFormat();

Descargo de responsabilidad: soy el autor de esta biblioteca y me aseguré de cubrir todo tipo de casos de esquina. Es de código abierto y gratuito (licencia Apache 2.0)

Espero que esto ayude.

Respuesta 1

Sí, pero solo si no se permite que los caracteres delimitadores existan como texto normal

La respuesta más simple es tener una lista con todos los caracteres delimitadores disponibles e intentar identificar qué carácter se está utilizando. Sin embargo, debe colocar algunas limitaciones en los archivos o en la persona / personas que los crearon. Mire los siguientes dos escenarios:

Caso 1 - Contenido de file.csv

test,test2,test3

Caso 2 - Contenido de file.csv

test1|test2,3|test4

Si tiene conocimiento previo de los caracteres delimitadores, entonces dividiría la primera cadena usando ,y la segunda usando |, obteniendo el mismo resultado. Pero, si intenta identificar el delimitador analizando el archivo, ambas cadenas se pueden dividir usando el ,carácter, y terminaría con esto:

Caso 1 - Resultado de la división usando ,

test1
test2
test3

Caso 2 - Resultado de la división usando ,

test1|test2
3|test4

Al no tener el conocimiento previo de qué carácter delimitador se está utilizando, no puede crear un algoritmo "mágico" que analice cada combinación de texto; incluso las expresiones regulares o contar el número de apariciones de un personaje no te salvarán.

Peor de los casos

test1,2|test3,4|test5

Al mirar el texto, se puede tokenizar usando |como delimitador. Pero la frecuencia de aparición de ambos ,y |son los mismos. Entonces, desde la perspectiva de un algoritmo, ambos resultados son precisos:

Resultado correcto

test1,2
test3,4
test5

Resultado incorrecto

test1
2|test3
4|test5

Si plantea un conjunto de pautas o puede controlar de alguna manera la generación de los archivos CSV, entonces puede intentar encontrar el delimitador utilizado con el String.contains()método, empleando la lista de caracteres antes mencionada. Por ejemplo:

public class MyClass {

    private List<String> delimiterList = new ArrayList<>(){{
        add(",");
        add(";");
        add("\t");
        // etc...
    }};

    private static String determineDelimiter(String text) {
        for (String delimiter : delimiterList) {
            if(text.contains(delimiter)) {
                return delimiter;
            }
        }
        return "";
    }

    public static void main(String[] args) {
        String csvFile = "/Users/csv/country.csv";
        String line = "";
        String cvsSplitBy = ",";
        String delimiter = "";
        boolean firstLine = true;
        try (BufferedReader br = new BufferedReader(new FileReader(csvFile)))  {
            while ((line = br.readLine()) != null) {
                if(firstLine) {
                    delimiter = determineDelimiter(line);
                    if(delimiter.equalsIgnoreCase("")) {
                        System.out.println("Unsupported delimiter found: " + delimiter);
                        return;
                    }
                    firstLine = false;
                }
                // use comma as separator
                String[] country = line.split(delimiter);
                System.out.println("Country [code= " + country[4] + " , name=" + country[5] + "]");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Actualizar

Para una forma más optimizada, en el determineDelimiter()método en lugar del for-eachbucle, puede emplear expresiones regulares.

Respuesta: 2

Si el delimitador puede aparecer en una columna de datos, está pidiendo lo imposible. Por ejemplo, considere esta primera línea de un archivo CSV:

one,two:three

Esto podría ser un archivo separado por comas o con dos puntos. No se puede saber de qué tipo es.

Si puede garantizar que la primera línea tiene todas sus columnas rodeadas de comillas, por ejemplo, si siempre es este formato:

"one","two","three"

entonces puede utilizar esta lógica (aunque no es 100% a prueba de balas):

if (line.contains("\",\""))
    delimiter = ',';
else if (line.contains("\";\""))
    delimiter = ';';

Si no puede garantizar un formato restringido como ese, entonces sería mejor pasar el carácter delimitador como parámetro.

Luego, puede leer el archivo utilizando un analizador CSV de código abierto ampliamente conocido como Apache Commons CSV .

Respuesta: 3

Agregue una condición como esta,

String [] country;
if(line.contains(",")
    country = line.split(",");
else if(line.contains(";"))
    country=line.split(";");
Respuesta: 4

Tengo un problema que creo que sería perfecto para transmisiones y / o lambdas. Por otro lado, no quiero complicar demasiado esto, pero ya que usaré esta técnica específica en muchas variaciones (ejecutar ...

Me gustaría utilizar una colección java única que pueda aceptar una estrategia para determinar si los objetos miembros son "iguales" en la inicialización de la colección. La razón por la que necesito hacer esto es porque los iguales ...

Me gustaría hacer una consulta en PostgreSQL select distinto en (uuid) (seleccione nr_zew de bo_get_sip_cti_polaczenie_info (uuid)) como nr_zew de bo_sip_cti_event_day donde data_ins :: date = ...

Estoy usando una fuente personalizada en mi proyecto de Android. Por alguna razón, cuando el texto incluye las letras IJ juntas, me da el siguiente glifo: Este parece ser el glifo ubicado en \ uE2C5 del ...