Python: Strings e Codificação


Outras informações sobre Strings

Aviso: Se você está lendo essas notas pela primeira vez essas informações podem ser consideradas um pouco complexas. É recomendável que você pule essa seção e volte a ela mais tarde.

Strings são variáveis usadas para armazenar texto. Nessas notas elas já foram estudadas na seção Python: Strings. Algumas informações adicionais podem ser úteis.

Prefixos Modificadores de Strings

Além das strings usuais é possível usar modificadores por meio de prefixos para representar coisas diferentes no Python. As strings resultantes são objetos de string, como qualquer outra string, admitindo seus métodos e propriedades. O prefixo f é o mais comum, permitindo a avaliação de expressões dentro de uma string. Além dele podemos mencionar outros prefixos que podem ser usados sozinhos ou em conjunto:

  • b: bytes literais
  • f: string formatada
  • r: strings brutos
  • u: string usando Unicode legado (PEP 414)

As f-strings são de uso muito comum no Python, que permitindo avaliar expressões dentro de literais de string. As strings brutas não são tão populares quanto as f-strings mas têm seus próprios usos, importantes em certas ocasiões. Resumidamente elas ignoram sequências de escape e retornam texto puro. Strings de bytes são necessárias para armazenar objetos que não contém apenas caracteres mas também códigos de controles e outros valores binários. Unicode legado serve para expressar string em sistemas antigos que ainda não tinham o UTF-8 incorporado.

Strings e bytes

O Python tem o datatype bytes, uma classe diferente das strings.

» string1 = 'Python Pool' 
» print(type(string1))  
↳ <class 'str'>

» string2 = b'Python Pool' 
» print(type(string2)) 
↳ <class 'bytes'>

Método bytes(): O método bytes() converte strings em bytes, retornando um objeto imutável. Seu construtor pode receber o conteúdo da string e sua codificação.

» texto = "Podemos converter strings em bytes"
# converta string em bytes
» texto_to_byte = bytes(texto, 'utf-8')
» print(texto_to_byte)
# Output:
↳ b'Podemos converter strings em bytes'

Lembrando: Nos blocos de código nesse site usamos a notação » para linhas de código, para resuktados (outputs) e # para comentários do Python.

O método bytes(texto, 'utf-8') converte a string em um objeto bytes usando a codificação utf-8.
Também é possível passar apenas o tamanho da variável, ou uma lista (um iterável):

» tamanho = 7
» bvar = bytes(tamanho)
» print(bvar)
# Output
↳ b'\x00\x00\x00\x00\x00'

» lista = [1, 2, 3, 4, 5]
» bvar = bytes(lista)
» print(bvar)

# Output
↳ b'\x01\x02\x03\x04\x05'

As saídas contém os números de entrada transformados para o formato hexadecimal: 0 &arr;\x00, …, 5 &arr;\x05, etc.

Método decode(): O método inverso, para receber entradas em formato codificado e retornar o argumento decodificado em uma string comum é decode().

» st1 = b'Decodificar \xE2\x9C\x85'
» st2 = b'Decodificar \xE2\x9B\x85'
» print(st1.decode("utf-8"))
↳ Decodificar ✅
» print(st2.decode("utf-8"))
↳ Decodificar ⛅

Nesse caso decode() converteu bytes em strings. Nesse exemplo o código utf-8 \xE2\x9C\x85 representa o sinal ✅ enquanto \xE2\x9B\x85 é o código para o sinal ⛅.

Método chr(): O método chr() converte um inteiro no caracter unicode correspondente.

» print("Usando chr(int):")
» print(f"Maiúsculas: chr(65) = {chr(65)}, ..., chr(90) = {chr(90)}")
» print(f"Minúsculas: chr(97) = {chr(97)}, ..., chr(122) = {chr(122)}")
    
↳ Usando chr(int):
↳ Maiúsculas: chr(65) = A, ..., chr(90) = Z
↳ Minúsculas: chr(97) = a, ..., chr(122) = z

Strings formatadas

Iniciando com o Python 3.12 passou a ser permitido usar strings formatadas, ou f-strings. Elas são uma forma de inserir avaliações de código dentro de texto, concatenando literais de strings com o resultado.

» idade_1 = 15
» idade_2 = 19
» print(f"A idade somada de nossos alunos é {idade_1 + idade_2}, com média {(idade_1 + idade_2)/2}.")
↳ 'A idade somada de nossos alunos é 34, com média 17.0.'

» aluno = {"nome": "Jean Paul", "sobrenome": "Dirac" ,"area": "Física"}
» print(f"Nosso aluno {aluno["nome"]} {aluno["sobrenome"]} se destacou em {aluno["area"]}!")
↳ 'Nosso aluno Jean Paul Dirac se destacou em Física!'

# uma forma mais compacta de conseguir o mesmo resultado consiste em usar 
» aluno = {"nome": "Jean Paul", "sobrenome": "Dirac" ,"area": "Física"}
» print("Nosso aluno {nome} {sobrenome} se destacou em {area}!".format(**aluno))
↳ 'Nosso aluno Jean Paul Dirac se destacou em Física!'


No último exemplo usamos os nomes dos campos diretamente e passamos a string para o método string.format(**aluno). Como argumento o operador ** de desempacotamento (unpacking) retorna os valores do dicionário, ignorando campos extras, caso existam. Essa última forma é mais concisa e legível.

Strings brutas

Strings brutas (raw strings) tem um comportamento igual ao de uma string literal normal, com uma diferença importante: elas ignoram quaisquer sequências de caracteres de escape contidas na string. Por exemplo:

» print("1 - Componentes do átomo:\n\t Prótons \n\t Nêutrons \n\t Elétrons")
↳ 1 - Componentes do átomo:
       Prótons 
       Nêutrons 
       Elétrons

» print(r"2 - Componentes do átomo:\n\t Prótons \n\t Nêutrons \n\t Elétrons")
↳ 2 - Componentes do átomo:\n\t Prótons \n\t Nêutrons \n\t Elétrons

No primeiro caso os carateres de controle \n e \t, respectivamente newline e tab, são interpretados como controles. No segundo caso os controles são representados literalmente, como strings.

Se nenhum caracter de controle for encontrado a string fica inalterada com o prefixo r.

» print(r"É muito legal programar com python!" == "É muito legal programar com python!")
↳ True

# mas...
» print(r"10\25\1991" == "10\25\1991")
↳ False

regex
Esse tipo de recurso é particularmente útil quando usamos expressões regulares. Nelas são passadas aos métodos parâmetros com strings incluídas barras invertidas, que têm significado especial para as regex, sem necessidade de escape. Você pode ler sobre as expressões regulares em Expressoes Regulares no Python e, no caso geral, Expressoes Regulares.

Raw strings também auxiliam na construção de caminhos de arquivos e diretórios que contêm barras invertidas que não devem ser “escapadas”. Finalmente elas são úteis para exibir strings com caracteres difíceis de digitar ou ler, caracteres de controle como nova linha ou tabulações.

Codificações de caracteres em Python

Para representar caracteres e sinais de controle no computador diversos sistemas de codificação foram criados. Uma codificação é um sistema de traduzir caracteres (letras, pontuações, símbolos, espaços em branco e controle) para números inteiros e posteriormente para bits.

O mais simples deles é o sistema ASCII, que usa apena 1 byte em toda a sua codificação. Isso pode ser confirmado com a operação:

» all(len(chr(i).encode("ascii")) == 1 for i in range(128))
↳ True

o que mostra que todos os caracteres em chr(i).encode("ascii") com i = 0 … 127 tem comprimento 1.
Tabela ASCII resumida:

Código representa
0 até 31 caracteres de controle, não imprimíveis,
32 até 64 pontuação, símbolos, núeros e espaço,
65 até 90 caracteres maiúsculos do alfabeto inglês,
91 até 96 sinais gráficos como [ \ ] ^ _ `,
97 até 122 caracteres minúsculos do alfabeto inglês,
123 até 126 sinais gráficos adicionais como { | } ~,
127 controle de apagamento (del) não imprimível.

No entanto, o sistema de codificação ASCII permite apenas o mapeamento de 127 sinais ou controles. Ele é pequeno demais para representar a variedade de caracteres acentuados, além daqueles usados em outras línguas como chinês e russo. Por isso se desenvolveu um sistema capaz de representar um conjunto muito maior de caracteres e sinais, de denominado Unicode. Muitos outros sistemas foram criados entes dele mas é predominante, hoje o uso do Unicode e um de seus esquemas de codificação, o UTF-8. Por motivo de compatibilidade os primeiros 127 códigos coicidem com os do ASCII



O Unicode não é um sistema de codificação mas engloba vários deles. Ele mapeia caracteres como “a”, “¢” ou “😎”, incluindo emojis. Ele contém praticamente todos os caracteres necessários para uma comunicção moderna internacional, incluindo a marca (código 8207) que indica que o texto será exibido da direita para a esquerda, usado em línguas árabes.

UTF-8: Para representar essa diversidade de caracteres, sinais e controles surgiu o UTF-8, que usa mais de 1 bite na codificação. Seu código tem comprimento variável para cada sinal, podendo chegar a até 4 bites. Por default o Python usa a codificação utf-8.

O código abaixo mostra um caracter, um emoji, com comprimento 4 nessa codificação.

» emoji = "🤨"
» print(len(emoji))
↳ 1
» print(emoji.encode("utf-8"))
↳ b'\xf0\x9f\xa4\xa8'
» print(len(ibrow.encode("utf-8")))
↳ 4

# construir uma lista com objeto de bytes retorna
# o valor decimal para cada byte
» print(list(b'\xf0\x9f\xa4\xa8'))
↳ [240, 159, 164, 168]

Nota, é importante lembrar: o comprimento de um único caracter em unicode no Python é 1, mesmo que ele ocupe vários bites. O comprimento desse caracter codificado em bytes será entre 1 e 4, no UTF-8.

Funções associadas do Python

O Python tem várias funções internas (built-in) associadas com systemas de numeração e codificação de caracteres:

Função retorna
ascii(objeto) string, representação ASCII do objeto com caracteres não-ASCII escapados,
bin(inteiro) string, representação binária do inteiro com prefixo “0b”,
bytes(iterável) converte para bytes, dados binários brutos,
chr(inteiro) string, caracter unicode,
hex(inteiro) string, representação hexadecimal com prefixo “0x”,
int(número) inteiro, converte para inteiro,
oct(número) inteiro, converte para número octal com prefixo “0o”,
ord(string) inteiro, converte caracter unicode para inteiro,
str(objeto) converte para string, texto.

Alguns exemplos:

» print(ascii("jalapeño"))
↳ "'jalape\\xf1o'"

» print(bin(400))
↳ '0b110010000'

» print(bytes(range(97, 123)))  # Iterável de inteiros
↳ b'abcdefghijklmnopqrstuvwxyz'

» print(chr(1114111))
↳ '\U0010ffff'

» print(hex(100))
↳ '0x64'

» print(int('11', base=2))
↳ 3

» print(ord("a"))
↳ 97

» print(str(5))
↳ '5'

» print(str(0xc0ffee))
↳ '12648430'

Módulo String

O Módulo de Strings vem pre-instalado no Python, contendo constantes e método úteis, e duas classes.

String, constantes:

» import string

# string module constants
» print(string.ascii_letters)
↳ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

» print(string.ascii_lowercase)
↳ abcdefghijklmnopqrstuvwxyz

» print(string.ascii_uppercase)
↳ ABCDEFGHIJKLMNOPQRSTUVWXYZ

» print(string.digits)
↳ 0123456789

» print(string.hexdigits)
↳ 0123456789abcdefABCDEF

» print(string.whitespace)  # ' \t\n\r\x0b\x0c'

» print(string.punctuation)
↳ !"#$%&'()*+,-./:;?@[\]^_`{|}~

Método capwords(): O módulo possui um único método, capwords(texto, sep=None). Ela quebra a string em texto, transforma em maiúscula a primeira letra de cada palavra e as junta na string de retorno. Se o argumento opcional sep="None" espaços em branco nas extremidaddes são removidos. Se outro sep é fornecido ela é usado para quebrar o texto original.

» import string
» texto = "  venha aprender o \n\n python  "
» print(string.capwords(texto))
↳ "Venha Aprender O Python"

Classe Formatter: O módulo string possui também duas classes. A classe Formatter tem o mesmo comportamento que string.format() mas é útil para ser herdada em uma classe nova do usuário que define formatação personalizada.

» from string import Formatter
» formatter = Formatter()
» print(formatter.format('Um bom site é {site}', site='Phylos.net.'))
↳ 'Um bom site é Phylos.net.'

# variáveis podem ser posicionais e nomeadas
» print(formatter.format('{} {site}', 'Visite nosso site: ', site='Phylos.net.'))
↳ 'Visite nosso site: Phylos.net.'

# O método de string "format()" tem o mesmo comportamento
» print('{} {site}'.format('Leia sobre vários tópicos em ', site='Phylos.net.'))
↳ 'Leia sobre vários tópicos em Phylos.net.'

Método Template: A outra classe de Formatter é Template, útil para a produção de aplicativos internacionalizados, onde um marcador informa a posição onde texto posterir será inserido.

» from string import Template
» temp = Template('Em $lingua a palavra "$palavra" é traduzida como  "$traducao".')
» texto = temp.substitute(lingua='português', palavra='intruder', traducao='intruso')
» print(texto)
↳ 'Em português a palavra "intruder" é traduzida como  "intruso".'

Bibliografia

Todas as URLs foram visitadas em janeiro de 2024.

Leave a Reply

Your email address will not be published. Required fields are marked *