sábado, 26 de outubro de 2013

Acrónimos

Numa das aulas foi pedido um programa para resolver o problema de gerar um acrónimo a partir de uma cadeia de caracteres. Por exemplo, “Ernesto Jorge Fernandes Costa” deve dar como resultado “EJFC”. Os acrónimos devem ser sempre em maiúsculas. No caso de “random access memory” o resultado deverá ser “RAM”.
Alguns resolveram o problema de um modo simples: percorrer a cadeia à procura do espaço em branco, que separa as palavras, para escolher o caractere seguinte. Vamos ver o código.
def acronimo_alunos(cadeia):
    """Extrai o acrónimo da cadeia."""
    cadeia = cadeia.upper()
    acro = cadeia[0]
    for i in range(1, len(cadeia)-1):
        if cadeia[i] == ' ':
            acro = acro + cadeia[i+1]
    return acro
O programa começa por converter toda a cadeia para maiúsculas. De seguida começa por formar o acrónimo com o primeiro caractere da cadeia que, por definição, será sempre o primeiro caractere da primeira palavra. Dentro do ciclo procura o espaço em branco e vai buscar o caractere seguinte para juntar ao acrónimo. Testando com os dois exemplos acima dá o resultado esperado. Perfeito! Perfeito??
E se existirem caracteres brancos no início ou no final? E se existir mais do que um espaço em branco a separar as palavras? Se testar verificará que a sua solução cai por terra. Enfim, cai por terra no caso de ser possível acontecer o descrito. Vamos admitir que sim e procurar uma nova solução.
def acronimo(cadeia):
    """
    Constrói o acrónimo a partir de uma frase 
    representada por uma cadeia de caracteres.
    """
    acro = ''
    inicio = True
    for car in cadeia:
        if car == ' ':
            inicio = True
        elif inicio == True:
            acro += car.upper()
            inicio = False
    return acro
O que fizemos? Algo de muito simples: usamos um indicador booleano (os ingleses dizem uma flag - bandeira) para nos dizer quando estamos à procura do início de uma palavra. Isso é verdade enquanto não encontrarmos um caractere diferente do branco! Quando isso acontece juntamos o caractere depois de o converter para maiúsculas associando-o ao nome acro que funciona como um acumulador. Experimente agora e verá que funciona para todas as situações.
Existem outras soluções para o problema. A primeira que vamos mostrar introduz implicitamente conceitos que ainda não demos (no caso objectos do tipo lista, ako de tuplos mas mutáveis).
def acronimo(cadeia):
    acro = ''
    nova_cadeia = cadeia.strip().split()
    for pal in nova_cadeia:
        acro += pal[0].upper()
    return acro
Nesta solução começamos por tirar os espaços em branco nas extremidades esquerda e direita da cadeia (método strip) e dividimos o que fica na sequência das palavras que a constituem (método split). Agora, no ciclo for, apenas temos que ir buscar o primeiro caractere de cada palavra, passá-lo a maiúsculas e juntar tudo. Simples, não é?
A última solução que vamos apresentar utiliza o conceito de ciclo variável (ciclo while) que será discutido numa das próximas aulas.
def acronimo(frase):
    """ Forma um acronimo a partir da frase."""
    frase = frase.upper().strip()
    comprimento = len(frase)
    acron = ''
    posicao = 0
    while posicao < comprimento:
        acron = acron + frase[posicao].upper()
        while (posicao < comprimento) and (frase[posicao] != ' '):
            posicao = posicao + 1           
        while (posicao < comprimento) and (frase[posicao] == ' '):
            posicao = posicao + 1
    return acron 
Começamos por passar tudo para maiúsculas e retirar os espaços em branco nas extremidades. De seguida vamos percorrer posição a posição a cadeia. Sabemos que o primeiro caractere da cadeia sem os espaços na extremidade tem que fazer parte do acrónimo. Depois passamos por todos os caracteres significativos até aparecer um espaço em branco (primeiro ciclo while interior). De seguida passamos por cima dos espaços em branco (segundo ciclo while interior) e voltamos ao início do ciclo while principal. Se ainda existirem caracteres ele terá que ir de novo para o acrónimo pelo que o ciclo se repete.

Moral da História: (1) Nem sempre o que parece é! (2) Vários são os caminhos que nos levam a Roma!

2 comentários:

  1. Este comentário foi removido pelo autor.

    ResponderEliminar
    Respostas
    1. O programa está correcto. Deve estar a cometer algum erro na transcrição (aliás tem um na chamada pois apenas manda fazer o print e não chama o programa,...).

      O método strip() serve para tirar os espaços em branco à esquerda e à direita de uma cadeia de caracteres. Quando fazemos o split por espaços em branco então não precisa realmente de usar o strip. Se o critério de divisão for outro, então em geral (depende do problema) precisa usar primeiro o strip. Acabei por escrever um programa mais geral.

      Eliminar