Os Tais Caracteres…

Nunca gostei desta salada de caracteres, wchar, mbs, blá, blá…

C, como o próprio nome diz é um Caractere. Simples assim UM CARACTERE.

Inventaram estas iconv, wchar.h, wctype.h e um monte de gambiarras para lidar com a questão de caracteres.

Bem, com a sutileza de um rinoceronte resolvi não esquentar a cabeça com esta coisa toda e me concentrei no problema simples que tinha: precisava de converter e eventualmente ordenar strings, em sua maioria ascii simples e eventualmente “perturbado” por acentos.

Como foi dito, meu problema é simples e não um editor de high-quality-tech ou um ordenador de bytes a ser usado pela Nasa.

Daí lembrei-me do básico – esta coisa toda são apenas apenas números. E números basta entender como são formados para se fazer algo útil com eles.

Percebi que para lidar com os tais multibyte (mbs) ou o widechar(wchar), algumas rotinas bem velhacas, lá do tempo do C89, já foram criadas e estão lá dentro do bom e velho stdlib.h:

  • mbtowc
  • wctomb
  • mbstowcs
  • wcstombs

São bem simples de usar e me ajudram a investigar o problema, mas no fim acabei não utilizando-as.

Convertendo um destes lindos caracteres para números, descobri que o primeiro byte encontrado – sem me importar com esta lenga-lenga de little endian, big endian que sempre me confundem (Fred disse que o menor… no menor é little endian…). Ok, não foi bem isto, mas foi assim que gravei na minha cabeça, acho que no endereço mais baixo vai o menos significativo para ser little endian enfim… O menor no menor e pronto!

Daí faço uma varredura no string, acho o bendito – que calha ser 0xC3 no utf-8 – e este é o meu sinal para pegar o próximo e converter usando uma tabela montada previamente.

Eu não me preocupei com os detalhes sórdidos de padrões e etc.

Então fiz os primores abaixo e estou feliz com eles. (Por enquanto)

#include <ctype.h>

int mtolower(int c)
{
    return ( -128 <= c && c < -96  ) ?  c += 32 : tolower(c);
}
int mtoupper(int c)
{
    return ( -96 <= c && c < -64  ) ?  c -= 32 : toupper(c);
}
int mnoaccent(int c)
{
    char _c[] = {
        /* ÀÁÂÃÄÅÆ -> A */ "AAAAAAA"
        /*       Ç -> C */ "C"
        /*    ÈÉÊË -> E */ "EEEE"
        /*    ÌÍÎÏ -> I */ "IIII"
        /*       Ð -> D */ "D"
        /*       Ñ -> N */ "N"
        /*   ÒÓÔÕÖ -> O */ "OOOOO"
        /*       × -> * */ "*"
        /*       Ø -> 0 */ "0"
        /*    ÙÚÛÜ -> U */ "UUUU"
        /*       Ý -> Y */ "Y"
        /*       Þ -> p */ "p"
        /*       ß -> B */ "B"
        /* àáâãäåæ -> a */ "aaaaaaa"
        /*       ç -> c */ "c"
        /*    èéêë -> e */ "eeee"
        /*    ìíîï -> i */ "iiii"
        /*       ð -> o */ "o"
        /*       ñ -> n */ "n"
        /*   òóôõö -> o */ "ooooo"
        /*       ÷ -> / */ "/"
        /*       ø -> 0 */ "0"
        /*    ùúûü -> u */ "uuuu"
        /*       ý -> y */ "y"
        /*       þ -> b */ "b"
        /*       ÿ -> y */ "y"
    };
    return
        (( -128 <= c && c < -96 ) || ( -96 <= c && c < -64  )) ? _c[c + 128] : c;
}

Nota: mstrnoaccent tem problema, acho que com o Ù (U com crase), que não é encontrado pelo sinal (0xC3) que tenho, parece que eles está em outra tabela. Como falo português e é nesta linda língua que pretendo usar estes trecos aí, o que consegui me bastou.

Lógico que em termos de precisão, usabilidade e um monte de coisas acadêmicas e etc, Estas rotinas não são, e nem pretendem ser, a melhor solução.

Se “melhor solução” existe, pra mim melhor solução é a que resolve o problema e solução ótima é a que resolve o problema sem te deixar com outro na mão. O que não é o caso da minha “melhor solução”.

Antes de usar esta coisa deve se habilitar o locale para português:

#include <locale.h>
.
.
.
    setlocale(LC_CTYPE, "pt_BR.utf-8");

{}’s
MaRZ

Anúncios

2 comentários sobre “Os Tais Caracteres…

  1. Só para melhorar sua rotina um cadinho só…
    Use a conversão feita palo iconv da libc do jeitinho mostrado no post anterior. Os caracteres wchar_t tem relação direta com UTF-16… Assim, você pode construir sua tabela de conversão com valores de 16 bits (basta ver o valor que segue o “U+”, no Charmap).

    Você pode querer fazer isso com 7 faixas do UNICODE: Basic Latin (não precisa de “tradução”), Latin-1 Supplement (de U+00A1 até U+00FF), Latin Extended-A (de U+0100 até U+017F), Latin Extended-B (de U+0180 até U+01FF), Latin Extended-C (de U+2C60 até U+2C7F), Latin Extended-D (de U+A7260 até U+A78C) e Latin Extended Additional (de U+1E00 até U+1EF9).

  2. Ok, talvez eu faça isto no futuro, mas como disse, no momento a gororoba do jeito que ficou me atende.
    O meu foco é poder usar a rotina somente com stdlib (C89).
    A otimização não compensa e seria mais uma lib a carregar para outro sistema caso precisa-se utilizá-la. Não sei se encontraria a iconv ou libiconv por lá.
    Antes porém, eu teria que estudar unicode e adjacências… Definitivamente não é minha prioridade. Estou começando por estruturas básicas no momento.

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s