Strings Avançado
A Lição 06 cobriu o básico. Agora vamos nos aprofundar. O que a imutabilidade realmente significa? Que operações de string menos conhecidas mas poderosas existem? Como caracteres chineses são armazenados em computadores? Após esta lição, seu entendimento de strings alcançará um novo nível.
1. Imutabilidade de Strings
Mencionamos brevemente no FAQ da Lição 06 — uma vez criadas, strings não podem ser modificadas. Vamos ver o que isso significa concretamente.
text = "Hello"
# ❌ Não pode modificar assim — isto daria erro
# text[0] = "h" # TypeError: 'str' object does not support item assignment
Para mudar a primeira letra para minúscula, crie uma nova string:
text = "Hello"
new_text = "h" + text[1:] # Cria uma nova string
print(new_text) # hello
print(text) # Hello — original inalterado
Benefícios da Imutabilidade
# Referências compartilhadas seguras
a = "Python"
b = a # b e a apontam para a mesma string
# Não importa o que você faça com a, b não é afetado
a = a.upper()
print(a) # PYTHON
print(b) # Python — b ainda mantém o valor original
O Custo da Imutabilidade
Cada "modificação" cria um novo objeto. Concatenar muitas strings em um laço é lento:
# ❌ Não recomendado: concatenação de strings em um laço
result = ""
for i in range(10000):
result += str(i) + ","
# Isso cria 10000 objetos temporários de string
# ✅ Recomendado: colete em uma lista, depois join()
parts = []
for i in range(10000):
parts.append(str(i))
result = ",".join(parts)
+= é perfeitamente aceitável.
Exemplo: Simulando Métodos de String (Dificuldade ⭐⭐)
# Implementa uma função "capitalize"
def my_capitalize(text):
if not text:
return text
first = text[0].upper()
rest = text[1:].lower()
return first + rest
print(my_capitalize("hello WORLD")) # Hello world
print(my_capitalize("python")) # Python
# Implementa uma função "replace"
def my_replace(text, old, new):
parts = text.split(old) # Divide por old, obtém as partes
return new.join(parts) # Rejunta com new
print(my_replace("one, two, one", "one", "1")) # 1, two, 1
2. Métodos de Consulta de String
Além de find() e count() da Lição 06, aqui estão mais métodos úteis.
startswith() e endswith()
# Verifica início/fim da string
url = "https://www.example.com"
print(url.startswith("https")) # True — protocolo HTTPS
print(url.endswith(".com")) # True — domínio .com
print(url.endswith(".org")) # False
# Pode verificar múltiplos de uma vez
print(url.endswith((".com", ".org", ".cn"))) # True — corresponde a .com
Usos Práticos
# Verificação de extensão de arquivo
filename = "relatorio.pdf"
if filename.endswith((".pdf", ".doc", ".docx")):
print("Arquivo de documento")
elif filename.endswith((".jpg", ".png", ".gif")):
print("Arquivo de imagem")
elif filename.endswith((".py", ".js", ".html")):
print("Arquivo de código")
else:
print("Outro arquivo")
# Verificação de protocolo de URL
link = "ftp://files.example.com"
if link.startswith(("http://", "https://")):
print("Link web")
elif link.startswith("ftp://"):
print("Link FTP")
Saída:
Arquivo de documento
Link FTP
removeprefix() e removesuffix() (Python 3.9+)
Estes foram adicionados no Python 3.9 para remover limpo prefixos ou sufixos:
url = "https://www.example.com"
# Remove prefixo do protocolo
domain = url.removeprefix("https://")
print(domain) # www.example.com
# Remove sufixo do domínio
site_name = url.removesuffix(".com")
print(site_name) # https://www.example
# Se a string não começar/terminar com o texto dado, retorna inalterada
print(url.removeprefix("ftp://")) # https://www.example.com (inalterado)
url[len("https://"):] ou url.split("://", 1)[1]. removeprefix() e removesuffix() tornam isso mais intuitivo.
3. Uso Avançado de split()
A Lição 06 cobriu a divisão básica. Vamos explorar variantes mais poderosas.
Limitando o Número de Divisões
# Limite divisões com o parâmetro maxsplit
text = "one,two,three,four,five"
print(text.split(",", 1)) # ['one', 'two,three,four,five']
print(text.split(",", 2)) # ['one', 'two', 'three,four,five']
print(text.split(",", 3)) # ['one', 'two', 'three', 'four,five']
rsplit(): Dividir da Direita para a Esquerda
text = "one,two,three,four,five"
print(text.rsplit(",", 1)) # ['one,two,three,four', 'five']
print(text.rsplit(",", 2)) # ['one,two,three', 'four', 'five']
splitlines(): Dividir por Linhas
multiline = """Primeira linha
Segunda linha
Terceira linha"""
lines = multiline.splitlines()
print(lines) # ['Primeira linha', 'Segunda linha', 'Terceira linha']
# Manter quebras de linha
lines = multiline.splitlines(True)
print(lines) # ['Primeira linha\n', 'Segunda linha\n', 'Terceira linha']
partition() e rpartition()
partition() não apenas divide mas também retém a posição do separador:
text = "usuario@example.com"
# Divide por @ em três partes: (esquerda, separador, direita)
parts = text.partition("@")
print(parts) # ('usuario', '@', 'example.com')
# Se separador não encontrado, retorna (string_original, '', '')
print("hello".partition("@")) # ('hello', '', '')
# rpartition pesquisa da direita
path = "/home/usuario/documentos/arquivo.txt"
last_slash = path.rpartition("/")
print(last_slash) # ('/home/usuario/documentos', '/', 'arquivo.txt')
partition() é melhor que split() para cenários de "extração" — informa exatamente o que cada uma das três partes é.
Exemplo: Análise de URL (Dificuldade ⭐⭐)
# Analisa uma URL usando partition
url = "https://www.example.com:8080/path/page.html?name=test&page=1"
# Extrai protocolo
proto, _, rest = url.partition("://")
print(f"Protocolo: {proto}") # https
# Extrai host e caminho
host_part, _, path_and_query = rest.partition("/")
print(f"Host: {host_part}") # www.example.com:8080
# Extrai porta
host, _, port = host_part.partition(":")
print(f"Domínio: {host}") # www.example.com
print(f"Porta: {port}") # 8080
# Extrai caminho e consulta
path, _, query = path_and_query.partition("?")
print(f"Caminho: /{path}") # /path/page.html
print(f"Consulta: {query}") # name=test&page=1
Saída:
Protocolo: https
Host: www.example.com:8080
Domínio: www.example.com
Porta: 8080
Caminho: /path/page.html
Consulta: name=test&page=1
4. Alinhamento e Preenchimento de String
Python fornece métodos para alinhar strings dentro de uma largura especificada — esquerda, direita ou centro.
text = "Python"
print(text.ljust(10)) # 'Python ' (alinhado à esquerda, preenchido com espaços à direita)
print(text.rjust(10)) # ' Python' (alinhado à direita, preenchido à esquerda)
print(text.center(10)) # ' Python ' (centralizado, preenchido em ambos os lados)
# Pode especificar um caractere de preenchimento
print(text.ljust(10, "-")) # 'Python----'
print(text.rjust(10, "-")) # '----Python'
print(text.center(10, "-")) # '--Python--'
zfill(): Preenchimento com Zeros
Comumente usado para IDs numéricos:
print("42".zfill(5)) # 00042
print("-42".zfill(5)) # -0042 — sinal negativo vem primeiro
print("3.14".zfill(8)) # 00003.14
# Gera IDs de 3 dígitos
for i in range(1, 11):
filename = f"foto_{str(i).zfill(3)}.jpg"
print(filename, end=" ")
Saída:
foto_001.jpg foto_002.jpg foto_003.jpg foto_004.jpg foto_005.jpg
foto_006.jpg foto_007.jpg foto_008.jpg foto_009.jpg foto_010.jpg
Exemplo: Gerando um Relatório Alinhado (Dificuldade ⭐⭐)
# Alinha uma tabela usando rjust e ljust
items = [
("Maçã", 5.0, 3),
("Banana", 3.5, 5),
("Leite", 12.0, 2),
]
# Cabeçalhos
header_name = "Item".ljust(8)
header_price = "Preço".rjust(6)
header_qty = "Qtd".rjust(4)
header_total = "Total".rjust(6)
print(f"{header_name}{header_price}{header_qty}{header_total}")
print("-" * 28)
# Linhas de dados
for name, price, qty in items:
total = price * qty
name_col = name.ljust(8)
price_col = f"{price:.1f}".rjust(6)
qty_col = str(qty).rjust(4)
total_col = f"{total:.1f}".rjust(6)
print(f"{name_col}{price_col}{qty_col}{total_col}")
Saída:
Item Preço Qtd Total
────────────────────────────
Maçã 5.0 3 15.0
Banana 3.5 5 17.5
Leite 12.0 2 24.0
5. Codificação de Caracteres: ord() e chr()
Cada caractere em um computador corresponde a um número (ponto de código). ord() obtém a codificação numérica de um caractere; chr() faz o inverso.
# Visualiza pontos de código Unicode
print(ord("A")) # 65
print(ord("ç")) # 231 (cedilha)
print(ord("❤")) # 10084
# Obtém caractere a partir do ponto de código
print(chr(65)) # A
print(chr(231)) # ç
print(chr(10084)) # ❤
# Gera todas as letras maiúsculas
for code in range(ord("A"), ord("Z") + 1):
print(chr(code), end=" ")
# Saída: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
O que é Unicode
Simplificando, Unicode é um padrão global de codificação de caracteres — atribui um número único a cada caractere de todos os sistemas de escrita do mundo (chinês, inglês, árabe, japonês, etc.). Python 3 armazena todas as strings internamente como Unicode, então suporta nativamente múltiplos idiomas.
# Strings Python 3 suportam nativamente Unicode
text = "Hello, 你好, مرحبا, こんにちは"
print(text) # Todos exibidos corretamente
print(len(text)) # Contagem de caracteres
# Você também pode representar caracteres com escapes \u
print("\u0048") # H
print("\u00e7") # ç
str (bytes) e unicode (texto), causando erros frequentes de codificação. Python 3 as unificou — todas as strings são Unicode, tratando chinês e inglês igualmente. Esta é uma das melhores decisões de design do Python 3.
Codificação e Decodificação
Embora Python use Unicode internamente, o armazenamento de arquivos e a transmissão de rede usam bytes. Então você precisa de codificação (encode) e decodificação (decode):
text = "Hello, 世界"
# Codificação: string → bytes
utf8_bytes = text.encode("utf-8")
print(utf8_bytes) # b'\xe4\xbd\xa0\xe5\xa5\xbd...'
print(len(utf8_bytes)) # Número de bytes em UTF-8
# Decodificação: bytes → string
decoded = utf8_bytes.decode("utf-8")
print(decoded) # Hello, 世界
# Se encode/decode não coincidirem, ocorre erro
# gbk_bytes.decode("utf-8") # UnicodeDecodeError!
encoding="utf-8" ao abrir o arquivo.
6. Suplemento de Formatação de String
Além das f-strings, Python tem dois métodos de formatação mais antigos. Embora as f-strings sejam o padrão moderno, você pode encontrar estes em código mais antigo.
Método format() (Python 3.0+)
# Por posição
print("Meu nome é {}, tenho {} anos.".format("Alice", 18))
# Meu nome é Alice, tenho 18 anos.
# Por nome
print("Meu nome é {nome}, tenho {idade} anos.".format(nome="Bob", idade=22))
# Meu nome é Bob, tenho 22 anos.
# Formatação de números
print("Pi: {:.3f}".format(3.14159))
# Pi: 3.142
Formatação % (Era Python 2)
# Você pode ver isso em código mais antigo
print("Meu nome é %s, tenho %d anos." % ("Alice", 25))
# Meu nome é Alice, tenho 25 anos.
print("Pi: %.2f" % 3.14159)
# Pi: 3.14
format() ainda é útil para "formatação atrasada" (definir um template agora, preencher valores depois). A formatação % é apenas para reconhecimento quando você a encontrar; não a use em código novo.
Casos de Uso Comuns
- Renomeação em lote de arquivos: Use
endswith()para filtrar tipos de arquivo,zfill()para numeração uniforme. - Análise de URL: Use
partition()eremoveprefix()para extrair protocolo, domínio e caminho. - Processamento de dados CSV: Use
split()commaxsplitpara controlar o número de divisões, evitando interferência de vírgulas dentro dos campos. - Formatação de log: Use
center()eljust()para saída de log alinhada. - Conversão de codificação: Lide com arquivos de texto de diferentes fontes usando
encode()edecode(). - Validação de dados: Use
startswith()eendswith()para verificar formatos (email, telefone, links).
❓ Perguntas Frequentes
P: Por que as strings do Python 3 são Unicode mas as do Python 2 não eram? R: A era do Python 2 foi atormentada por uma confusão de codificações (ASCII, Latin-1, GBK, Shift-JIS coexistindo). O tratamento de strings era dividido entre "bytes" e "texto" — dois sistemas separados, muito propensos a erros. Python 3 fez uma ruptura limpa: todas as strings são Unicode (texto); dados de bytes são tratados separadamente pelo tipo
bytes. Isso torna as operações de string intuitivas —len("ç")é sempre 1 em qualquer sistema. A desvantagem é que você precisa de encode/decode manual para E/S de arquivo ou rede. ⚠️ P: Quando devo usarsplit()vspartition()? R: Para divisão simples, usesplit(). Quando você precisa do próprio separador, usepartition().partition()sempre retorna três elementos (esquerda, separador, direita), útil para desempacotamento de tupla:esq, sep, dir = texto.partition(":").split()retorna uma lista de comprimento variável. Se o delimitador aparece apenas uma vez e você precisa do conteúdo em ambos os lados,partition()é a melhor escolha. P: Qual a diferença entreljust()e a f-string{valor:10}? R: Eles produzem o mesmo resultado —text.ljust(10)equivale af"{text:<10}". A versão f-string é mais flexível (combina alinhamento com formatação de números), enquanto a chamada de método é mais intuitiva. É uma questão de preferência — escolha uma e mantenha consistência. Símbolos de alinhamento em f-strings:<esquerda,>direita,^centro:f"{text:^10}". P: Qual a diferença entre UTF-8 e GBK? Por que meu arquivo Python às vezes salva com caracteres ilegíveis? R: UTF-8 é o padrão internacional — 1-4 bytes por caractere, universal. GBK é um padrão chinês (chinês simplificado) — 1-2 bytes por caractere, suporta apenas chinês e inglês. Se seu arquivo Python for salvo como GBK mas contiver texto em japonês ou árabe, ocorrerá erro ou exibição ilegível. Solução: salve todos os arquivos Python como UTF-8 — Python 3 usa UTF-8 como padrão.
📖 Resumo
- Strings são imutáveis: cada "modificação" cria um novo objeto; use
join()em vez de+=para grandes concatenações - Métodos de consulta:
startswith()/endswith()verificam início/fim; suporta argumentos de tupla para múltiplas verificações - Python 3.9+:
removeprefix()/removesuffix()para remoção limpa de prefixo/sufixo - Divisão avançada:
split(maxsplit=N)limitar,rsplit()da direita,splitlines()por linhas partition()retém informação do separador, ideal para análise estruturada- Alinhamento:
ljust()/rjust()/center()/zfill(); caracteres de preenchimento personalizados suportados ord()obtém o ponto de código Unicode do caractere;chr()converte de volta- Strings Python 3 usam Unicode internamente; codifique/decode com
encode()/decode(); UTF-8 recomendado
📝 Atividades
-
Básico (Dificuldade ⭐): Dado
files = ["relatorio.pdf", "foto.jpg", "script.py", "notas.txt", "index.html"], useendswith()para filtrar:- Todos os arquivos de imagem (.jpg, .png, .gif)
- Todos os arquivos de documento (.pdf, .doc, .docx, .txt)
- Todos os arquivos de código (.py, .js, .html, .css)
-
Intermediário (Dificuldade ⭐⭐): Escreva um "renomeador de arquivos em lote." Dado
photos = ["IMG_1.jpg", "IMG_2.jpg", ..., "IMG_12.jpg"], renomeie-os paraphoto_001.jpg,photo_002.jpg, ...,photo_012.jpg. Dica: Usepartition()para dividir nome e extensão; usezfill()para preenchimento com zeros. -
Desafio (Dificuldade ⭐⭐⭐): Escreva um "mecanismo de template simples." Dado uma string de template
templatee um dicionáriodata, substitua espaços reservados{variavel}por valores reais.PYTHONtemplate = "Prezado {nome}, seu pedido {pedido_id} foi {status}. Previsão de entrega: {prazo_entrega}." data = { "nome": "Alice", "pedido_id": "20260623001", "status": "enviado", "prazo_entrega": "3 dias úteis" } # Seu código: implemente replace_template(template, data) # Saída: Prezado Alice, seu pedido 20260623001 foi enviado. Previsão de entrega: 3 dias úteis.Requisito extra: Se uma variável do template não existir em data, deixe
{variavel}como está (não substitua). Dica: Itere sobre pares chave-valor em data, chamandoreplace()no template para cada um.



