Qual o problema nesse codigo?

16 respostas
R

Pessoal, estou fazendo um programinha que recebe um arquivo .txt com palavras em ingles e filtro ele deixando tudo minusculo, sem acento, cedinha, hifen, virgula, etc… ou seja, somente o texto de a-z + espaço…
meu codigo que fiz eh esse da filtragem…

public String retiraPalavras() throws IOException {
        String retorno = "";

        int i = 0;
        BufferedReader buf = arquivo.getBuffer();

        i = buf.read();
        while(i != -1){
            if ((i==(int)'a') || (i==(int)'A')){
                quantidade[0] = quantidade[0]+1;
                retorno += 'a';
            }
            else if (i==(int)'b' || (i==(int)'B')){
                quantidade[1] = quantidade[1]+1;
                retorno += 'b';
            }
            else if (i==(int)'c'|| (i==(int)'C')){
                quantidade[2] = quantidade[2]+1;
                retorno += 'c';
            }
            else if (i==(int)'d'|| (i==(int)'D')){
                quantidade[3] = quantidade[3]+1;
                retorno += 'd';
            }
            else if (i==(int)'e'|| (i==(int)'E')){
                quantidade[4] = quantidade[4]+1;
                retorno += 'e';
            }
            else if (i==(int)'f'|| (i==(int)'F')){
                quantidade[5] = quantidade[5]+1;
                retorno += 'f';
            }
            else if (i==(int)'g'|| (i==(int)'G')){
                quantidade[6] = quantidade[6]+1;
                retorno += 'g';
            }
            else if (i==(int)'h'|| (i==(int)'H')){
                quantidade[7] = quantidade[7]+1;
                retorno += 'h';
            }
            else if (i==(int)'i'|| (i==(int)'I')){
                quantidade[8] = quantidade[8]+1;
                retorno += 'i';
            }
            else if (i==(int)'j'|| (i==(int)'J')){
                quantidade[9] = quantidade[9]+1;
                retorno += 'j';
            }
            else if (i==(int)'k'|| (i==(int)'K')){
                quantidade[10] = quantidade[10]+1;
                retorno += 'k';
            }
            else if (i==(int)'l'|| (i==(int)'L')){
                quantidade[11] = quantidade[11]+1;
                retorno += 'l';
            }
            else if (i==(int)'m'|| (i==(int)'M')){
                quantidade[12] = quantidade[12]+1;
                retorno += 'm';
            }
            else if (i==(int)'n'|| (i==(int)'N')){
                quantidade[13] = quantidade[13]+1;
                retorno += 'n';
            }
            else if (i==(int)'o'|| (i==(int)'O')){
                quantidade[14] = quantidade[14]+1;
                retorno += 'o';
            }
            else if (i==(int)'p'|| (i==(int)'P')){
                quantidade[15] = quantidade[15]+1;
                retorno += 'p';
            }
            else if (i==(int)'q'|| (i==(int)'Q')){
                quantidade[16] = quantidade[16]+1;
                retorno += 'q';
            }
            else if (i==(int)'r'|| (i==(int)'R')){
                quantidade[17] = quantidade[17]+1;
                retorno += 'r';
            }
            else if (i==(int)'s'|| (i==(int)'S')){
                quantidade[18] = quantidade[18]+1;
                retorno += 's';
            }
            else if (i==(int)'t'|| (i==(int)'T')){
                quantidade[19] = quantidade[19]+1;
                retorno += 't';
            }
            else if (i==(int)'u'|| (i==(int)'U')){
                quantidade[20] = quantidade[20]+1;
                retorno += 'u';
            }
            else if (i==(int)'v'|| (i==(int)'V')){
                quantidade[21] = quantidade[21]+1;
                retorno += 'v';
            }
            else if (i==(int)'w'|| (i==(int)'W')){
                quantidade[22] = quantidade[22]+1;
                retorno += 'w';
            }
            else if (i==(int)'x'|| (i==(int)'X')){
                quantidade[23] = quantidade[23]+1;
                retorno += 'x';
            }
            else if (i==(int)'y'|| (i==(int)'Y')){
                quantidade[24] = quantidade[24]+1;
                retorno += 'y';
            }
            else if (i==(int)'z'|| (i==(int)'Z')){
                quantidade[25] = quantidade[25]+1;
                retorno += 'z';
            }
            else if (i==(int)' '){
                quantidade[26] = quantidade[26]+1;
                retorno += ' ';
            }
            else if(i==(int)'-' || (i==(int)'
Qual o programa...
testei alguns .txt.

* Para um texto com 200 linhas o tempo pra ele fazer isso e jogar num JTextArea foi de 207 milisegundos
* para um texto com 1000 linhas o tempo para ele fazer isso e jogar num JTextArea foi de 7657 milisegundos = 7,6 segundos     aproximadamente.
* para um texto com 2000 linhas o tempo para ele fazer isso e jogar num JTextArea foi de 55130 milisegundos = 55 segundos

* o problema vem agora, o texto original tem 5319 linhas, coloquei pra rodar, ja se passou 10 minutos e nao retornou resposta(tb nao deu erro, continua la rodando com processador a 100% mas tive que parar a execução forçadamente pq nao sei quando iria terminar mas esperei 10 minutos e nada)...

eu queria saber o pq dessa demora e se tem como agilizar esses calculos...


ps.: minha primeira implementação foi usando buff.readLine(); e usando substring(i,i+1) para pegar caractere por caractere mas o problema ficava na mudanca de linha que ele considerava como espaco, entre outros problemas na contagem de letras que ja esqueci.. porem no texto completo de 5319 linhas ele demorava em torno de 1 minuto e retornava o texto...

ja usando a ideia de codigo ascii da letra com o metodo read() ele faz a contagem perfeita mas to nesse impasse ai dessa demora(que em tese nao devia demorar tanto ja que pelo metodo substring ele tb verifica caractere por caractere o que no meu teexto original tem em torno de 150.000 caracteres)..

Alguma soluçao pessoal??? e agradeço...')){
                retorno += ' ';
                quantidade[26] = quantidade[26]+1;
            }
            else if(i==(int)'\n'){
                retorno += '\n';
            }
            i = buf.read();
        }
        return retorno;
    }

Qual o programa…
testei alguns .txt.

  • Para um texto com 200 linhas o tempo pra ele fazer isso e jogar num JTextArea foi de 207 milisegundos

  • para um texto com 1000 linhas o tempo para ele fazer isso e jogar num JTextArea foi de 7657 milisegundos = 7,6 segundos aproximadamente.

  • para um texto com 2000 linhas o tempo para ele fazer isso e jogar num JTextArea foi de 55130 milisegundos = 55 segundos

  • o problema vem agora, o texto original tem 5319 linhas, coloquei pra rodar, ja se passou 10 minutos e nao retornou resposta(tb nao deu erro, continua la rodando com processador a 100% mas tive que parar a execução forçadamente pq nao sei quando iria terminar mas esperei 10 minutos e nada)…

eu queria saber o pq dessa demora e se tem como agilizar esses calculos…

ps.: minha primeira implementação foi usando buff.readLine(); e usando substring(i,i+1) para pegar caractere por caractere mas o problema ficava na mudanca de linha que ele considerava como espaco, entre outros problemas na contagem de letras que ja esqueci… porem no texto completo de 5319 linhas ele demorava em torno de 1 minuto e retornava o texto…

ja usando a ideia de codigo ascii da letra com o metodo read() ele faz a contagem perfeita mas to nesse impasse ai dessa demora(que em tese nao devia demorar tanto ja que pelo metodo substring ele tb verifica caractere por caractere o que no meu teexto original tem em torno de 150.000 caracteres)…

Alguma soluçao pessoal??? e agradeço…

16 Respostas

G

Boa tarde,

Nossa cara, tem muito IF isso ae.
Faz com expressão regular, vai economizar tempo, ficar um código limpo, e rápido.

flw.

R

opa. vlw pela resposta.

eh que sou novo e nao sei usar expressao regular e meu tempo nao ta muito grande pra estudar isso pois a entrega disso ja esta proxima…

nao creio ser problema dos IFs pois como disse, quando usei com substring, ele demorava em torno de 1 minuto pra retornar o texto completo… com essa nova forma usando read(); ele me da as respostas mais corretas mas esta demorando absurdamente maior que antes o q nao devia ocorrer ja que antes e agora continuo verificando caractere por caractere e no mesmo texto…

Quero tentar resolver dessa forma pois a entrega ja eh proxima, mas de toda forma se alguem puder da dica, alem de corrgiir esse codigo, fazer tb com ER pois eu tenho interesse de otimiza-lo mais na frente…

agradeço a todos.

pmlm

Não uses Strings que vai sendo incrementadas dentro de ciclos. Para isso usa StringBuilder.

cdorner

pmlm:
Não uses Strings que vai sendo incrementadas dentro de ciclos. Para isso usa StringBuilder.

RaphaelSantos ele quer dizer pra vc ler sobre String Imutaveis, existem metodos da propria classe String que resolvem os seus problema, tem o toLowerCase(), replaceAll, enfim muitos outros meios de se conseguir oq vc quer fazer, da uma pesquisada melhor ai.

abraço

T

O seu principal problema é usar "+=". Isso é um verdadeiro veneno; use um StringBuilder (Java 5.0 ou posterior) ou StringBuffer.
Outro problema é ler o arquivo caracter por caracter. O correto é ler uma linha de cada vez, já que você está usando BufferedReader.

No seu caso em particular, você pode usar uma expressão regular. Pelo que estou vendo, você quer deixar só as letras e espaços, e se achar um “-” ou “’” você quer trocar por " ", e além disso você quer tornar todas as letras minúsculas. Ou seja, você pode separar sua rotina em 2:

int quantidade[] = new int[27];
public String limpa (String linha) {
    return linha.replace ("[-']", " ").replace ("[^A-Za-z ]", "").toLowerCase();
}
public void contaLetras (String linhaLimpa) {
    for (int i = 0; i < linhaLimpa.length(); ++i) {
        if ('a' <= linhaLimpa.charAt (i) && linhaLimpa.charAt(i) <= 'z') 
            quantidade [linhaLimpa.charAt (i) - 'a']++;
        else
            quantidade [26]++;
    }
}

e deixar a parte de leitura separada dessa rotina.

Giulliano

Eu acho q vc poderia carregar esse arquivo num BufferedReader mesmo…do mesmo modo q vc fez.

Mas na hora de substituir utilize a API da String:

//Faz um for para ler todas as linhas
for(xyz){

    String linha  = reader.readLine();
    linha = linha.replace("ã",a);
    linha = linha.replace("â",a);
    // continua com as várias e várias possiblidades
    e por último linha = linha.toLowerCase();
}

valews

R

vlw pessoal(thingol tb pelo codigo)…

vejam meu problema…eu nao preciso APENAS retornar o texto sem caracteres estranhos… ou seja retorna apenas a-z e espaco… se tiver cedilha, espaco, colchetes, virgula etc ele retira…

qual o problema disso? eh que depois de filtrado o texto, eu preciso calcular a probabilidade de cada palavra… exemplo…se o total de caracteres eh 3000 e a quantidade de letras a eh 1000, a probabilidade de ter a eh de 1000/3000 = 1/3… por isso dentro de cada if tem um somatorio de um vetor…
ou seja, usando expressao regular, cedo ou tarde terei q ler caractere a caractere para achar a qauntidade de cada letra…

estou modificando para StringBuilder para ver se da um resultado bom…

se algeum tiver + alguma sugestao, pq com essa demora o meu professor nao vai querer esperar pra ver :stuck_out_tongue:

R

Pessoa, so tenho a gradecer a voces…
com o StringBuilder mesmo o texto de 5319 linhas demorou APENAS 19 milisegundos… incrivel…

so uma pergunta… pq o gargalo foi tao grande ao usar += na String???

R

thingol:
O seu principal problema é usar "+=". Isso é um verdadeiro veneno; use um StringBuilder (Java 5.0 ou posterior) ou StringBuffer.
Outro problema é ler o arquivo caracter por caracter. O correto é ler uma linha de cada vez, já que você está usando BufferedReader.

No seu caso em particular, você pode usar uma expressão regular. Pelo que estou vendo, você quer deixar só as letras e espaços, e se achar um “-” ou “’” você quer trocar por " ", e além disso você quer tornar todas as letras minúsculas. Ou seja, você pode separar sua rotina em 2:

int quantidade[] = new int[27];
public String limpa (String linha) {
    return linha.replace ("[-']", " ").replace ("[^A-Za-z ]", "").toLowerCase();
}
public void contaLetras (String linhaLimpa) {
    for (int i = 0; i < linhaLimpa.length(); ++i) {
        if ('a' <= linhaLimpa.charAt (i) && linhaLimpa.charAt(i) <= 'z') 
            quantidade [linhaLimpa.charAt (i) - 'a']++;
        else
            quantidade [26]++;
    }
}

e deixar a parte de leitura separada dessa rotina.


thingol, acho que esse seu codigo ai vai ficar beleza, comecei a entender sua logica…irei fazer o teste com ele… muito obrigado.

T

RaphaelSantos:
Pessoa, so tenho a gradecer a voces…
com o StringBuilder mesmo o texto de 5319 linhas demorou APENAS 19 milisegundos… incrivel…

so uma pergunta… pq o gargalo foi tao grande ao usar += na String???

A instrução:

s += 'a';

é traduzida para:

s = s.concat ('a');

e concat é um método de java.lang.String que faz basicamente o seguinte:

StringBuilder sb = new StringBuilder (this); // cria um objeto StringBuilder a partir da String original, 
// copiando fisicamente os seus caracteres. A criação desse objeto StringBuilder implica na
// criação de um objeto char[]
sb.append ('a'); // adiciona um caracter
return sb.toString();  // cria um novo objeto java.lang.String (que copia o objeto char[] do StringBuilder)

Ou seja, você cria 4 objetos e tem 2 cópias para char[]. Se as strings forem um pouco grandes (como linhas de um arquivo texto),
o tempo gasto em alocação e cópias vai ser bem alto.

Se você usar uma StringBuilder todo o tempo, cada “append” não cria novos objetos à toa (só quando
um buffer interno estourar, mas isso não deve ocorrer muito frequentemente, e mesmo assim você pode ter uma
idéia do tamanho aproximado - existe um construtor de StringBuilder que permite passar uma estimativa
do tamanho final da StringBuilder.

Tchello

RaphaelSantos:
Pessoa, so tenho a gradecer a voces…
com o StringBuilder mesmo o texto de 5319 linhas demorou APENAS 19 milisegundos… incrivel…

so uma pergunta… pq o gargalo foi tao grande ao usar += na String???

Isso é por que uma String é imutável, ou seja, toda vez que você concatena duas strings na verdade você cria uma terceira, exigindo mais recursos de máquina (processamento e memória).
O que não acontece com a StringBuilder nem com a StringBuffer, pois essas sim são mutáveis e não ficam realocando recursos.
Agora imagine isso pra cada letra de um arquivo de texto de mais de 5 mil linhas… qual lhe parece mais performático?
Com a StringBuilder ele não precisa ficar recriando objetos strings, o que diminui bastante esse gargalo.

ps: A título de informação a diferença entra StringBuilder e StringBuffer é que a segunda é Thread Safe, ou seja, tem os métodos sincronizados pra que apenas uma thread por vez possa acessa-la. Isso a torna mais “lenta” mas em alguns casos é necessário assim como em outros não.

Abraços!

edit: correção ortográfica.

Tchello

Ok, parece que o thingol e eu respondemos ao mesmo tempo… a explicação dele está melhor.

Enjoy!

R

compreendi o problema do += finalmente…

valeu meus amigos…

R

Só mais uma duvida pessoal, se essa concatencao fosse com inteiros ou doubles teria o mesmo problema que teve com String???

caso sim, qual seria a alternativa para inteiro e doubles??

T

Concatenação não é a mesma coisa que adição.

int x = 2;
x += 3; // dá 5, como esperado, não 23, como seria esperado se fosse uma concatenação.

Ao usar tipos primitivos (tais como int e double), o operador “+=” (que é adição seguida de atribuição) não cria novos objetos, justamente porque não há objetos envolvidos.

R

Amigo thingol e amigos,
estou com outro problema…
com essa modificação quando tento filtrar um texto enorme(exemplo, tenho a biblia em txt), mesmo assim ele nao demora nem 20 segundos para filtrar e setar todo o texto filtrado num JTEXTAREA…

porem repeti o codigo para poder setar a codificacao num JTEXTAREA e retorno o problema… com os mesmos exemplos (os mesmos textos na mesma quanitdade de linhas), ele filtra, codifica, codifica o texto todo e mostra num jtextarea em segundos, mas no texto final(o txt de 5319 linhas e 150.000 caracteres aproxiamadamente) ele demora muito pra setar no jTExtArea…

tirei a prova dos 9 fazendo o System.currentTimeMillis() antes de comecar e apos terminar…
ele leva 1 minuto pra fazer tudo, o q eh um tempo aceitavel mas depois que termina leva mais 5 minutos aproximadamente somente para SETAR no textArea o texto em formato de 0 e 1 com um total de 400.000 caracteres.

pq essa demora toda mesmo usando o StringBuilder???

outra duvida amigos para nao criar um topico novo.
eu faço varios cálculos no meu programa e os numeros dao grande como da pra imaginar…e seto esses valores num jTable1.setValueAt(huffman.getZeros(), 0, 1); por exemplo…esse numero costuma ser na casa de 100000 em media… como eh ums String, como faco pra setar os pontos na visualizaçao? ou seja se for 50000(aparecer 50.000)… se for 300 mostra 300 mesmo… se for 100000 mostra 100.000 e assim por diante numa String???

Criado 24 de abril de 2009
Ultima resposta 25 de abr. de 2009
Respostas 16
Participantes 7