Aula 15: Strings

Tópicos

Aulas a distância - Google Meet:

Para verem os vídeos, vocês devem estar logados no e-mail da usp.

Um string (=tipo str) é uma sequência de caracteres.

Por ser uma sequência de caracteres, podemos fazer uma analogia de strings com listas em Python. Assim como elementos de listas, um caractere de um string pode ser acessado por meio de um índice, o comprimento pode ser dado pela função len(), e os caracteres podem ser fatiados e concatenados. Veja os exemplos abaixo:

>>> texto = "Devagar se chega ao longe"
>>> len(texto)
25
>>> texto[0]
'D'
>>> texto[8]
's'
>>> texto[11:16]
'chega'
>>> texto[20:]
'longe'

A grande diferença em relação às listas (que são dados mutáveis) é que strings em Python são imutáveis, ou seja, não é possível alterar seus elementos. Veja os exemplos abaixo:

>>> nome = "Paulo"
>>> nome[4] = 'a'
Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    nome[4] = 'a'
TypeError: 'str' object does not support item assignment

>>> nome = "Paulo"
>>> nome.append(" Miranda")
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in
    nome.append(" Miranda")
AttributeError: 'str' object has no attribute 'append'

Para gerar modificações em um texto fornecido em Python, é necessário criar um novo string. Para isso, podemos gerar novos strings usando o operador de concatenação e o comando de fatiamento. O operador de concatenação gera um novo texto com conteúdo igual à fusão dos dois textos fornecidos. O comando de fatiamento gera cópias de trechos específicos extraídos do texto fornecido. Veja os exemplos abaixo:

>>> nome = "Paulo"
>>> nome = nome[:len(nome)-1] + 'a'
>>> print(nome)
Paula

>>> nome = "Paulo"
>>> nome = nome + " Miranda"
>>> print(nome)
Paulo Miranda

Representação de caracteres (funções ord e chr)

Um conhecimento importante para trabalhar com strings é o de conhecer a sua forma de representação. Strings são sequências de caracteres. Um caractere é um símbolo tipográfico usado para escrever texto em alguma língua. Em Python 3.X, um caractere é uma string de comprimento 1.

Como vimos na primeira aula deste curso, tudo o que um computador armazena e processa são números (internamente no sistema binário). Para que possam ser processados pelo computador, precisamos representar os caracteres por meio de números.

Existem diferentes codificações (= representações numéricas) que podem ser usadas para caracteres. Algumas codificações são específicas para uma língua (como Chinês, Russo, etc), enquanto outras podem ser usadas para múltiplas línguas. Um mesmo caracter pode aparecer em diferentes codificações; entretanto, duas codificações diferentes podem usar códigos numéricos diferentes para representar um mesmo caracter, gerando problemas de incompatibilidade. Para solucionar esses problemas e prover uma representação unificada dos alfabetos de todas as línguas da humanidade, o padrão Unicode foi desenvolvido. O Unicode fornece um número único para cada caractere, independentemente da plataforma ou programa.

Na versão 3.X do Python strings são armazenadas no padrão Unicode em uma instância do tipo str. Para obter o código Unicode de um caracter, como um inteiro, podemos usar a função ord() do Python. Já o caminho inverso pode ser feito usando a função chr(). Veja os exemplos abaixo:

>>> ord('a')
97
>>> ord('b')
98
>>> ord('c')
99
>>> ord('z')
122
>>> ord('8')
56
>>> ord('9')
57
>>> ord('?')
63
>>> chr(97)
'a'
>>> chr(122)
'z'
>>> chr(56)
'8'
>>> chr(63)
'?'

Curiosidades:

No Python 2.X, o tipo unicode é usado para expressar cadeias Unicode, enquanto instâncias do tipo str são representações de byte.

Uma das codificações mais conhecida é a ASCII (American Standard Code for Information Interchange), que foi definida como um padrão em 1968. A ASCII foi criada para representar caracteres da língua inglesa. No ASCII os caracteres numerados de 0 a 31 são considerados de controle, e os de 32 a 127 correspondem aos caracteres comuns de um teclado de computador em inglês, incluindo letras, dígitos decimais e sinais de pontuação. Como um código ASCII é um número entre 0 e 127, ele pode ser armazenado usando-se apenas 7 bits, ou seja, ele cabe dentro de um byte (= 8 bits). A numeração da tabela Unicode é compatível com a tabela ASCII. Logo, podemos executar o seguinte programa para ver os caracteres de 32 a 127 da tabela ASCII:

print("Tabela ASCII de 32 a 127: ")
for i in range(32, 128, 3):
    print("ASCII[ %3d ] = '%s'  |  ASCII[ %3d ] = '%s'  |  ASCII[ %3d ] = '%s'"%
    (i, chr(i), i+1, chr(i+1), i+2, chr(i+2)))
  
Infelizmente, o alfabeto ASCII não é suficiente para escrever texto em português, pois não contém vogais com acentos e o til (ex: á, ã, é, etc) e não possui a cedilha que se coloca sob a letra c (produzindo ç). Para lidar com esse problema, nos anos 80 várias extensões do ASCII foram criadas usando os valores entre 128 e 255 como códigos para caracteres acentuados, resultando em códigos de 1 byte. Um exemplo de uma dessas extensões, usada para a língua portuguesa, é a codificação ISO-8859-1, também chamada de Latin1. Os 256 primeiros códigos Unicode são idênticos aos do padrão ISO-8859-1 de forma que para exibir os demais caracteres ocidentais com acentos no Python 3.X basta imprimir também os caracteres no intervalo de 160 a 255:
print("Tabela ISO-8859-1 (Latin1) de 160 a 255: ")
for i in range(160, 256, 3):
    print("Latin1[ %3d ] = '%s'  |  Latin1[ %3d ] = '%s'  |  Latin1[ %3d ] = '%s'"%
    (i, chr(i), i+1, chr(i+1), i+2, chr(i+2)))
  

Acessando caracteres não disponíveis no teclado

Para acessar caracteres não disponíveis no teclado, podemos obter os seus números/códigos Unicode (conhecidos como code points), consultando a tabela Unicode na internet, e depois basta aplicar a função chr() para fazer a conversão do código inteiro para string.

Em geral, entretanto, esses números são escritos em notação hexadecimal (base 16). Além disso, usualmente os code points são apresentados incluindo o prefixo U+ a cada número.

Por exemplo, considere a tabela abaixo que mostra os códigos Unicode de alguns caracteres do alfabeto grego:

Lista de alguns caracteres gregos em Unicode:
número
Unicode
caractereDescrição
U+03B1 α Alpha
U+03B2 β Beta
U+03B3 γ Gamma
U+03B4 δ Delta
U+03B5 ε Epsilon
U+03B6 ζ Zeta
U+03B7 η Eta
U+03B8 θ Theta

A lista completa de caracteres e seus números Unicode pode ser vista na página List of Unicode characters da Wikipedia.

Por exemplo, para imprimir a letra beta, podemos usar o seguinte código:

>>> beta = chr(0x03B2)
>>> print(beta)
β

Em 0x03B2, a parte 0x é o padrão utilizado pelo Python para indicar que o valor na sequência 03B2 deve ser interpretado como um inteiro expresso em notação hexadecimal. Ou seja, 0x03B2 é o código Unicode da letra beta.

Em Python 3.X, podemos também usar a seguinte solução alternativa:

>>> beta = "\u03B2"
>>> print(beta)
β

Problema 1:

Escreva um programa que contabiliza a frequência relativa de vogais em um texto fornecido em uma linha pelo usuário.

Observação: Por questões de simplicidade, assuma o padrão ASCII e ignore vogais acentuadas, tais como à, á, ã, etc.

Exemplo: Para o texto "Paulo" temos a seguinte saída do programa.

Digite um texto: Paulo
Frequência rel. = 3/5 = 0.600000

Solução 1:

Ao invés de testar cada vogal com uma condição correspondente sendo explicitamente escrita (ex: if letra == 'a' or letra == 'e' or ... or letra == 'u':), na solução abaixo consideramos uma string contendo todas possíveis vogais, de modo que podemos então usar o teste mais simples if letra in vogais:.

def main():
    texto = input("Digite um texto: ")
    vogais = "aeiouAEIOU"
    n = len(texto)
    nv = 0  #número de vogais no texto.
    for letra in texto:
        if letra in vogais:
            nv += 1
    print("Frequência rel. = %d/%d = %f"%(nv,n,nv/n))

main()
  

Solução 2:

Solução um pouco mais complexa, utilizando laços encaixados com as variáveis de controle i e j correspondendo aos índices das strings texto e vogais, respectivamente.

def main():
    texto = input("Digite um texto: ")
    vogais = "aeiouAEIOU"
    n = len(texto)
    nv = 0  #número de vogais no texto.
    for i in range(n):
        for j in range(len(vogais)):
            if texto[i] == vogais[j]:
                nv += 1
    print("Frequência rel. = %d/%d = %f"%(nv,n,nv/n))

main()
  

Problema 2:

Escreva um programa que leia uma linha de texto e que imprima o texto com todas as letras minúsculas convertidas para maiúsculas.

Solução 1:

Nesta primeira solução, por questões de simplicidade, estamos assumindo o padrão ASCII e ignorando acentos, tais como à, á, ã, etc.

def maiuscula(c):
    if c >= 'a' and c <='z':
        c = chr(ord(c) - ord('a') + ord('A'))
    return c

def main():
    texto = input("Digite um texto: ")
    novo = ""
    for l in texto:
        novo += maiuscula(l)
    print(novo)

main()
  

Solução 2:

Uma solução mais pythonica e geral, utilizando recursos já existentes no Python, pode considerar o uso do método upper().

def main():
    texto = input("Digite um texto: ")
    print(texto.upper())

main()
  

Problema 3:

Escreva uma função separa, que recebe um string texto e um caractere separador sep. A função "corta" o texto nos separadores, retornando uma lista com as partes recortadas do texto.

Exemplo: para o texto "Nome completo;NUSP;e-mail" e sep=";" a saída deve ser a lista ['Nome completo', 'NUSP', 'e-mail'].

Solução:

def separa(texto, sep = " "):
    L = []
    palavra = ""
    for l in texto:
        if l != sep:
            palavra += l
        elif palavra != "":
            L.append(palavra)
            palavra = ""
    if palavra != "":
        L.append(palavra)
    return L
  
Abaixo temos um exemplo de programa principal, que chama a função acima para obter a lista de palavras separadas por espaços em branco de uma linha de texto.
  
def main():
    texto = input("Digite um texto: ")
    P = separa(texto, " ")
    print(P)

main()
  
Note, porém, que as strings no Python já possuem um método nativo chamado split(), que desempenha esse papel de quebrar o texto no separador fornecido. Caso omitido, o separador é assumido como sendo o espaço em branco.
def main():
    texto = input("Digite um texto: ")
    P = texto.split()
    print(P)

main()
  

Problema 4:

Escreva um programa que leia uma linha com palavras, separadas por espaços em branco, e determina o comprimento da maior palavra. Assuma que o texto não contém caracteres de pontuação.

Exemplo:

Digite uma frase: Pedro Álvares Cabral
Comprimento da palavra mais longa é 7

Solução 1:

Uma primeira solução analisando letra por letra do texto, sem o uso do split() para separar as palavras do texto.

def main():
    frase = input("Digite uma frase: ")
    tam = 0
    maxtam = 0
    for letra in frase:
        if letra != ' ':
            tam += 1
        else:
            tam = 0
        if tam > maxtam:
            maxtam = tam
    print("Comprimento da palavra mais longa é",maxtam)

main()
  

Solução 2:

Uma segunda solução com a separação explícita das palavras do texto, via o método split().

def main():
    frase = input("Digite uma frase: ")
    palavras = frase.split()
    maxtam = 0
    for pal in palavras:
        if len(pal) > maxtam:
            maxtam = len(pal)
    print("Comprimento da palavra mais longa é",maxtam)

main()