Processamento de Texto
Pedro Barahona
DI/FCT/UNL
Introdução aos Computadores e à Programação
2º Semestre 2008/2009
8 Maio 2008
Processamento de Texto
1
Processamento de Texto
•
Muita informação útil, nomeadamente em tarefas de gestão, não é do tipo
numérico.
•
Por exemplo, variadas entidades (pessoas, empresas, disciplinas, departamentos,
etc...) têm associado um nome que se pode querer processar (por exemplo,
procurar, ordenar, passar para maiúsculas, etc...).
•
Este é apenas um exemplo de situações em que se pretende que os programas
efectuem processamento de texto.
•
Assim, todas as linguagens de programação prevêem tipos de dados para este
fim, nomeadamente
– Caracteres;
– sequências de caracteres (“strings”).
8 Maio 2008
Processamento de Texto
2
Caracteres e seus Códigos
•
Os caracteres mais utilizados (representados no código ASCII - American
Standard Code for Information Interchange) incluem
•
Letras (52), maiúsculas (26) e minúsculas (26)
•
Dígitos (10)
•
Espaço e outros caracteres “visíveis” (34)
–
•
‘“()[]{},.:;=<>+-*\|/^~´`#$%&_!?@
Caracteres de controle (32)
– horizontal tab (\t), new line (\n), alert (\a), ...
•
Outros caracteres, (ç, ã, ñ, š , ø , ∞,  , Σ, ш, ‫ך‬, ‫ﭏ‬, ‫ )غغ‬só podem ser
representados em códigos mais avançados e não são “suportados” em algumas
linguagens de programação (em Octave, uma variável não pode ter o nome
“acção”)
8 Maio 2008
Processamento de Texto
3
Sequências de Caracteres
•
Sequências de caracteres (“strings”) são conjuntos de caracteres, com uma
ordenação determinada.
•
Em quase todas as linguagens, dados do tipo caracter e sequência (incluindo
sequências simples, com um só caracter) são representados entre delimitadores,
que podem ser aspas (“ ”) ou plicas (‘ ’), devendo abrir-se e fechar-se com o
mesmo tipo de delimitadores.
•
Quando se pretende incluir um dos delimitadores no texto, pode usar-se o outro
delimitador
nome = “João d’Eça”
ou
frase= ‘ disse “Basta”’
•
...ou usarem-se sequências de escape
nome = ‘João d’’Eça’
•
ou
frase = “disse \“Basta\””
... que por vezes não se podem evitar
– frase_toda = “João d’Eça disse \”Basta\””
– frase_toda = ‘João d’’Eça disse “Basta”’
8 Maio 2008
Processamento de Texto
ou
4
Sequências de Caracteres e Vectores
•
Em geral, e o Octave não foge à regra, sequências de caracteres são
“implementadas” como vectores dos códigos dos caracteres.
•
Muitas funções e operações em Octave exigem a utilização do tipo correcto. Duas
funções permitem transformar
– Vectores em sequências : toascii: <sequência>  <vector>
 a = [65,66,67]
>> a = toascii(“ABC”)
– Sequências em vectores :
setstr: <vector>  <sequência>
>> b = setstr([97,98,99])
•
O Octave não é muito estrito no que se refere aos tipos de dados. Por exemplo,
permite operações “numéricas” com sequências, fazendo a conversão de tipos
necessária
>> c = ‘abc’ * 1
•
 b = ‘abc’
 c = [97,98,99]
Nota: Estas “facilidades” tornam difícil a detecção de erros de programação e não
devem ser usadas (ou apenas com muito cuidado)
8 Maio 2008
Processamento de Texto
5
Conversão de Sequências de Caracteres
•
Sequências de caracteres podem ser processados de várias formas. Para as mais
comuns, existem funções pré-definidas.
•
Algumas dessas funções permitem converter sequências de caracteres que
representam números para os próprios números.
•
Exemplo: Dada a sequência “ 23.76 ” (com espaços), a sua conversão para um
número é obtida com a função str2num.
>> s = “ 23.76
“; a = str2num(s); b = 2*a
 b = 47.52
•
É interessante comparar o resultado acima com (porquê???)
>> s = “ 23.76
“; b = 2*s
 s = [64,100,102,92,110,108,64,64]
•
A conversão oposta, pode fazer-se com a função num2str.
8 Maio 2008
Processamento de Texto
6
Partição de Sequências de Caracteres
•
As sequências podem ser “partidas” noutras mais simples, havendo várias formas
de fazer essa partição.
•
Uma forma possível é através de caracteres que funcionam como separadores
(tipicamente espaços).
•
O Octave tem uma função, split, para esse efeito, criando uma matriz de
sequências, cada sequência na sua linha, com brancos acrescentados se
necessário
•
Exemplo: Separar os nomes (próprios e apelidos) de uma pessoa.
>> nome = “Rui da Costa Pina”; nms = split(nome,“ ”)
 nms =
“Rui
”
“da
”
“Costa”
“Pina ”
8 Maio 2008
Processamento de Texto
7
Concatenação de Sequências de Caracteres
•
As sequências podem ser concatenadas. Esta operação é utilizada para juntar
numa só sequência a informação que está dispersa por várias sequências. Por
exemplo, para juntar
– O(s) nome(s) próprio(s) ao(s) apelido(s)
– Os vários campos de um endereço (rua, nº, andar, local, etc.)
•
O Octave tem uma função strcat, para esse efeito.
•
Exemplo: Juntar um nome próprio e um apelido, separados por um espaço.
>> np = “Rui”; ap = “Lopes”; nome= strcat(np,“ ”,ap)
 nome = “Rui Lopes”
•
Dada a representação de sequências como vectores em Octave, o mesmo efeito
se conseguiria através da concatenação de vectores:
>> np = “Rui”; ap = “Lopes”; nome = [np,“ ”,ap]
8 Maio 2008
Processamento de Texto
8
Extracção de Sequências de Caracteres
•
Por vezes estamos interessados apenas em partes de uma sequência. Uma forma
comum de o fazer é indicar
– o índice do primeiro caracter pretendido para a subsequência; e
– o comprimento da subsequência.
tendo o Octave tem uma função, substr, para esse efeito.
•
Por exemplo: Separar os nomes (próprios e apelidos) de uma pessoa.
>> n = “Rui Andrade”; n1 = substr(n,1,3), n2 = substr(n,5,7),
 nm1= “Rui”, nm2= “Andrade”
•
O mesmo efeito se obteria pala definição de intervalos no vector, isto é
>> n = “Rui Andrade”; n1 = n(1:3), n2 = n(5:lenght(n))
 nm1= “Rui”, nm2= “Andrade”
•
Que utiliza afunção predefinida length.
>> x = length(nome)
 x= 17
8 Maio 2008
Processamento de Texto
9
Comparação de Caracteres
•
Uma operação vulgar no processamento de texto é a ordenação “por ordem
alfabética”.
•
Esta ordenação requer a comparação “alfabética” de caracteres.
•
Esta pode ser feita através da comparação “numérica” dos códigos dos
caracteres.
•
A comparação só é fácil se os códigos usados respeitam a ordem alfabética, o
que acontece em todos os códigos.
•
Por exemplo, em ASCII, o código dos caracteres “A” e “B” é, respectivamente, 65
e 66, pelo que se pode fazer a correspondência pretendida
o caracter c1 “vem antes do” caracter c2  c1 < c2
•
Exemplo: >> teste = “a” < “b”
 teste = 1
8 Maio 2008
Processamento de Texto
10
Comparação de Caracteres
•
A comparação “alfabética” de caracteres está assim muito dependente do código
utilizado na sua representação..
•
Se os código ASCII preserva a ordenação dos caracteres se ambos forem
maiúsculos ou minúsculos, já o mesmo não se verifica se um for maiusculo e
outro minúsculo.( por exemplo ‘a’ > ‘B’ !).
•
O Octave tem algumas funções que facilitam o tratamento deste tipo de situações,
nomeadamente as funções tolower e toupper, que convertem os caracteres
maiúsculos / minúsculos em caracteres minúsculos / maiúsculos.
>> ‘a’ < ‘B’,
ans = 0
>>
>>
8 Maio 2008
a = toupper(‘a’),
a = ‘A’
b =
a = tolower(‘a’),
a = ‘a’
b =
b = toupper(‘B’), a < b
‘B’,
ans = 1
b = tolower(‘B’), a < b
‘b’,
ans = 1
Processamento de Texto
11
Comparação de Caracteres
•
A comparação “literal” pode ser obtida a partir da comparação caracter a caracter.
•
O Octave tem uma função, strcmp, para verificar se duas cadeias são idênticas.
nm1 = “Rui Costa”; nm2 = “Rui Costa”; t = strcmp(nm1,nm2)
t=1
•
Não havendo função semelhante para que indique se uma sequência precede
ourtra, vamos implementar a função my_strcomp como:
my_strcmp (s1,s2) =
•
-1
se s1 << s2
0
se s1 = s2
1
se s1 >> s2
Desta forma, a função my_strcmp compara os primeiros caracteres das
sequências (se existirem). Se estes forem iguais, compara as caudas das
sequências (chamada recursiva).
8 Maio 2008
Processamento de Texto
12
Comparação de Sequências de Caracteres
function b = my_strcmp(s1,s2)
c1 = length(s1); c2 = length(s2);
if
c1 == 0 & c2 == 0
b = 0;
elseif c1 == 0 & c2 > 0
b = -1;
elseif c1 > 0 & c2 == 0
b = 1;
else
% c1 > 0 & c2 > 0
if
s1(1) < s2(1)
b = -1;
elseif s1(1) > s2(1)
b = 1;
else
t1 = s1(2:c1);
t2 = s2(2:c2);
b = my_strcmp(t1,t2);
endif;
endif;
endfunction;
•
8 Maio 2008
De notar o caso em que as duas cadeias são vazias ou em que uma é vazia e a
outra não.
Processamento de Texto
13
Comparação de Sequências de Caracteres
• A comparação de cadeias de caracteres “interpretáveis” (por exemplo, de texto em
português) é mais complexa.
• Os problemas mais frequentes são de 3 tipos:
– Ocorrência de espaços (e outros caracteres brancos)
•
“Rui Santos” = “ Rui Santos “ ???
– Tratamento de letras maiúsculas e minúsculas
•
“Rui Santos” = “RUI SANTOS “ ???
– Caracteres especiais (com acentos e cedilhas)
•
“João França” = “Joao Franca“ ???
• Estes problemas têm de ser considerados no contexto apropriado (Franca e França
são apelidos diferentes, ou o terminal (telemóvel) não tinha o caracter “ç” ?), e
requerem algoritmos dedicados.
8 Maio 2008
Processamento de Texto
14
Comparação de Sequências com Brancos
• Existem vários caracteres de controle que servem para dar instruções ao computador
(mudar de linha, avançar o cursor para a próxima posição de tabela, etc.).
• Os mais vulgares são os caracteres de mudança de linha (“\n”, “\r” ou “\f”), e os de
tabulação (“\t” e “\v”)
Nota: usar aspas “ para delimitar sequências com estes caracteres.
• Adicianalmente, e em conjunto com os espaços, estes caracteres são considerados
brancos (não visíveis) e usados para separar “palavras” de caracteres visíveis.
• No código ASCII os caracteres de controle têm códigos inferiores a 32 (espaço). Em
todo o caso, a função Octave iscntrl(c) indica se o caracter c é um caracter de
controle, independentemente do código usado no computador.
• Assim pode definir-se a função blank(c) que indica se o caracter c é um caracter
branco
function b = blank(c)
b = (c == ‘ ‘ | iscntrl(c));
endfunction;
8 Maio 2008
Processamento de Texto
15
Comparação de Sequências com Brancos
• A comparação do conteúdo das sequências de caracteres pode assim simplificar-se
se a comparação fôr feita após normalização. Esta normalização, consiste em
– eliminar todos os separadores prefixos e sufixos, i.e. antes e depois do primeiro
e último caracter significativo, respectivamente.
– Eliminar todos os separadores repetidos, e substituí-los por um só espaço.
• Algumas funções pre-definidas podem auxiliar na normalização, mas o Octave não
tem esta função predefinida.
• Por exemplo, o Octave dispõe de uma função (deblank) que elimina todos os
espaços sufixos. Uma função semelhante, d2blank, pode ser implementada para
eliminar todos os espaços prefixos.
function t = d2blank(s)
i = 1;
while blank(s(i)) i = i+1;
t = s(i:length(s))
endfunction;
8 Maio 2008
endwhile;
Processamento de Texto
16
Eliminação de Brancos Repetidos
• A eliminação de brancos repetidos pode ser feita pela função ssumindo que todos
os caracteres brancos têm código inferior a 32, podemos utilizar a função remdup,
indicada abaixo, para substituir todos os caracteres brancos por espaços.
• A função varre todos os caracteres de
s a partir da segunda posição (o
• Para cada um, se ele não for branco
escreve-o em t (actualizando j, o
próximo caracter de t)
• Se for branco, só o escreve se o
anterior não tiver sido branco.
8 Maio 2008
function t = remdup(s)
if length(s) >= 1
t(1) = s(1); j = 2;
for i = 2:length(s)
if ! blank(s(i))
t(j) = s(i);
j = j +1;
elseif ! blank(s(i-1))
t(j) = ' ';
j = j + 1;
endif
endfor
endif
endfunction;
Processamento de Texto
17
Normalização de Sequências de Caracteres
• A normalização de cadeias de caracteres pode ser feita usando a função str_norm,
indicada abaixo, que utiliza todas as funções anteriores, da forma esperada.
• Primeiro, substitui os brancos por espaços. Depois elimina os espaços sufixos. Em
terceiro lugar elimina os espaços prefixos (eliminando os espaços sufixos da cadeia
invertida, invertendo de novo o resultado). Finalmente, os espaços repetidos são
removidos.
function sn = strnorm(s)
s1 = deblank(s)
s2 = d2blank(s1);
sn = remdup(s2)));
endfunction;
8 Maio 2008
Processamento de Texto
18
Eliminação de Espaços Repetidos
• A comparação de cadeias de caracteres pode ser feita usando a função
my_strcmpnorm, indicada anteriormente, que não considera os espaços repetidos
nem os caracteres brancos.
function b = normcmp(s1,s2)
sn1 = strnorm(s1);
sn2 = strnorm(s2);
b = my_strcmp(sn1,sn2);
endfunction;
• As diferenças podem ser exemplificadas em baixo.
>> t = normcmp(“Rui Lopes”, “ Rui Lopes”)
 t = -1
>> t = my_str_norm_before(“Rui
Lopes”, “ Rui Lopes”)
 t = 0
8 Maio 2008
Processamento de Texto
19
Comparações com Maiúsculas / Minúsculas
• A comparação de cadeias de caracteres pode ser igualmente prejudicada pela
existência de letras maiúsculas e minúsculas.
• O Octave tem algumas funções que facilitam o tratamento deste tipo de situações,
nomeadamente as funções tolower e toupper, que convertem os caracteres
maiúsculos / minúsculos em caracteres minúsculos / maiúsculos.
>> s1 = “\n Rui \t Lopes”; s2 = “RUI lopes”;
sn1 = toupper(s1), sn2 = toupper(s2),
t1 = my_str_norm_before(s1,s2),
t2 = my_str_norm_before(sn1,sn2)

8 Maio 2008
sn1 = “\n RUI \t LOPES”
sn2 = “RUI LOPES”
t1 = -1
t2 = 0
Processamento de Texto
20
Conversões Independentes do Código
• Algumas primitivas adicionais do Octave para testar tipos de caracteres
– isalpha(s)
1 se s fôr alfabético (maiúscula ou minúscula)
– islower(s)
1 se s fôr uma minúscula
– isupper(s)
1 se s fôr uma maiúscula
– isdigit(s)
1 se s fôr um dígito
– isalnum(s)
1 se s fôr dígito ou alfabético
– ispunct(s)
1 se s fôr um caracter de pontuação
– iscntrl(s)
1 se s fôr caracter de controle
8 Maio 2008
Processamento de Texto
21
Sequências com Caracteres Especiais
• Os caracteres com cedilhas e acentos, típicos do português, não fazem parte do
código ASCII básico, e os seus códigos em ASCII estendido não respeitam a ordem
“natural”.
• Por exemplo, como os códigos dos caracteres “a”, “s” e “ã” são, respectivamente
97, 115 e 227, o nome João está alfabeticamente após José, ao contrário do que
acontece com Joao.
• Uma forma de manter a ordenação pretendida é utilizar, para efeitos de ordenação,
as cadeias com os caracteres acentuados substituídos pelos caracteres não
acentuados.
• O Octave dispõe de uma função (strrep) que substitui numa cadeia base, todas as
de uma (sub)cadeia por outra.
>> s1 = “João”; s2 = strrep(s1,”ã”,”a”)
 s2 = “Joao”
8 Maio 2008
Processamento de Texto
22
Download

pp - SSDI