segunda-feira, 1 de abril de 2013

Criando tabela em arquivo HTML usando C

Criando tabelas HTML através da linguagem C

Em uma aula de linguagem de programação, foi proposto o seguinte exercício de lógica:

O usuário deve entrar com a quantidade de linhas e colunas e com estes dados, desenhar um retângulo que a borda é o caracter 'O' e o seu interior é preenchido com 'X'.

Por exemplo, se a entrada fosse 3 linhas e 5 colunas, teríamos:

OOOOO
OXXXO
OOOOO

Assim, tive a ideia de fazer um programa em C que fizesse a estrutura de uma tabela HTML pedindo para o usuário a quantidade de linhas e colunas.

O ponteiro para arquivos ps cria o arquivo tabelas.html e ao invés de usar printf que imprime na tela, usa-se fprintf para imprimir dentro do arquivo.

São necessários dois laços for sendo que o for externo diz respeito à linha e o mais interno, à coluna.

Uma vez que o ponteiro é aberto para escrita, deve-se instruí-lo a fechá-lo e o comando para este fim é o fclose(nome_do_ponteiro). Neste exemplo, fclose(ps).

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i,j,colunas=1, linhas=1, contador=0;
    FILE *ps;

    ps = fopen("tabela.html","w");
    if (ps == NULL)
    {
        printf("Erro na abertura do arquivo");
        exit(0);
    }

    printf("Programa de geracao de tabelas\n\n");
    printf("Digite o numero de linhas da tabela: ");
    scanf("%d",&linhas);
    printf("Digite o numero de colunas da tabela: ");
    scanf("%d",&colunas);

    fprintf(ps,"<html>");
    fprintf(ps,"\n");
    fprintf(ps," <head>");
    fprintf(ps,"\n");
    fprintf(ps,"   <title></title>\n");
    fprintf(ps," </head>");
    fprintf(ps,"\n\n");

    fprintf(ps,"  <body>\n\n");
    fprintf(ps,"  <table>\n");

    for (i=1; i<=linhas;i++)
    {
        for (j=1; j<=colunas+2; j++)
        {
              if (j==1)
                fprintf(ps,"   <tr> ");
              else if (j==colunas+2)
                fprintf(ps," </tr>\n");

              else
                fprintf(ps," <td></td> ");
              contador++;              
        }
    }

    fprintf(ps,"  </table>\n");
    fprintf(ps,"\n");

    fprintf(ps,"  </body>\n");
    fprintf(ps,"</html>");

    fclose(ps);

    printf("Arquivo tabelas.html criado com sucesso\n");

    return 0;
}

Se estiver usando uma distribuição GNU/Linux, compile com:

$ gcc tabelaHTML.c -o tabelaHTML.out

Em seguida, execute da seguinte forma:

$ ./tabelaHTML.out

Como diz a mensagem, o arquivo tabela.html foi criado com sucesso. Abra este arquivo que está no mesmo diretório que o seu binário e bom proveito!

sábado, 2 de março de 2013

Ponteiro tipo char para imprimir um número indeterminado de caracteres

Uma habilidade muito comum e exigido na linguagem C é a manipulação de caracteres. Como a declaração da variável é do tipo char, é preciso tratar caracter a caracter ao invés da string toda.

O exemplo abaixo declara um ponteiro do tipo char e é atribuído palavras, portanto, contém inclusive espaços.

O laço while analisa o indíce do ponteiro que incrementado antes do fim do bloco verificando se chegou no fim da cadeia de caracteres indicada por '\0'.

A cada vez que o caracter é impresso, o comando printf adiciona um espaço pela ação de "%c ".

# include <stdio.h>
# include <unistd.h>

int main()
{
  int i;
  char *vetor;

  vetor="Este ponteiro de nome vetor passa a armazenar uma frase que poderia ser muito maior do que esta.";
  
  i=0;
  while (vetor[i] != '\0')
  {
    printf ("%c ", vetor[i]);
    i++;    
  }

  printf("\n");

  return 0;
}

O resultado é exibido abaixo:

E s t e p o n t e i r o d e n o m e v e t o r p a s s a a a r m a z e n a r u m a f r a s e q u e p o d e r i a s e r m u i t o m a i o r d o q u e e s t a .

sábado, 2 de fevereiro de 2013

Exibição dos caracteres especiais para HTML

O fato de desenvolver textos HTML tanto para Linux como para Windows tem causado o incoveniente de exibir os caracteres acentuados de forma errada porque os sistemas operacionais usam codificações distintas.

A melhor forma de adequar a ambas as situações é substituir os caracteres problemáticos por códigos que ao serem interpretados pelo navegador são traduzidos pela combinação de vogais acentuadas ou cedilha.

O código abaixo faz a substituição global destes caracteres. Desta forma, basta redigir o texto normalmente e após a execução do script o texto está pronto para ser visualizado por qualquer navegador.

Observação: É preciso juntar o "&" com o que vem em seguida, pois se fosse feito no editor seria interpretado e desta forma não seria exibido o código HTML.

#/bin/bash
# Fonte dos caracteres especiais: http://www.lsi.usp.br/~help/html/iso.html

if [ $# != 1 ]
  then
    echo Digite $0 arq
    exit
  else
    sed 's/Á/\& Aacute;/g' $1 > $$
    sed 's/á/\& aacute;/g' $$ > $1
    sed 's/Â/\& Acirc;/g' $1 > $$
    sed 's/â/\& acirc;/g' $$ > $1
    sed 's/À/\& Agrave;/g' $1 > $$
    sed 's/à/\& agrave;/g' $$ > $1
    sed 's/Â/\& Atilde;/g' $1 > $$
    sed 's/ã/\& atilde;/g' $$ > $1

    sed 's/É/\& Eacute;/g' $1 > $$
    sed 's/é/\& eacute;/g' $$ > $1
    sed 's/Ê/\& Ecirc;/g' $1 > $$
    sed 's/ê/\& ecirc;/g' $$ > $1

    sed 's/Í/\& Iacute;/g' $1 > $$
    sed 's/í/\& iacute;/g' $$ > $1

    sed 's/Ó/\& Oacute;/g' $1 > $$
    sed 's/ó/\& oacute;/g' $$ > $1
    sed 's/Ô/\& Ocirc;/g' $1 > $$
    sed 's/ô/\& ocirc;/g' $$ > $1
    sed 's/Õ/\& Otilde;/g' $1 > $$
    sed 's/õ/\& otilde;/g' $$ > $1

    sed 's/Ú/\& Uacute;/g' $1 > $$
    sed 's/ú/\& uacute;/g' $$ > $1

    sed 's/ç/\& ccedil;/g' $1 > $$

    sed 's/>/\&# 62;/g' $$ > $1
    sed 's/</\&# 60;/g' $1 > $$
    
fi
mv -v $$ $1


segunda-feira, 31 de dezembro de 2012

Análise dos números da Mega Sena

Para encerrar o ano, um script que trabalha com os números dos concursos anteriores da Mega Sena.

O script baixa um arquivo com todos os resultados da Mega Sena, descompacta e apaga arquivos sem importância.

Considero ser uma melhoria em relação ao script da Análise dos números da Quina por simplificar a etapa de extrair os números sorteados e evitar mensagens de erros quando se tenta apagar arquivos que não existem.

#!/bin/bash
# Created in dez/26/2012 by murilofujita@gmail.com

# Baixa e descompacta
wget http://www1.caixa.gov.br/loterias/_arquivos/loterias/D_mgsasc.zip
unzip D_mgsasc.zip

# Apaga arquivos desnecessários
if [ -f D_mgsasc.zip ]
  then
    rm D_mgsasc.zip
fi

if [ -f T2.GIF ]
  then
    rm T2.GIF
fi

if [ -f /tmp/sena1.txt ]
  then
    rm /tmp/sena*.txt
fi

inicio=4 # Primeira linha da sequência do primeiro sorteio 
fim=9 # Última linha da sequência do primeiro sorteio
contador=1 # Primeiro sorteio

# Necessário eliminar o Feed Line e Carriage Return editado pelo windows
tr -d '\r' < d_megasc.htm > $$
mv $$ d_megasc.htm 

# Busca a quantidade de sorteios realizados
jogos=`tail -n 23 d_megasc.htm | head -n 1 | sed 's/<td>//' | sed 's/<\/td>//'`
echo $jogos sorteios realizados

# Loop que elimina as marcações HTML
while [ $contador -le $jogos ]
  do
    for i in `seq $inicio 1 $fim`
      do
        head -n $i d_megasc.htm | tail -n 1 | sed 's/<td>//g' | sed 's/<\/td>//g' 
      done 
    let inicio=$inicio+21 # A cada 21 linhas uma nova sequência do sorteio
    let fim=$fim+21
    let contador=$contador+1    
  done > /tmp/sena1.txt

echo Exibindo a frequencia dos numeros sorteado da Mega Sena
  for i in `seq 9`
    do
      printf "0$i `grep 0$i /tmp/sena1.txt | wc -l`  "
    done
  printf "10 `grep 10 /tmp/sena1.txt | wc -l` "
  printf "\n"

  inicio=11
  fim=20
  while [ $inicio -le 60 ] # Conta a frequencia dos 60 números da Mega Sena
  do
   for i in `seq $inicio 1 $fim`;
     do
       printf "$i `grep $i /tmp/sena1.txt | wc -l`  "
     done
     printf "\n"
     let inicio=$inicio+10
     let fim=$fim+10
  done

# Para efeito de tabulação, separa-se os números de 1 e 2 algarismos
for i in `seq 9`; do printf "0$i `grep 0$i /tmp/sena1.txt | wc -l`\n" ; done >> /tmp/sena2.txt
for i in `seq 10 1 60`; do printf "$i `grep $i /tmp/sena1.txt | wc -l`\n" ; done >> /tmp/sena2.txt

# Ordena de acordo com a frequencia sorteada
awk '{printf "%3s %3s\n",$2, $1}' /tmp/sena2.txt | sort -n | tail -n 6 > /tmp/sena3.txt

printf "\n"
echo Os numeros mais sorteados sao:
echo Dezena Frequencia

# Exibe as 6 dezenas mais frequentes (do maior para o menor)
for i in `seq 6`
  do
     tail -n $i /tmp/sena3.txt | head -n 1 | awk '{printf "%4s %8s\n",$2, $1}'
  done
  
if [ -f d_megasc.htm ]
  then
    rm d_megasc.htm
fi

O resultado do script, executado até o concurso 1454 é exibido a seguir:

1454 sorteios
Exibindo a frequencia dos numeros sorteado da Mega Sena
01 135  02 143  03 144  04 159  05 177  06 137  07 146  08 150  09 126  10 151 
11 136  12 153  13 155  14 134  15 133  16 154  17 157  18 138  19 141  20 140  
21 127  22 123  23 150  24 158  25 137  26 117  27 145  28 152  29 158  30 149  
31 144  32 152  33 163  34 146  35 136  36 148  37 147  38 141  39 134  40 141  
41 155  42 156  43 160  44 146  45 130  46 130  47 147  48 132  49 156  50 155  
51 161  52 156  53 160  54 162  55 132  56 143  57 140  58 140  59 146  60 140  

Os numeros mais sorteados sao:
Dezena Frequencia
  05      177
  33      163
  54      162
  51      161
  53      160
  43      160

real 1m1.930s

quarta-feira, 28 de novembro de 2012

Geração de combinações entre n elementos

comb3.h

#ifndef COMB3_H
#define COMB3_H

class comb3 {
public:
    comb3();
    comb3(const comb3& orig);
    virtual ~comb3();
    void elementos3();
private:

};

#endif /* COMB3_H */

comb3.cpp

#include 
using std::cout;
using std::endl;
#include 
#include "comb3.h"

comb3::comb3() {
}

comb3::comb3(const comb3& orig) {
}

comb3::~comb3() {
}

void comb3::elementos3()
{
  int p1=1, p2=1, p3=1;
  int total, totalc=0;

  total=pow(3,3);

  for (int i = 1; i <= total; i++)
  {
        if (p1 != p2 && p1 != p3 && p2 != p3)
        {
           totalc++;
           cout << p1 << " " << p2 << " " << p3 << endl;
        }

        if (p3 < 3)
        {
            p3++;
        }
        else
        {
           p2++;
           p3 = 1;
        }

        if (p2 == 4)
        {
           p2 = 1;
           p1++;
        }
  }
  cout << totalc << " combinações" << endl;    
}

comb4.h

#ifndef COMB4_H
#define COMB4_H

class comb4 {
public:
    comb4();
    comb4(const comb4& orig);
    virtual ~comb4();
    void elementos4();
private:

};

#endif /* COMB4_H */

comb4.cpp

#include 
using std::cout;
using std::endl;
#include 
#include "comb4.h"

comb4::comb4() {
}

comb4::comb4(const comb4& orig) {
}

comb4::~comb4() {
}

void comb4::elementos4()
{
    int p1 =1, p2 = 1, p3 = 1, p4 = 1;
    int total = pow(4,4);
    int totalc = 0;

    for (int i = 1; i <= total; i++) {
            if (p1 != p2 && p1 != p3 && p1 != p4 && p2 != p3  && p2 != p4 && p3 != p4) 
            {
               totalc++;
               cout << p1 << " " << p2 << " " << p3 << " " << p4 << endl;
            }

            if (p4 < 4) 
            {
               p4++;
            }
            else
            {
               p3++;
               p4 = 1;
            }

            if (p3 == 5) 
            {
               p3 = 1;
               p2++;
            }

            if (p2 == 5) 
            {
               p2 = 1;
               p1++;
            }
    }
    cout << totalc << " combinações" << endl;    
}

comb5.h

#ifndef COMB5_H
#define COMB5_H

class comb5 {
public:
    comb5();
    comb5(const comb5& orig);
    virtual ~comb5();
    void elementos5();
private:

};
#endif /* COMB5_H */

comb5.cpp

#include 
using std::cout;
using std::endl;
#include 
#include "comb5.h"

comb5::comb5() {
}

comb5::comb5(const comb5& orig) {
}

comb5::~comb5() {
}

void comb5::elementos5()
{
   int p1 = 1, p2 = 1, p3 = 1, p4 = 1, p5 = 1;
   int total = pow(5,5);
   int totalc = 0;

   for (int i = 1; i <= total; i++) 
   {
      if (p1 != p2 && p1 != p3 && p1 != p4 && p1 != p5 && p2 != p3 && p2 != p4 && 
p2 != p5 && p3 != p4 && p3 != p5 && p4 != p5) 
      {
         totalc++;
         cout << p1 << " " << p2 << " " << p3 << " " << p4 << " " << p5 << endl;
      }

      if (p5 < 5) 
      {
         p5++;
      }
      else
      {
        p4++;
        p5 = 1;
      }

      if (p4 == 6) 
      {
        p4 = 1;
        p3++;
      }

      if (p3 == 6) 
      {
        p3 = 1;
        p2++;
      }

      if (p2 == 6) 
      {
        p2 = 1;
        p1++;
      }
      
  }
  cout << totalc << " combinações" << endl;     
}

comb6.h

#ifndef COMB6_H
#define COMB6_H

class comb6 {
public:
    comb6();
    comb6(const comb6& orig);
    virtual ~comb6();
    void elementos6();
private:

};

#endif /* COMB6_H */

comb6.cpp

#include 
using std::cout;
using std::endl;
#include 
#include "comb6.h"

comb6::comb6() {
}

comb6::comb6(const comb6& orig) {
}

comb6::~comb6() {
}

void comb6::elementos6()
{
    int p1 = 1, p2 = 1, p3 = 1, p4 = 1, p5 = 1, p6 = 1;
    int total = pow(6, 6);
    int totalc = 0;

    for (int i = 1; i <= total; i++) 
    {
        if (p1 != p2 && p1 != p3 && p1 != p4 && p1 != p5 && p1 != p6 && p2 != p3 &&
 p2 != p4 && p2 != p5 && p2 != p6 && p3 != p4 && p3 != p5 && p3 != p6 && 
p4 != p5 && p4 != p6 && p5 != p6) 
        {
           totalc++;
           cout <<  p1 << " " << p2 << " " << p3 << " " << p4 << " " << p5 << " " 
<< p6 << endl;
        }

        if (p6 < 6) 
          {
            p6++;
          }
        else
        {
            p5++;
            p6 = 1;
        }

        if (p5 == 7) 
        {
           p5 = 1;
           p4++;
        }

        if (p4 == 7) 
        {
           p4 = 1;
           p3++;
        }

        if (p3 == 7) 
        {
           p3 = 1;
           p2++;
        }

        if (p2 == 7) 
        {
           p2 = 1;
           p1++;
        }                                                                               
    }
    cout << totalc << " combinações" << endl;    
}
  • Shell Script
  • PHP
  • C++
Elementos Combinações Shell Script PHP C++
3 6 0m0.016s 0m0.00069s 0m0.005s
4 24 0m0.051s 0m0.0012s 0m0.005s
5 120 0m0.471s 0m0.015s 0m0.008s
6 720 0m9.639s 0m0.25s 0m0.023s
7 5040 5m44.219s 0m4.98s 0m0.159s
8 40320 142m51.553s 1m52s 0m1.712s
9 362880 - - 0m24.090s

sábado, 22 de setembro de 2012

Da base decimal para as bases binária, hexadecimal e octal

Há muito tempo já tinha reparado que não existia uma função pronta que converte da base decimal para binária.

Eu estava enganado e um professor falou da função itoa. No entanto, para minha decepção, a função não funciona apresentando o erro abaixo:

teste.c:(.text+0x4f): undefined reference to `itoa'

Como disse um velho amigo de programação: "você não precisa saber todos os comandos, funções e etecera. Se for criativo, você contorna a situação". Então criei minha própria forma de converter de decimal para binário. Basta executar o programa na linha de comando passando como parâmetro o número na base decimal. O código em C++ contém comentários descrevendo suas etapas.

Bibliotecas necessárias:

  • iostream
  • iomanip
  • cstdlib

Para converter de decimal para binário, a primeira tarefa é determinar a quantidade de divisões. Para tal, foi preciso que primeiro cálculo fosse feito fora do while para determinar o valor do quociente. Só então o loop while começa incrementando a variável divisoes.

A cada divisão, o valor do resto é armazenado em um vetor. Assim, cada cálculo, um índice é preenchido.

Para exibir o resultado, é impresso o quociente encontrado na última divisão e o vetor de restos do maior para o menor índice.

Para o valor hexadecimal, a namespace hex converte para hexadecimal. Finalmente, para o valor octal, a namespace oct converte para octal.

Apresento o código-fonte abaixo.


// Created by Murilo Fujita <murilofujita@gmail.com> in 09/21/2012

#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <iomanip>
using std::setprecision;
using std::setw;
#include <cstdlib>
using std::hex;
using std::oct;

int main(int argc, char** argv) {

    int pos=50; //quantidade de POSICOES do array
    int num,quo,res[pos], divisoes, numero;

    if (argc <2)
    {
      cout << "Digite um número na base decimal" << endl;
      exit(1);
    }

    num=atoi(argv[1]);

    numero=num; // num é usado para calculos; numero é usado para recuperar o input
    divisoes=0; // inicializa a quantidade de divisoes

    quo=num/2;
    res[0]=num%2; // precisa calcular o primeiro resto para o WHILE saber como comeca

    pos=1; // comeca em 1 porque o indice 0 ja foi calculado fora do loop
    while (quo>1)
    {
        quo=num/2; // quociente
        res[pos++]=num%2; // armezena os restos
        num=quo; // sacada para realizar as divisoes sucessivas
        divisoes++; //conta a quantidade de divisoes
    }
    cout << numero << " precisa de " << divisoes+1 << " bits." << endl;

    pos=divisoes;
    cout << "binário: ";
    cout << quo; // imprime o bit mais significativo: o quociente da ultima divisao
    for (int j=divisoes; j>0; j--)
    {
       cout << res[pos--]; // imprime os restos do ultimo indice para o primeiro
    }

    cout << endl;
    cout << "hexadecimal: " << hex << numero << endl;
    cout << "octal: " <<  oct << numero << endl;
    return 0;
}

E para concluir, dois exemplos da resposta do programa:

./bases_numericas.out 51966
51966 precisa de 16 bits.
binário: 1100101011111110
hexadecimal: cafe
octal: 145376

./bases_numericas.out 987654321
987654321 precisa de 30 bits.
binário: 111010110111100110100010110001
hexadecimal: 3ade68b1
octal: 7267464261

quinta-feira, 6 de setembro de 2012

Script para organizar a conjugação de verbos

Procurando ajudar uma colega taiwanesa que está se adaptando à nossa língua-pátria, eu respondo os e-mails mostrando a conjugação dos verbos para que ela entenda a concondância do pronome com a flexão do verbo.

Antes é necessário instalar o pacote brazilian-conjugate. O aplicativo apt-get instala o pacote através da linha de comando:

$ apt-get install brazilian-conjugate

Uma vez instalado, para chamar o aplicativo, digite:

$ conjugue

A figura abaixo mostra a tela assim que o programa inicia e em destaque vemos o comando que executa o conjugue bem como o verbo escolhido para ser conjugado (extorquir).


Figura 1. Tela Inicial do conjugue

Esta outra figura mostra a conjugação. Perceba que o programa reconhece os verbos defectivos e omite em certos pronomes.


Figura 2. Selecionando os tempos verbais

Note que o texto selecionado será copiado para área de memória e será usado como entrada para o script a seguir.

#!/bin/bash
# Created in September/02/2012

if [ "$#" -eq 0 ]
  then
    echo Falta o parâmetro dos verbos
  else
    conj1=`echo $1 | tr ":" " " | cut -f1 -d" "`
    conj3=`echo $1 | tr ":" " " | cut -f3 -d" "`
    conj4=`echo $1 | tr ":" " " | cut -f4 -d" "`
    conj6=`echo $1 | tr ":" " " | cut -f6 -d" "`

    echo eu $conj1
    echo ele/você $conj3
    echo nós $conj4
    echo eles/vocês $conj6
fi

Primeiro o script verifica se recebeu uma entrada ao ser chamado na linha de comando. Caso sim, as variáveis conj1, conj2, conj4 e conj6 associarão às flexões dos pronomes eu, ele, nós, eles respectivamente. Em seguida o echo imprime o pronome juntamente com o verbo flexionado. Como exemplo, vamos ver a saída do verbo extorquir no presente do indicativo:

./conjugador.sh :extorques:extorque:extorquimos:extorquis:extorquem
eu
ele/você extorque
nós extorquimos
eles/vocês extorquem

Repare que o script separa as flexões identificando o sinal de dois pontos (:). Assim, foram recebidos 5 parâmetros e reconhecido que não existe a primeira flexão.

Conclusão: Além de agilizar na orientação de como escrever corretamente, pode ser uma ferramenta de grande utilidade para evitar deslizes na língua portuguesa.