Ler CSV, delimitar e atualizar parte da linha do CSV

Boa tarde Pessoal,

Seguinte, estou com alguns probleminhas aqui. Tenho um arquivo em CSV de tradução e estou criando a integração com a api Google Tradutor(haha, infelizmente tem que pagar essa meleca, mais fazer o que!!) para traduzir determinados termos deste CSV. Eu preciso ler ele e fazer algumas alterações.

Basicamente, cada linha tem uma palavra ou frase em inglês seguido de uma virgula e o mesmo termo em inglês, como abaixo.

Active,Active

O que tenho que fazer é pegar a segunda palavra, jogar numa variável para que eu possar chamar um método, que tenho quase pronto aqui, que ira receber uma string e passar para o Google traduzir, e ele deverá retornar a string traduzida e atualizar o csv.
O grande problema é:

  • Como ler cada linha do CSV
  • Como pegar a segunda palavra ou frase, inserir numa variável(para que assim eu possa chamar o meu método traduzir)
  • E como pegar o retorno do método(isso eu sei fazer) e atualizar(isso não consegui bolar a logica para isso) a linha com o termo traduzido(A linha deverá ficar, no exemplo acima, desta maneira: Active, Ativo)

Outros problemas a se considerar são que há duas variações de linhas, como no exemplo abaixo:

  • Possuem aspas duplas nos termos, mais continuam sendo separados por virgula como no exemplo acima
    “Add Banner”,“Add Banner”

  • Frases que tem virgula, neste caso, sempre se usa aspas duplas em cada termo
    “Hello, Welcome”,“Hello, Welcome”

Pela minha ideia, a logica seria mais ou menos assim(meu teste de mesa - é meio doido mesmo :shock: ):

START_LOOP

SE (LINHA NAO COMECAR POR ASPAS DUPLAS)
{
PERCORRER LINHA ATE ENCONTRAR UM VIRGULA E SEPARAR O QUE ELE ENCONTROU ANTES E DEPOIS EM DUAS VARIAVEIS TEMPORARIAS(var1 E var2)
CRIAR VARIAVEL TEMPORARIA (var3)
ARMAZENAR O RETORNO DO METODO TRADUZIR NA var3 [OBS: metodo traduzir passa como paramento a var2]
APAGAR TODO O CONTEUDO DA LINHA EM QUESTAO
PREENCHER A LINHA COM var1 + “,” + var3

}
SENAO SE(LINHA COMECAR POR ASPAS DUPLAS)
{
PERCORRER LINHA ATE ENCONTRAR “,” (ASPAS VIRGULA ASPAS) E SEPARAR O QUE ELE ENCONTROU ANTES E DEPOIS EM DUAS VARIAVEIS TEMPORARIAS(var1 E var2)
CRIAR VARIAVEL TEMPORARIA (var3)
RETIRAR A ASPA QUE FICOU NO INICIO DA var1 COM REPLACE
RETIRAR A ASPA QUE FICOU NO FINAL DA var2 COM REPLACE
ARMAZENAR O RETORNO DO METODO TRADUZIR NA var3 [OBS: metodo traduzir passa como paramento a var2]
APAGAR TODO O CONTEUDO DA LINHA
PREENCHER A LINHA COM " " " + var1 + " " , " " + var3 + " " "
}

END_LOOP

Agora como implementar, principalmente a parte de cortar a linha de acordo com o paramentro ou como apagar uma determinada linha e preencher ela de novo no csv, de forma a atualizar ele, é que não sei.

Qualquer dúvida, estou a disposição.

1 curtida

Fala alex.willian!

Cara, seu problema é simples!

para ler linha a linha de um arquivo é simples:

FileReader fFeader = new FileReader(new File("i18n.txt"));
BufferedReader buffReader = new BufferedReader(fReader);
String line = null;
while((line = buffReader.readLine())) {  
    System.out.println("Linha: " + line);  
}
buffReader.close();  
fReader.close();

no caso da virgula, vc pode quebrá-la com o metodo .split() da propria string line:

String dic[] = line.split(",");
System.out.println("Parte em ingles: " + dic[1]);

e no caso das palavras com “aspas”, vc pode usar expressão regular para tratar isso :smiley: tranquilo tranquilo

vai pensando ai… bola um esboço do script e vai postando aqui que eu vou te ajudando, mas por enquanto, foca em como ler o seu arquivo e usar regex para tratar as aspas.
depois a gente passa para a gravação blz?

Como ele vai dar um split dessa linha: “Hello, Welcome”,“Hello, Welcome” ?

Vou te mandar um código bem louco já que eu não sei usar muito bem regex…

Se alguém puder mandar um código com tratamento por regex de acordo com o problema que eu citei acima seria muito legal.

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TesteSplit {

	public static void main(String[] args) throws IOException {
		
		// Apenas para testes
		Map<String, String> mapaTraducao = new HashMap<String, String>();
		mapaTraducao.put("Hi, Welcome", "Olá, Bem vindo");
		mapaTraducao.put("Word", "Palavra");
		mapaTraducao.put("Hello man", "Olá cara");
		mapaTraducao.put("Wtf", "Mas que PIIII");

		BufferedReader br = new BufferedReader(new FileReader(new File("teste.csv")));
		
		String linha;
		while ((linha = br.readLine()) != null) {
			String vetor[] = analisaLinha(linha);
			imprimeVetor(vetor);
			System.out.println();
			
			// TODO Método para analisar os indices do vetor e efetuar a tradução
			
			if (mapaTraducao.containsKey(vetor[0])) {
				System.out.print("["+vetor[0]+"]");
				System.out.print("["+mapaTraducao.get(vetor[0])+"]");
			}
			System.out.println();
			
		}

	}

	private static String[] analisaLinha(String linha) {
		if (linha.contains("\"")) {
			char vetorCaractere[] = linha.toCharArray();
			StringBuffer sb = new StringBuffer();
			boolean processaFrase = false;
			List<String> frases = new ArrayList<String>();
			for (char c : vetorCaractere) {
				if (c == '\"') {
					if (processaFrase == false)
						processaFrase = true;
					else
						processaFrase = false;

				}
				
				if (processaFrase) {
					if (c != '\"') {
						sb.append(c);
						
					}
					
				} else {
					if (sb.toString().length() > 0) {
						frases.add(sb.toString());
						sb = new StringBuffer();
						
					}
				}
			}
			return converteList2StringArray(frases);
		} else {
			String vetorS[] = linha.split(",");
			for (int i=0;i<vetorS.length;i++)
				vetorS[i] = vetorS[i].trim();
			
			return vetorS;
		}
	}

	private static String[] converteList2StringArray(List<String> frases) {
		Object vetorO[] = frases.toArray();
		String vetorS[] = new String[frases.size()];
		for (int i=0;i<frases.size();i++)
			vetorS[i] = (String) vetorO[i];
			
		return vetorS;
	}
	
	private static void imprimeVetor(String[] vetor) {
		for (String s : vetor)
			System.out.print("["+s+"]");
		
	}
}

Com Expressão Regular!!! :smiley:

é impressionante a quantidade de código que a gente economiza utilizando elas né?! :stuck_out_tongue:

Duvida de mim? então compila esse código:

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

public class Tradutor {

    // Essa expressao regular casa todas as linhas que tiverem 2 sentenças com virgula dentro delas
    // e que essas 2 sentenças estejam separadas por uma virgula
    private static final String REGEX = " *(\".*?\") *, *(\".*?\") *";
    private static final String MSG = "\npt_br: %s | en_us: %s";
    private static final String SPLITTER = ",";
    
    public static void main(String[] args) {
        FileReader fileReader;
        BufferedReader bufferedReader;
        String line, arr[];
        
        // compila a expressao regular
        Pattern p = Pattern.compile(REGEX);
        Matcher m;
        
        try {
            // Carrega arquivo
            fileReader = new FileReader(new File("I18N.csv"));
            bufferedReader = new BufferedReader(fileReader);

            // executa enquanto houver linhas
            while ((line = bufferedReader.readLine()) != null) {
                // Cria um objeto responsavel por casar a regex com a linha corrente
                m = p.matcher(line);
                
                // verifica se é possivel casar a regex com a linha
                if(m.matches()) {
                    System.out.printf(MSG, m.group(1), m.group(2));
                } else {
                    // se nao houve casamento, significa que não há virgula dentro das sentenças
                    // entao usa-se um split normal
                    arr = line.split(SPLITTER);
                    System.out.printf(MSG, arr[0], arr[1]);
                }
            }
            
            // fecha os readers com segurança
            bufferedReader.close();
            fileReader.close();
        } catch (FileNotFoundException ex) {
            System.out.print(ex.getMessage());
        } catch (IOException ex) {
            System.out.print(ex.getMessage());
        }
    }
}

e olha o arquivo que usei como entrada (“I18N.csv”):
tem linhas com “aspas” e com virgula dentro
e linhas sem aspas, mas sem virgula tambem né :lol:

Adicionar Banner,Add Banner
"Ola, Bem Vindo","Hello, Welcome"
"Teste com espaco entre a ,,,"    , " ,,, , , , ,"
        "comeco da linha tem espaco",      "mais espacos entre a virgula que separa as sentencas .,.,."
 "vamo enfiar mais caracteres aqui alem da ,,,,","nao tem problemaaaaa"
 agora sem as aspas,mas nao pode ter virgulas aqui
 sem aspas a regex nao casa,e ai tem que usar o split normal mesmo

coloque o arquivo no mesmo diretório corrente do seu projeto e roda!

vai ver que funciona!!

essa foi a resposta que tive do programa rodando no netBeans:

[quote]run:

pt_br: “Adicionar Banner” | en_us: “Add Banner”
pt_br: “Ola, Bem Vindo” | en_us: “Hello, Welcome”
pt_br: “Teste com espaco entre a ,” | en_us: " , , , , ,"
pt_br: “comeco da linha tem espaco” | en_us: “mais espacos entre a virgula que separa as sentencas .,.,.”
pt_br: “vamo enfiar mais caracteres aqui alem da ,” | en_us: “nao tem problemaaaaa”
pt_br: agora sem as aspas | en_us: mas nao pode ter virgulas aqui
pt_br: sem aspas a regex nao casa | en_us: e ai tem que usar o split normal mesmo[/quote]

alex.willian

veja o código que postei acima, o que vc precisa fazer agora é se concentrar nas linhas 34 e 39 como vc mesmo diz na citação abaixo!!

o código acima te dá a segunda palavra!!!

proximo passo é gravar de volta o arquivo CSV :smiley:

e ai? quer tentar postar um esboço do seu código ou o pessoal aqui pode continuar te dando ideias?

Acho isso um desafio legal para vc agora que já tem metade do que precisava:

[quote]- Como ler cada linha do CSV

  • Como pegar a segunda palavra ou frase, inserir numa variável(para que assim eu possa chamar o meu método traduzir)[/quote]

alex.willian

porque em vez de usar arquivo CSV você não usa um .properties da vida mesmo???

ai vc não tem que se preocupar com nada do que postamos acima, porque o java já tem classes prontas que fazem tudo isso que vc ta querendo em poucas linhas de código :smiley:

pensa bem…

arquivo.properties não seria melhor?

ou que tal um XML???

e não seja ingrato, não esqueça de dar feedback para o pessoal aqui do forum hen?! :lol:

Eu não estava com dúvida de você cara, eu realmente queria que alguém postasse algum código com regex por que eu também queria saber…

Bom dia Galera,

Obrigado pelo feedback, ontem não deu para responder por causa da facu, mais de maneira geral eu comecei a explorar aqui, usando o código do ul1sses. Ainda estou adaptando um pouco ele.
Sobre o uso de .properties ou xml não dá thiagof , porque tenho 87 arquivos em CSV, que deve ter em torno de 70 mil linhas no total. Cada arquivo se refere há uma parte de um eCommerce que deve ser traduzida. A tradução é feita usando CSV, e como o sistema é meio que de prateleira, e em php, achei mais viavel manter o CSV e automatizar boa parte da tradução(mesmo assim eu ainda vou ter que verificar se a tradução ficou boa e corrigir um monte de coisas :lol: na verdade eu não vou olhar nada, mais sim o estagiário 8) ) do que escrever umas 500 a 800 linhas de código para alterar o funcionamento do sistema criando um novo módulo.

Hoje a tarde vou ver se consigo postar o que eu já fiz. Desde já agradeço pessoal pela ajuda!!

Eu recomendo que você foque no código do thiagof. Ficou bem mais refinado e se você, assim como eu, não tem muita prática em REGEX isso vai dar uma vontade de estudar melhor. É muito útil! :slight_smile:

[quote]
ul1sses

Eu não estava com dúvida de você cara, eu realmente queria que alguém postasse algum código com regex por que eu também queria saber…[/quote]

Tranqüilo! escrevi aquilo apenas na brincadeira mesmo :smiley:

A regex que fiz pode ser refinada ainda mais, e quanto mais refinada, mais precisa vai ficar… (dá até para tirar aquele else lá do .split() e fazer tudo por regex mesmo) Eu não fiz porque tava sem tempo aqui, mas é legal que fica como ponto de melhoria para quem quiser refinar ela aqui no forum… fica como exercício para a gente essa qeuestão aee :wink:

Com relação a aprender regex, eu conheço um site muito bom!
http://aurelio.net/regex/guia/

esse site é do Aurelio Marinho Jargas, um meste Jedi das expressões regulares! aprendi tudo que sei sobre regex só lendo esse site dele. Depois comprei o livro dele, muito bom e barato também, só 36 reais! (comprei na novatec com código de promoção que o próprio Aurelio disponibiliza no site dele: http://www.piazinho.com.br/ procurem lá, vale a pena ter um :wink: )

Dêem uma olhada lá no site, aprendam um pouco sobre regex e melhorem essa minha regex :wink:
Uma dica inicial, tentem entender o que essa regex faz:

private static final String REGEX = "^ *(\".*?\") *, *(\".*?\") *$";

notem que já consegui refinar um pouco mais ela, com os meta caracteres ^ e $
se quiserem, eu explico o que a regex acima ta fazendo, mas ai perde a graça de estudar e tentar decifrá-la né?! :lol:
qualquer dúvida, posta ai pra gente discutir :smiley:

Bom, eu dei uma leve estudada no material que o thiagof citou, então consegui diminuir um pouco meu código:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TesteSplit {

	public static void main(String[] args) throws IOException {
		
		String vetor[] = new String[2];
		
		// Apenas para testes
		Map<String, String> mapaTraducao = new HashMap<String, String>();
		mapaTraducao.put("Hi, Welcome", "Olá, Bem vindo");
		mapaTraducao.put("Word", "Palavra");
		mapaTraducao.put("Hello man", "Olá cara");
		mapaTraducao.put("Wtf", "Mas que PIIII");

		BufferedReader br = new BufferedReader(new FileReader(new File("teste.csv")));
		
		String linha;
		while ((linha = br.readLine()) != null) {
			if (linha.contains("\"")) {
				String regex = "\".*?\"";
				Pattern p = Pattern.compile(regex);
				Matcher m = p.matcher(linha);
				
				int indice = 0;
				while (m.find()) {
					vetor[indice] = m.group().replaceAll("\"", "");
					indice++;	
				}
				
			} else {
				vetor = linha.split(",");
			}
			
			// TODO Método para analisar os indices do vetor e efetuar a tradução
			
			if (mapaTraducao.containsKey(vetor[0])) {
				System.out.print("["+vetor[0]+"]");
				System.out.print("["+mapaTraducao.get(vetor[0])+"]");
			}
			System.out.println();
			
		}

	}
}

arquivo csv de teste:

"Hi, Welcome", "Hi, Welcome"
Word, Word
"Hello man", "Hello man"
Wtf, Wtf

Vou continuar estudando e ver se consigo melhorar a ER!

Ah, obrigado thiago pela referência! :smiley:

heehehe aeee ul1sses seu código ficou bem melhor que o meu :smiley:

achei a sua ER muito boa, quanto mais simples, melhor para ler, e se ela atende o que vc precisa, tá ótimo, nem precisa melhorar mais, achei que ficou muito bom mesmo!!!

ai para atualizar o arquivo que vai ser um desafio hen, porque vai ter que percorrer linha a linha do arquivo buscando pela chave == vetor[0]…

bom, agora não sei como vc pretende atualizar o arquivo, se é de pedaço em pedaço ou se é tudo de uma vez…

agora o bicho pegou :frowning:

Ele pode pegar essa parte do código abaixo e alterar para pegar o m.start() (posicao inicial do casamento atual na string) e o m.end() (posical final do casamento atual na string).
Depois o resto é só montar o frankstein. hehe

...
while (m.find()) {
    vetor[indice] = m.group().replaceAll("\"", "");
    indice++;	
    // Exemplo
    posicalInicial = m.start();
    posicaoFinal = m.end();
}
...

[quote]Ele pode pegar essa parte do código abaixo e alterar para pegar o m.start() (posicao inicial do casamento atual na string) e o m.end() (posical final do casamento atual na string).
Depois o resto é só montar o frankstein. hehe[/quote]

Voce fala em atualizar o arquivo CSV???

acho que para atualizar um arquivo texto, vc precisa da posicalInicial e posicaoFinal no arquivo como um todo (como uma string unica) e não só o indiceInicial e o indice final da palavra na linha corrente…

Na verdade ele nem precisa pegar posição alguma.
Essa minha idéia se encaixa mais em outro tópico http://www.guj.com.br/java/270785-resolvido-expressao-regular-com–. Acho que viajei um pouco.
Ele pode ler uma linha, faz o processo devido (busca e tradução), então ele salva em um StringBuffer ou Mapa. No fim ele salva em arquivo.
Ou então ele pode ir lendo uma linha, fazer o processo devido e já ir salvando em algum arquivo temporário…
De qualquer maneira, ele vai ter que ler o arquivo todo mesmo, certo?

Tem razão, é mais fácil ir gravando em um arquivo com nome diferente e depois excluir o arquivo antigo e renomear o novo para o nome do antigo, já que vc vai ter que ler o arquivo todo e gravar o arquivo “todo” novamente :smiley:

Pessoal, estou com um problema semelhante …

Por exemplo, tenho um loop que lê um arquivo linha por linha, e dependendo da situação, preciso inserir dados nas linhas seguintes. É possivel que na próxima iteração do loop eu esteja com este arquivo já atualizado com as informações anteriormente escritas? Caso negativo, eu teria que usar outro arquivo auxiliar?? Me ajudem por favor … :oops:

minhas duvidas sanadas aki… OMG
----------