Um milhão, um mil e um ou um milhão mil e um?

Para os preguiçosos:

O projeto de que trato aqui é um conversor de números para sua representação "por extenso". Se você chegou aqui e não quer ter o trabalho de ler, apenas achar o código, siga este link: código (ou acesso o projeto no google code). Se, por outro lado, estiver em busca de explicações para fazer o seu próprio conversor ou curioso sobre como este conversor aí em cima funciona, leia o resto deste post.

Ábaco

Para os curiosos:

O título é esquisito, mas a dúvida era essa. O problema surgiu quando, num dos relatórios do sistema, o cliente exigiu que os valores fossem escritos de forma numérica (fácil, o NumberFormat dá conta que é uma beleza) seguidos do valor por extenso. Pensei com meu botões: não tem problema, TODO MUNDO já precisou disso um dia, deve ter DÚZIAS de conversores para números por extenso vagando pelo labirinto de Falken. Basta escolher o mais bonitim e boas!

Na verdade a tarefa nem era minha. Caiu pra mim quando surgiu o primeiro bug. A classe que tinham usado funcionava bem, contanto que o número fosse redondo ou pequeno. "Um milhão de reais" ele disse quando pedi pra converter 1.000.000,00. Mas logo depois me cospe "Um milhão e três de reais" pra 1.000.003,00. Hein? Mas peraí, isso eu conserto, vá... Só que o próximo número piorou: "Um milhão e seiscentos e cinquenta mil e novecentos e dez reais". Pera lá! Tem E demais aí!.

A primeira coisa que pensei foi em achar outro conversor. Doce ilusão. Existir até existem. Vários (ou melhor, várias cópias do mesmo, já que parecem ser todos baseados no mesmo código original). Mas nenhum funciona.

Quer dizer, funcionam... Se você usar os números de teste que o autor usou! (Quem gosta disso pode fazer disto um "caso" para test-driven design, ou o que valha). Saindo um pouco do que o autor tinha em mente, a coisa desanda.

Nesse ponto eu não tinha mais escolha: teria de implementar o meu próprio conversor. Bom, que os outros estavam errados eu sabia, mas e qual a forma correta de se escrever por extenso? Depois de muita discussão e nenhum acordo, decidimos: Vamos consultar uma gramática!Cheque

Na biblioteca, pegamos logo 3 gramáticas. Nenhuma, claro, concordava com a quantidade de "e" que o sujeito usou. Alias, nenhuma delas concordava entre si. Uma, a mais antiga, pregava o uso de vírgulas a torto e a direito:

um bilhão, cento e vinte milhões, duzentos e três mil, cento e quarenta e sete.

A outra era categórica: depois de mil não! Só depois dos "ãos" é que tem vírgula:

um bilhão, cento e vinte milhões, duzentos e três mil cento e quarenta e sete.

E por último, uma que se dizia de acordo com o novo acordo ortográfico (que não tratou nem de números nem de vírgulas, mas que de alguma forma afetava a opinião do autor a respeito) abominava vírgulas:

um bilhão cento e vinte milhões duzentos e três mil cento e quarenta e sete.

Assim fica difícil, né? Em nosso auxílio veio uma ótima e hiper didática revisora de texto que passava pelo local:

Vírgulas servem para separar os elementos numa lista. No caso dos números, use para separar cada grupo de unidade, milhar, milhão, etc. (nesse ponto a gente, das exatas, anota: uma vírgula a cada potência de 1000). Mas elas não são absolutas, e podem ser omitidas se for para aumentar a clareza. Pense na clareza do texto e escolha a forma que melhor lhe convém. Depois de escolhido o melhor jeito, procure uma gramática que concorde com você e use ela como bibliografia!

Pra mim, esse conselho foi genial. E de certa forma resolveu nosso problema: bastava escolher o mais fácil de implementar e depois procurar uma gramática que nos apoiasse.

Acabei me guiando por 8 regrinhas, que definiram como implementar meu conversor:

  1. números abaixo de 20 tem nome próprio;
  2. de 21 a 99 os números são formados por DEZENA "e" UNIDADE (exemplo: "trinta e cinco");
  3. dezenas redondas não tem nada depois (20 -> "vinte", e não "vinte e zero");
  4. 100 tem nome próprio: cem;
  5. números maiores que 100 são compostos por CENTENA "e" DEZENA ["e" UNIDADE];
  6. acima de 1000 agrupa-se os números em blocos de 3 dígitos (potências de 1000), que são representados como se fossem números menores do que 1000 acrescidos do sufixo representando a potência de mil apropriada (mil, milhão, etc);
    1. os grupos são concatenados por vírgula;
    2. A ultima concatenação é feita por "e" ("um milhão e 200 mil");
    3. A ultima concatenação é omitida (ou substituída por vírgula) caso o ultimo grupo seja maior que 100 e não seja múltiplo e 100 ("mil[,] duzentos e cinquenta")
  7. o "um" em frente ao descritor de grupo "mil" é opcional e deve ser parametrizável ("mil e um" e "um mil e um" são igualmente aceitáveis);
  8. Ao acrescentar a unidade (por exemplo "reais") usa-se o prefixo "de" antes da unidade caso o último sufixo seja de milhão ou maior ("dez milhões de reais", mas "dez mil reais").

Código

Com essas regras a implementação foi quase direta. Primeiro criei uma função para as unidades:


        String unidades(int n) {
                return UNIDADES[n];
        }

Em seguida as dezenas:


        String dezenas(int n) {
                if (n < UNIDADES.length) return unidades(n);
                int unidade = n % 10;
                n = n / 10;
                return DEZENAS[n] + " e " + unidades(unidade);
        }

depois tratei a exceção da regra 3:


        String dezenas(int n) {
                . . .
                String unidadeStr = "";
                if (unidade != 0) {
                        unidadeStr = " e " + unidades(unidade);
                }
                return DEZENAS[n] + unidadeStr;
        }

E seguindo as regras uma a uma cheguei no resultado final, que pode ser visto no google code. Ainda não está perfeito, e ainda quero brincar bastante com esse conversor, então deixem suas sugestões,seja aqui, seja como "bug" no google code, que eu implemento, caso dê tempo (e ânimo).

CLT x PJ

O Coragi da experilmes perguntou como calcular se valia a pena mudar de um emprego PJ pra um CLT. Como a conta não é fácil, fiz essa planilha ai em baixo, que está aberta pra quem quiser editar em: http://spreadsheets.google.com/ccc?key=pkGIIoRl9u7Dhu_UoUDcfOg

(Atenção: ao editar diretamente no google docs, os dados estarão visíveis para todos, cuidado ao inserir dados confidenciais).

Ou pra quem quiser fazer o download nos formatos:

  • ODS (Open Office/BROffice)
  • XLS (Excell)

A planilha calcula IRPF, INSS, férias e 13o salário automaticamente, ainda calcula o desconto de 20% na base de calculo do IRPF, considerando o desconto da declaração simplificada. Não incluí FGTS pois nem todos consideram isso uma vantagem. Quem baixar as versões XLS e ODS poderá ver como é feito o cálculo.

Knol, ou uma enxurada de girinadas.

O google lançou o seu complemento/concorrente da wikipédia: knol!

É tudo que um girino pediu a Deus! Nada de fontes, referências, ponto de vista neutro, o escambau aquático! É simplesmente um repositório de conhecimento, QUALQUER UM! Quer lugar melhor pras minhas girinadas? Pois já comecei por lá: escrevi um artiguinho sobre a Lilica Westies, copiei pra lá sem tirar nem por meu tutorial de fractais, e o que eu gastei mais tempo: um artigão, em inglês, introdutório sobre compressão de dados. (Essa foto aí do lado é uma das ilustrações toscas que eu fiz pro artigo 😉 ) Quem animar, dê uma olhada:

Mais "buscas" que cairam aqui.

Sacumé, eu tinha resolvido reviver o blog a partir das buscas interessantes que caiam nele. Pra isso eu precisava listar todas as buscas e encontrar as interessantes. Achar as buscas foi fácil: meu provedor fornece o "awstats" para analisar o tráfego no site e ele separa isso pra mim. Mas pegar da interface dele tava ficando chato porque são muitas, eu queria organizar e analisar antes de escolher "as melhores". Por isso resolvi tratar direto o arquivo de log do awstats.

Como tratar o arquivo de logs do awstats pra extrair as frases de busca

O primeiro passo foi escolher o arquivo. O awstats usa arquivos mensais. Escolhi, claro, o mais recente, afinal é só uma brincadeira. Encontrar lá dentro o que eu queria foi fácil:

$ grep -ni BEGIN_SEARCHWORDS awstats072008.girino.org.txt
380:BEGIN_SEARCHWORDS 343

Ou seja, na começa na linha 380 e se estende por mais 343 linhas. Então vamos extrair essas informações daí, certo? Fiz esse scriptzinho aqui pra isso:

$ file=awstats072008.girino.org.txt;
$ grep_result=`grep -ni BEGIN_SEARCHWORDS $file`;
$ begin_pos=`echo $grep_result | awk -F: '{print $1}'`;
$ size=`echo $grep_result | awk '{print $2}'`;
$ head -$1) $file | tail -$2)

Podem ver que as 4 primeiras linhas "apenas" processam o tamanho do arquivo para encontrar o inicio e fim do trecho que eu quero extrair. E só a ultima linha faz o trabalho mesmo. Eu poderia ter feito "na mão" e colocado logo:

$ head -$3) awstats072008.girino.org.txt  | tail -$4)

Mas perdia toda a graça de se brincar com linha de comando 😉

Mas ainda tem um detalhe: esses "dados" estão "codificados" para uso em url (urlencoded, para os íntimos), e precisamos decodificar. Eu até pensei em um script perl ou sed ou awk pra isso, mas pra que? Como dizia o João Cupim, meu professor de marcenaria no COLTEC, cada atividade tem sua ferramenta apropriada, não improvise ferramentas. Pois pra lidar com URLs, quem melhor que PHP? Então o que levaria uma dúzia de linhas e prometeria ficar incompleto em perl/sed/awk, vira isto daqui em PHP:

<?php
$line = fgets(STDIN); // reads one line from STDIN
while ($line) {
    echo urldecode($line);
    $line = fgets(STDIN); // reads one line from STDIN
}
?>

E ainda com a garantia do PHP de que vai funcionar e ter atualizações futuras, etc e tal!

Basta lascar isso aí num arquivo "urldecode.php" e chamar:

$ head -$5) $file | tail -$6) | php urldecode.php

Et voilá! Seu arquivo de log foi processado com sucesso ;).

No próximo post eu falo sobre as buscas que encontrei.

References   [ + ]

1, 5. begin_pos+size+1
2, 6. size+2
3. 380+343+1
4. 343+2

VMware e PulseAudio no Ubuntu 8.04 Hardy Heron

Atualizei na madrugada de ontem pra hoje, e me deparei com dois problemas: O totem "travava" e o internet banking do banco do brasil não entrava mais...

Bom, fazer entrar o site foi fácil: pelo synaptic eu desistalei do plugin java "gcj" e forcei a reinstalação do plugin java 6 da sun. Só que o diaxo do BB resolveu que meu computador era agora outro computador! E a pior merda do mundo é conseguir cadastrar o computador pelo telefone (antigamente era moleza, mas agora o cara pergunta até a opção sexual e o nome da namorada do jardim de infância).

O VMWare

Mas como eu sou safo, eu tenho uma vmware de emergência que é cadastarda 🙂 sempre que preciso recadastrar meu computador, subo a vmware e cadastro... Quer dizer... Quando o vmware funciona... E por algum desígnio de Buddha, a atualização do ubuntu removeu meu VMware...

Não me faço de rogado, é só baixar de novo, claro.

... 1 hora e vários joguinhso mais tarde ...

CLARO que tinha um motivo pro ubuntu desinstalar meu vmware: os drivers que ele usa não são compatíveis com o kernel mais novo. E enquanto a vmware não resolve o problema, o ubuntu é que não quer assumir: ranca logo essa coisa!

Mas eu precisava dele. Era isso ou andar quase 500 metros até uma agência! HORROR!

De google em google, de forum em forum, achei o milagre: um patch e um HOWTO! Alias, achei em dois lugares: aqui e aqui. Finalmente, cadastrei meu computador, depois de quase 3 horas de luta (e tédio, e joguinhos).

O som

Mas ainda não resolvi o outro problema: O som. Alguns programas com som, outros sem. Alguns sem som, e o totem travando. Eu vi em alguns lugares umas referencias a um tal de PulseAudio e resolvi correr atrás: fui direto ao labirinto de Falken e achei isso: https://wiki.ubuntu.com/PulseAudio.

Reiniciei o X11 e fui pro abraço!

Como colocar padres no google maps...

Uns post atrás eu postei o fruto de minha atoíce, onde usei uma figura do padre voador com o google maps pra fazer uma espécie de "joguinho"[foot]não é bem um "joguinho" já que não tem nenhum objetivo, é apenas uma brincadeira, digamos assim...[/foot]. Hoje, por falta do que postar, resolvi colocar um pequeno tutorial de...

Como colocar padres no google maps...

Continue reading