sexta-feira, 16 de janeiro de 2015

[P1] Numerônimo

Referência da Wikipédia: http://en.wikipedia.org/wiki/Numeronym

     Assim como existem os sinônimos e antônimos existem os "numerônimos". O nome deste blog é um numerônimo para o meu nome completo (Ricardo Melo Czekster), ou seja, entre o primeiro 'R' e o último 'R' do meu nome existem 17 caracteres (o que é interessante, pois muitas pessoas dizem que meu nome é impronunciável mas, acreditem, existem sobrenomes poloneses/russos bem piores de pronunciar que este...):

00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18
R i c a r d o m e l o c z e k s t e R

     Existem dois casos interessantes para se usar um numerônimo: (a) para formar uma abreviação que ao ser pronunciada se parece com a palavra, no caso de K9 ("kay" + "nine" ou canine unit, em inglês) e (b) para substituir as letras entre a primeira e a última e utilizar números para representar as letras omitidas, como é o caso de i18n, um numerônimo para InternationalizatioN ('I' seguido de 18 letras seguido de 'N').

     Outros numerônimos intressantes são W3C (World Wide Web Consortium), 101 para introdução básica a qualquer assunto (mais utilizado nos Estados Unidos da América, por exemplo, Curso: Jogos 101), ou mesmo quando números são utilizados para substituir letras similares (caso de H4CK3D para significar HACKED).

     Exemplos: a11y (accessibility), G20 (as vinte maiores economias do mundo) e Y2K (year 2000, bug do milênio, do ano 2000).

Introdução à Interface de Linha de Comando

     A Interface de Linha de Comando (Command Line Interface - CLI) é extremamente importante em programação. Através desta modalidade os programadores podem compilar programas que aceitam argumentos (ou parâmetros) fornecidos pela linha de comando (no GNU/Linux trata-se do terminal e no MS-Windows do cmd.exe).

     Uma curiosidade interessante: o Sistema Operacional UNIX foi escrito em C e usava extensivamente o conceito de programas com passagem de parâmetros.

Linguagem C

     A Linguagem C (e C++ também) oferece mecanismos para tratar a linha de comando através da função principal main.
// tudo após // na mesma linha não será lido pelo compilador //////////

// cabeçalho C necessário para a função printf
#include <stdio.h>

int main(int argc, char *argv[]) {
   int i;
   printf("Total de argumentos: %d\n", argc);
   for (i = 0; i < argc; i++) {
      printf("argv[%d] = %s\n", i, argv[i]);
   }
   return 0;
}
     Estamos aqui usando a função printf que imprime dados na tela, %d para representar a impressão de números inteiros, %s para imprimir textos (strings) e \n para realizar quebra de linha (return). O número de caracteres % na função indica o número de parâmetros necessários que devem ser chamados (observe as duas chamadas para printf e veja suas diferenças).

     Vamos dar o nome deste arquivo de teste.c e compilar através da linha de comando:
gcc teste.c -o teste
teremos um executável chamado teste (parâmetro de linha de comando -o). Observe que o gcc (GNU C Compiler, o compilador da Linguagem C) também aceita parâmetros pela linha de comandos. Caso -o não seja chamado, o gcc criará um executável chamado a.out (no GNU/Linux) e a.exe no MS-Windows.

     Neste ponto, basta executar o programa e observar a saída produzida, passando diferentes parâmetros:
./teste Isto eh um teste!
     O ./ acima é necessário apenas no GNU/Linux, e informa que deseja-se executar um programa do diretório corrente. Sem isso não funciona. A saída produzida é a seguinte:
Total de argumentos (argc): 5
argv[0] = teste
argv[1] = Isto
argv[2] = eh
argv[3] = um
argv[4] = teste!
     Mas porque 5 e não 4 argumentos de linha de comando? Porque em C, ele conta o nome do programa (no caso, teste).


     Mas e se quiséssemos usar um número da linha de comando no nosso programa, por exemplo, calcular a raiz quadrada de um número passado por parâmetro pela linha de comando. O programa só deve funcionar se for passado UM parâmetro. Como seria a implementação?
// função printf
#include <stdio.h>

// função exit(int status) - sair do programa
// função int atoi(char* v) - converte um texto para um inteiro
#include <stdlib.h>

// função double sqrt(double n) - raiz quadrada de um número (square root)
#include <math.h>

int main(int argc, char *argv[]) {
   int i;
   int num;           // número passado pela linha de comando
   double resposta;   // raiz quadrada do número

   if (argc != 2) {
      printf("Erro.");
      printf("Voce nao informou o numero de parametros necessarios.\n");
      printf("Tente novamente\n");
      printf("Uso:\n\t./teste NUMERO\n"); // \t insere TABULAÇÃO
      exit(1);
   }

   // converte um texto (a) para um inteiro (i)
   //     passando um texto por parâmetro: argv[1]
   num = atoi(argv[1]); // argv[1] pois argv[0] é o nome do programa
   resposta = sqrt(num);
   printf("A raiz quadrada de %d eh %2.2f\n", num, resposta);

   return 0;
}
     Chame este arquivo de raiz.c, compile e execute-o para diferentes valores.


     No entanto, uma pergunta ainda persiste: como C interpreta múltiplos parâmetros de linha de comando?

     Vamos supor que desejamos passar a seguinte sequência de caracteres por linha de comando:
./teste2 -o 1 -s international insolence intrusion
     Neste exemplo, gostaríamos que -o representasse o tipo da saída (aceitando apenas 0 ou 1), -s sendo mostrar os textos inseridos, seguidos dos textos que desejamos inserir.

     A Linguagem C, por utilizar char *argv[] (que é uma matriz de caracteres), considera a entrada como sendo:

argc=7 00 01 02 03 04 05 06 07 08 09 10 11 12 13
argv[0] 't' 'e' 's' 't' 'e' '2' '\0'              
argv[1] '-' 'o' '\0'                      
argv[2] '1' '\0'                        
argv[3] '-' 's' '\0'                      
argv[4] 'i' 'n' 't' 'e' 'r' 'n' 'a' 't' 'i' 'o' 'n' 'a' 'l' '\0'
argv[5] 'i' 'n' 's' 'o' 'l' 'e' 'n' 'c' 'e' '\0'        
argv[6] 'i' 'n' 't' 'r' 'u' 's' 'i' 'o' 'n' '\0'        

     Ou seja, argv[4][4]='r' e argv[0][5]='2' (lembre-se que é uma matriz de caracteres). Observe que \0 é um caractere de controle em C que representa o final da string. Observe também que os espaços entre os argumentos foram consumidos pelo programa.

Descrição do projeto
     Vamos implementar um programa que, dado qualquer texto da linha de comando, este calculará seu numerônimo. Por exemplo:
./numeronimo pneumonoultramicroscopicsilicovolcanoconiosis
irá produzir a seguinte saída:
Numerônimo: p43s
     Somente um parâmetro deverá ser passado para o programa. Como você faria este programa?

Questões interessantes deste projeto
  1. implemente o numerônimo de qualquer argumento passado por linha de comando (conforme acima), sendo que o programa só deve aceitar um argumento, resultado em erro caso contrário
  2. vamos supor que múltiplos parâmetros sejam passados na linha de comando
    1. faça um programa que mostra uma matriz de caracteres (com aspas simples) de todos os parâmetros, inclusive o \0
    2. implemente um programa que mostra o numerônimo destes múltiplos parâmetros, separando-os por linha
    3. implemente um programa que concatena (junta as strings separadas por espaço) todos os múltiplos parâmetros fornecidos (se foram fornecidos) em um único numerônimo
  3. considere que a=1,b=2,c=3,d=4 e assim por diante, até z=26 (faça funcionar para o alfabeto: abcdefghijklmnopqrstuvwxyz); faça um programa que acumula estes valores para calcular o numerônimo ao invés de apenas contar o total de caracteres entre o primeiro e o último caractere
    1. faça uma opção de linha de comando (-c) que calcula o numerônimo conforme o alfabeto acima (caso -c não for informado, ele retorna o numerônimo sem calcular conforme o alfabeto)
  4. [DESAFIO] separe os números conforme o total de vogais e o total de consoantes, por exemplo, internationalization, ficaria: i9-9n, pois tem 9 vogais e 9 consoantes e pneumonoultramicroscopicsilicovolcanoconiosis ficaria p23-20s (dica: teste os caracteres do parâmetro individualmente, por exemplo: if (argv[5][0] == 'a')...)

Nenhum comentário:

Postar um comentário