Criando regex para arquivos csv

Gente tava tentando cria uma regex …
a ideia
seria

String[] camposDoArquivo = linhaDoArquivo.split(regex);

meu arquivo
esta no formato csv
ou seja

“informacoesDoCampo1”, " informacoesDoCampo2", “informacoesDoCampo3” , …
assim
camposDoArquivo[0] = informacoesDoCampo1
camposDoArquivo[1] = informacoesDoCampo2
camposDoArquivo[2] = informacoesDoCampo3

a expressao que eu tinha montado…::

([\"][^"]*[\"])

alguem pode me ajudar?
Abrçao

Olá!

Por que você não usa StringTokenizer?
Não serve neste caso?

Desculpa aí se estou esquecendo, mas:

String[] camposDoArquivo = linhaDoArquivo.split(","); 

Não é apenas isso?

[quote=CintiaDR]Desculpa aí se estou esquecendo, mas:

String[] camposDoArquivo = linhaDoArquivo.split(","); 

Não é apenas isso?[/quote]

Não; pense em um campo string que tenha vírgulas dentro. Por exemplo:

2.34, "R. dos Bobos, 0", 2008-09-23

Você pode ver que há uma vírgula dentro de um campo, a qual não deve ser usada para separar os campos. Split não leva isso em conta, e expressões regulares têm certa dificuldade de tratar tais casos.

Se o campo string contiver aspas dentro, então elas devem ser duplicadas. O segundo campo contém a string Frederico “Fred” Abranches. Em um arquivo CSV ela apareceria como:

2.34, "Frederico ""Fred"" Abranches", 2008-09-23

Outra coisa mais chata que aparece em arquivos CSV é que o Excel em português gera arquivos CSV separados por “;” e com os números de ponto flutuante usando vírgulas flutuantes. Algo como:

2,34 ; "América; Ásia; Oceania" ; 2009-12-10

Embora haja soluções para tratamento de arquivos CSV, se você simplesmente não quiser usar nada fora da biblioteca-padrão do Java, pode tentar usar a java.io.StreamTokenizer.

Oi de novo!

Segue um exemplo com StringTokenizer:

	public static void main(String args[])
	{
		String minhaString = "Eita string dificil de separar!";
		
		StringTokenizer tokenizer = new StringTokenizer(minhaString," "); // os espaços serão utilizados na quebra
		
		while(tokenizer.hasMoreTokens())
			System.out.println("String atual: " + tokenizer.nextToken());

	}

Espero ter ajudado…

StringTokenizer não cuida direito do caso em que há campos vazios, como em:

20,,3,56,"abcd",,dd

Nesse caso, StringTokenizer acaba “pulando” esse campo vazio. Se quiser usar alguma coisa que não pule campos vazios, e supor que em suas strings nunca vai aparecer uma vírgula (o que normalmente você não pode supor), use String.split com 2 parâmetros ( para o segundo, passe -1 ).

Huuuuuuuuum, entendi.

Obrigada =)

gente, mas como dito anteriormnente…
pode ser que um dos campos contenha a virgula
mas tenho certeza de que o campo n tem "…

ai utilizando o stringtokenizer ou o split…
separando p virgula, eu perco este campo…
por isso que pensei em criar uma exp reg

Vou dar um exemplo com StreamTokenizer daqui a pouco. É meio chatinho, mas pelo menos evita tais problemas de ter uma vírgula dentro.

consegui monta
a regex

ao invez de tenta escolhe a virgula

eu peguei “,” p dividir a string
String[] campos = linha.split("["][,]["]");

deu certinho…
o campos[0] vai ter um " na frente
e o
campos[ultimo] vai ter um " no final
ai e so tratar isso…

Eu falei tão bem do StreamTokenizer, mas ele tem alguns problemas com strings que contém aspas dentro (não tem com vírgulas dentro). Rode o programa abaixo, e veja o que estou falando.

import java.io.*;
import java.util.*;

class Cliente {
    private double valor1, valor2;
	private String endereco, nome;
	public Cliente() {}
	public Cliente (final double valor1_, final double valor2_, final String endereco_, final String nome_) {
	    valor1 = valor1_; valor2 = valor2_; endereco = endereco_; nome = nome_;
	}
	public void setValor1(final double valor1_) { valor1 = valor1_; }
	public void setValor2(final double valor2_) { valor2 = valor2_; }
	public void setEndereco(final String endereco_) { endereco = endereco_; }
	public void setNome(final String nome_) { nome = nome_; }
	public String toString() { return String.format ("[%.2f;%.2f;%s;%s]", valor1, valor2, endereco, nome); }
}

class TesteCSV {
    private static String quote (final String str) {
		StringBuilder sb = new StringBuilder();
		sb.append ("\"");
		for (int i = 0; i < str.length(); ++i) {
			final char ch = str.charAt (i);
		    if (ch == '\"') {
				sb.append ("\"");
			}
			sb.append (ch);
		}
		sb.append ("\"");
		return sb.toString();
	}
    public void gerarArquivo() {
	    PrintWriter pw = null;
	    try {
			pw = new PrintWriter(new BufferedWriter(new FileWriter ("teste.csv")));
			// Note que printf ("%.2f") imprime com vírgulas, não com pontos, o que é indesejável neste caso.
			// Portanto, iremos pôr um parâmetro adicional (Locale.US) para que ele imprima com pontos
			pw.printf ("valor1,valor2,rua,nome%n");
			pw.printf (Locale.US, "%.2f,%.2f,%s,%s%n", 2.34, 1002.45, quote ("R. dos Bobos, 0"), quote ("Frederico \"Fred\" Abranches"));
			pw.printf (Locale.US, "%.2f,%.2f,%s,%s%n", 105.35, -2334.47, quote ("R. da Amargura, 13"), quote ("James Ryan Gosling O'Malley"));
		} catch (IOException ex) {
		    ex.printStackTrace();
		} finally {
			pw.close();
		}
	}
	public void lerArquivo() {
		BufferedReader br = null;
		try {
			br = new BufferedReader (new FileReader ("teste.csv"));
			List<Cliente> clientes = new ArrayList<Cliente>();
			// A primeira linha contém apenas nomes
			br.readLine();
			for (String str = br.readLine(); str != null; str = br.readLine())
			{
				StringReader sr = new StringReader (str);
				StreamTokenizer st = new StreamTokenizer (sr);
				st.parseNumbers(); // necessário
				Cliente cli = new Cliente();
				int tokenType;
				tokenType = st.nextToken(); 
				if (tokenType == StreamTokenizer.TT_NUMBER)
					cli.setValor1 (st.nval);
				tokenType = st.nextToken(); // deve ser uma vírgula
				tokenType = st.nextToken();
				if (tokenType == StreamTokenizer.TT_NUMBER)
					cli.setValor2 (st.nval);
				tokenType = st.nextToken(); // deve ser uma vírgula
				tokenType = st.nextToken();
				if (tokenType == '\"' || tokenType == StreamTokenizer.TT_WORD)
					cli.setEndereco (st.sval);
				tokenType = st.nextToken(); // deve ser uma vírgula
				tokenType = st.nextToken();
				if (tokenType == '\"' || tokenType == StreamTokenizer.TT_WORD)
					cli.setNome (st.sval);
				clientes.add (cli);
			}
			System.out.println (clientes);
		} catch (IOException ex) {
		    ex.printStackTrace();
		} finally {
			if (br != null) try { br.close(); } catch (IOException ex) {}
		}
	}

    public static void main(String[] args) {
	    TesteCSV tc = new TesteCSV();
		tc.gerarArquivo();
		tc.lerArquivo();
	}
}