quarta-feira, 7 de julho de 2010

Substituindo caracteres acentuados em strings, no NCL

Num destes dias me deparei com uma tarefa bem interessante: criar arquivos individuais (formato ASCII), cujos nomes são compostos de strings retirados dos dados lidos. Neste caso específico, os dados eram as coordenadas espaciais dos limites municipais dos municípios do Estado de São Paulo.

Estes dados estão disponíveis para download no site do IBGE e estão no formato shapefile, que é um formato de dados vetoriais geoespaciais. O NCL suporta a leitura deste tipo de arquivo e vários exemplos estão disponíveis em http://www.ncl.ucar.edu/Applications/shapefiles.shtml. Logo colocarei um exemplo bem prático aqui.

O ponto principal e motivador deste "post" é que os nomes dos municípios, nestes arquivos, estão acentuados. Do ponto de vista de exibição do nome não há nenhum problema. Entretanto, quanto tenta-se automatizar a procura de algum município ou a geração de arquivos com as suas coordenadas limites, tendo seu nome como o nome do arquivo, as coisas complicam. Por padrão, o NCL não aceita caracteres acentuados (veja mais sobre isso em um post anterior).

Portanto, faz-se necessário um tratamento prévio das strings com o nome dos municípios antes de usá-los apropriadamente. Como a dor ensina a gemer tive que me virar para resolver este probleminha. A solução: comparar os valores decimais dos caracteres (tabela ASCII/ANSI) e substituí-los pelos mesmos caracteres sem acento.

Abaixo está uma função que criei para isto:

undef("ansi2ascii")
function ansi2ascii( string1:string )
local dummy,idxANSI,dimsANSI,i
begin
; quebra a string passada a funcao
; em um arranjo unidimensional de
; caracteres
dummy = chartoint( stringtochar( string1 ) )

; indices da tabela ANSI (ASCII extendido) com os valores
; correspondentes aos caracteres acentuados
; neste arranjo, tem-se, para cara linha:
; coluna 0 => indice inferior
; coluna 1 => indice superior
; coluna 2 => indice do caracter substitutivo
idxANSI = (/ (/192,197,65/),\ ; caractere A
(/200,203,69/),\ ; caractere E
(/204,207,73/),\ ; caractere I
(/210,214,79/),\ ; caractere O
(/217,220,85/),\ ; caractere U
(/224,229,97/),\ ; caractere a
(/232,235,101/),\ ; caractere e
(/236,239,105/),\ ; caractere i
(/242,246,111/),\ ; caractere o
(/249,252,117/),\ ; caractere u
(/199,199,67/),\ ; caractere Ç
(/231,231,99/),\ ; caractere ç
(/209,209,78/),\ ; caractere Ñ
(/241,241,110/),\ ; caractere ñ
(/39,39,32/) /) ; caractere ' (apóstrofo)

; dimensoes do arranjo com codigos ASCII/ANSI.
dimsANSI = dimsizes( idxANSI )

do i = 0, dimsANSI(0)-1
; substitui os caracteres acentuados de acordo com os
; codigos passados no arranjo idxANSI
dummy = where( dummy.ge.idxANSI(i,0) .and. dummy.le.idxANSI(i,1),\
idxANSI(i,2), dummy )
end do

; converte o arranjo unidimensional de caracteres a uma string
RESULT = chartostring( inttochar( dummy ) )

; retorna a string
return( RESULT )
end

Suponha que, lendo o conteúdo de um arquivo, obtém-se uma string contendo: "NCL não aceita acentuação". Esta string é colocanda numa variavel myString. Aplicando a função acima neste variável:

myStr = ansi2ascii( myString )

resultará no conteúdo "NCL nao aceita acentuacao" para a variável myStr. O conteúdo desta nova variável pode ser manipulado normalmente dentro do NCL.

A função utiliza índices inferior e superior para cada caractere. Isto porque a tabela ANSI está organizada de uma forma que todas as acentuações em um dado caractere estão dispostas sequencialmente. Veja o caso dos caracteres A acentuados: À=192; Á=193; Â=194; Ã=195; Ä=196; Å=197.

Usando isto em favor próprio, basta verificar se o código decimal ANSI de um dos caracteres da string analisada encontra-se entre 192 e 197. Caso positivo, substituí-se seu valor por 65, o código ASCII do caractere A.

Note que a função é bem flexível. Se mais caracteres devem ser procurados e substituídos, basta adicionar seu(s) código(s) no arranjo idxANSI, dentro da função. Nada mais precisa ser feito. Outro ponto que deve ser observado é o caso de caracteres únicos, como por exemplo, ñ, Ñ, ç e Ç. Nestes casos, basta definir os índices inferior e superior com o mesmo valor. Veja na própria função como isto é feito.

Pronto, tarefa realizada e menos um problema em aberto!

Até a próxima.

PS.: Lembre-se, toda e qualquer função ou biblioteca de funções deve ser carregada no "preâmbulo" do script, ou seja, antes corpo principal do script, entre begin ... end.