6. Manipulação Prática de Strings
No Capítulo 5, você aprendeu o básico de como trabalhar com strings: criá-las, acessar caracteres por indexação e fatiamento (slicing) e usar métodos simples de string. Agora vamos construir em cima dessa base para explorar operações de string mais sofisticadas que você vai usar constantemente em programas Python reais.
Este capítulo foca em técnicas práticas de manipulação de strings que resolvem problemas comuns de programação: quebrar texto em partes menores e juntá-las novamente, criar saídas formatadas que parecem profissionais. Essas habilidades são essenciais, seja processando entrada do usuário, gerando relatórios, lendo arquivos de dados ou construindo qualquer programa que trabalhe com texto.
6.1) Dividindo e Juntando Strings
Uma das tarefas mais comuns em processamento de texto é quebrar uma string em partes menores ou combinar várias partes em uma única string. Python fornece métodos poderosos para ambas as operações.
6.1.1) Dividindo Strings com split()
O método split() quebra uma string em uma lista de strings menores com base em um separador (também chamado de delimitador). Isso é extremamente útil para processar texto estruturado como dados CSV, entrada de usuário com vários valores ou sentenças em palavras.
Divisão básica por espaço em branco:
Quando você chama split() sem nenhum argumento, ele divide em qualquer espaço em branco (espaços, tabs, quebras de linha) e remove automaticamente strings vazias do resultado:
# split_basic.py
sentence = "Python is a powerful programming language"
words = sentence.split()
print(words) # Output: ['Python', 'is', 'a', 'powerful', 'programming', 'language']
print(len(words)) # Output: 6Perceba como split() lida de forma inteligente com múltiplos espaços:
# split_whitespace.py
messy_text = "Python is awesome"
words = messy_text.split()
print(words) # Output: ['Python', 'is', 'awesome']Mesmo que haja vários espaços entre as palavras, split() trata qualquer quantidade de espaço em branco como um único separador e produz uma lista limpa.
Dividindo por um separador específico:
Você pode especificar exatamente em qual caractere ou string dividir, passando-o como argumento:
# split_separator.py
csv_data = "apple,banana,cherry,date"
fruits = csv_data.split(',')
print(fruits) # Output: ['apple', 'banana', 'cherry', 'date']
date_string = "2024-03-15"
parts = date_string.split('-')
print(parts) # Output: ['2024', '03', '15']
year = parts[0]
month = parts[1]
day = parts[2]
print(f"Year: {year}, Month: {month}, Day: {day}") # Output: Year: 2024, Month: 03, Day: 15Diferença importante: Quando você especifica um separador, split() o trata literalmente e vai criar strings vazias se o separador aparecer em sequência:
# split_empty_strings.py
data = "apple,,cherry"
result = data.split(',')
print(result) # Output: ['apple', '', 'cherry']
print(len(result)) # Output: 3A string vazia '' no meio representa o "nada" entre as duas vírgulas consecutivas. Esse comportamento é diferente de dividir por espaço em branco sem argumentos.
Limitando o número de divisões:
Você pode controlar quantas divisões acontecem passando um segundo argumento (maxsplit):
# split_maxsplit.py
text = "one:two:three:four:five"
parts = text.split(':', 2) # Divide apenas nos 2 primeiros dois-pontos
print(parts) # Output: ['one', 'two', 'three:four:five']Isso cria no máximo 3 partes (maxsplit + 1), porque ele para de dividir depois do número especificado de divisões. O restante da string permanece intacto.
Exemplo prático: Processando entrada do usuário
# process_input.py
user_input = input("Enter your full name: ")
# User enters: "Alice Marie Johnson"
name_parts = user_input.split()
if len(name_parts) >= 2:
first_name = name_parts[0]
last_name = name_parts[-1] # Last element
print(f"First name: {first_name}") # Output: First name: Alice
print(f"Last name: {last_name}") # Output: Last name: Johnson
else:
print("Please enter at least a first and last name")6.1.2) Juntando Strings com join()
O método join() é o oposto de split(): ele combina uma lista (ou qualquer iterável) de strings em uma única string, com um separador entre cada elemento. A sintaxe pode parecer invertida no começo — é a string separadora que chama o método, e a lista é passada como argumento.
Junção básica:
# join_basic.py
words = ['Python', 'is', 'awesome']
sentence = ' '.join(words)
print(sentence) # Output: Python is awesome
csv_line = ','.join(['apple', 'banana', 'cherry'])
print(csv_line) # Output: apple,banana,cherryA string que chama join() (como ' ' ou ',') se torna o separador entre os elementos.
Por que a sintaxe é separator.join(list):
Essa sintaxe faz sentido quando você pensa do ponto de vista do separador: "Quero juntar esses itens, me inserindo entre cada par." Ela também permite encadeamento elegante e deixa o separador bem visível no seu código.
Juntando com diferentes separadores:
# join_separators.py
items = ['eggs', 'milk', 'bread', 'butter']
# Separado por vírgula
print(', '.join(items)) # Output: eggs, milk, bread, butter
# Separado por quebras de linha (cada item em sua própria linha)
print('\n'.join(items))
# Output:
# eggs
# milk
# bread
# butter
# Separado por hífen
print('-'.join(items)) # Output: eggs-milk-bread-butter
# Sem separador (concatenação)
print(''.join(items)) # Output: eggsmilkbreadbutterImportante: join() só funciona com strings:
Todos os elementos do iterável precisam ser strings. Se você tentar juntar números ou outros tipos, vai obter um erro:
# join_error.py
numbers = [1, 2, 3, 4]
# result = ','.join(numbers) # This would cause: TypeError: sequence item 0: expected str instance, int foundPara juntar itens que não são strings, converta-os para strings primeiro. Vamos aprender um jeito mais elegante de fazer isso no Capítulo 34, mas por enquanto você pode converter cada item manualmente:
# join_numbers.py
numbers = [1, 2, 3, 4]
# Convert each number to a string manually
string_numbers = [str(numbers[0]), str(numbers[1]), str(numbers[2]), str(numbers[3])]
result = ','.join(string_numbers)
print(result) # Output: 1,2,3,4Exemplo prático: Construindo caminhos de arquivo
# build_path.py
path_parts = ['home', 'user', 'documents', 'report.txt']
# On Unix-like systems (Linux, macOS)
unix_path = '/'.join(path_parts)
print(unix_path) # Output: home/user/documents/report.txt
# On Windows
windows_path = '\\'.join(path_parts)
print(windows_path) # Output: home\user\documents\report.txtNote: In Chapter 26, we'll learn about the os.path module which provides better cross-platform path handling, but this demonstrates the concept of joining.
6.1.3) Combinando split() e join() para Processamento de Texto
Esses dois métodos funcionam muito bem juntos para transformar texto. Combinando-os, você pode limpar entradas confusas, converter entre formatos ou extrair e reorganizar dados:
# transform_text.py
# Replace multiple spaces with single spaces
messy = "Python is really cool"
clean = ' '.join(messy.split())
print(clean) # Output: Python is really cool
# Convert comma-separated to space-separated
csv_data = "apple,banana,cherry"
space_separated = ' '.join(csv_data.split(','))
print(space_separated) # Output: apple banana cherry
# Remove all spaces
text_with_spaces = "H e l l o"
no_spaces = ''.join(text_with_spaces.split())
print(no_spaces) # Output: Hello6.1.4) Outros Métodos de Divisão
Python fornece métodos adicionais de divisão para casos específicos:
rsplit() - Divide a partir da direita:
# rsplit_example.py
path = "folder/subfolder/file.txt"
# Regular split with maxsplit
parts = path.split('/', 1)
print(parts) # Output: ['folder', 'subfolder/file.txt']
# rsplit splits from the right
parts = path.rsplit('/', 1)
print(parts) # Output: ['folder/subfolder', 'file.txt']Isso é útil quando você quer separar a última parte de uma string de todo o resto.
splitlines() - Divide em quebras de linha:
# splitlines_example.py
multiline = "Line 1\nLine 2\nLine 3"
lines = multiline.splitlines()
print(lines) # Output: ['Line 1', 'Line 2', 'Line 3']
# Works with different line ending styles
mixed_lines = "Line 1\nLine 2\r\nLine 3\rLine 4"
all_lines = mixed_lines.splitlines()
print(all_lines) # Output: ['Line 1', 'Line 2', 'Line 3', 'Line 4']O método splitlines() reconhece todas as convenções padrão de quebra de linha (\n, \r\n, \r) e divide de acordo, tornando-o mais robusto que split('\n') para processar texto de diferentes fontes.
6.2) Formatando Strings com f-Strings
Criar saída formatada é uma das tarefas mais comuns em programação. Você precisa combinar texto com valores de variáveis, alinhar colunas, formatar números e criar saídas legíveis para usuários. As f-strings (formatted string literals) do Python fornecem a forma mais moderna, legível e poderosa de fazer isso.
6.2.1) Sintaxe Básica de f-Strings
Uma f-string é uma string literal prefixada com f ou F que pode conter expressões dentro de chaves {}. Python avalia essas expressões e converte seus resultados em strings:
# fstring_basic.py
name = "Alice"
age = 30
greeting = f"Hello, {name}! You are {age} years old."
print(greeting) # Output: Hello, Alice! You are 30 years old.As expressões dentro de {} podem ser qualquer expressão Python válida:
# fstring_expressions.py
x = 10
y = 20
result = f"The sum of {x} and {y} is {x + y}"
print(result) # Output: The sum of 10 and 20 is 30
price = 19.99
quantity = 3
total = f"Total cost: ${price * quantity}"
print(total) # Output: Total cost: $59.976.2.2) Por que f-Strings São Melhores que Abordagens Antigas
Antes das f-strings (introduzidas no Python 3.6), programadores usavam concatenação de strings ou o método format(). Vamos comparar:
Concatenação de strings (o jeito antigo e sujeito a erros):
# concatenation_example.py
name = "Bob"
age = 25
# Requires converting numbers to strings and lots of + operators
message = "Hello, " + name + "! You are " + str(age) + " years old."
print(message) # Output: Hello, Bob! You are 25 years old.Essa abordagem é verbosa, sujeita a erros (esquecer str() causa erros) e difícil de ler quando há muitas variáveis.
f-strings (o jeito moderno e limpo):
# fstring_clean.py
name = "Bob"
age = 25
message = f"Hello, {name}! You are {age} years old."
print(message) # Output: Hello, Bob! You are 25 years old.F-strings convertem valores para string automaticamente, são mais legíveis e na verdade são mais rápidas que outras abordagens.
6.2.3) Expressões e Chamadas de Método em f-Strings
Você pode incluir expressões complexas, chamadas de métodos e até chamadas de funções dentro de f-strings:
# fstring_methods.py
name = "alice"
print(f"Capitalized: {name.capitalize()}") # Output: Capitalized: Alice
print(f"Uppercase: {name.upper()}") # Output: Uppercase: ALICE
print(f"Length: {len(name)}") # Output: Length: 5
# Arithmetic and comparisons
x = 10
print(f"Is {x} even? {x % 2 == 0}") # Output: Is 10 even? True
# Indexing and slicing
text = "Python"
print(f"First letter: {text[0]}") # Output: First letter: P
print(f"First three: {text[:3]}") # Output: First three: Pyt6.2.4) Formatando Números em f-Strings
As f-strings suportam especificadores de formato que controlam como os valores são exibidos. A sintaxe é {expression:format_spec}:
Controlando casas decimais para floats:
# fstring_decimals.py
pi = 3.14159265359
print(f"Default: {pi}") # Output: Default: 3.14159265359
print(f"2 decimals: {pi:.2f}") # Output: 2 decimals: 3.14
print(f"4 decimals: {pi:.4f}") # Output: 4 decimals: 3.1416
print(f"No decimals: {pi:.0f}") # Output: No decimals: 3O especificador de formato .2f significa "formatar como float com 2 casas decimais". O f indica "notação de ponto fixo".
Formatando com separadores de milhares:
# fstring_thousands.py
large_number = 1234567890
print(f"No separator: {large_number}") # Output: No separator: 1234567890
print(f"With commas: {large_number:,}") # Output: With commas: 1,234,567,890
print(f"With underscores: {large_number:_}") # Output: With underscores: 1_234_567_890
# Combining with decimal places
price = 1234567.89
print(f"Price: ${price:,.2f}") # Output: Price: $1,234,567.89Formatação de porcentagem:
# fstring_percentage.py
ratio = 0.847
print(f"Ratio: {ratio}") # Output: Ratio: 0.847
print(f"Percentage: {ratio:.1%}") # Output: Percentage: 84.7%
print(f"Percentage: {ratio:.2%}") # Output: Percentage: 84.70%O especificador de formato % multiplica por 100 e adiciona o símbolo de porcentagem.
6.2.5) Exemplos Práticos com f-Strings
Criando relatórios formatados:
# report_example.py
product = "Laptop"
price = 899.99
quantity = 5
tax_rate = 0.08
subtotal = price * quantity
tax = subtotal * tax_rate
total = subtotal + tax
print(f"Product: {product}") # Output: Product: Laptop
print(f"Price: ${price:.2f}") # Output: Price: $899.99
print(f"Quantity: {quantity}") # Output: Quantity: 5
print(f"Subtotal: ${subtotal:.2f}") # Output: Subtotal: $4499.95
print(f"Tax (8%): ${tax:.2f}") # Output: Tax (8%): $360.00
print(f"Total: ${total:.2f}") # Output: Total: $4859.95Criando mensagens amigáveis para usuários:
# user_messages.py
username = "Alice"
login_count = 42
last_login = "2024-03-15"
welcome = f"Welcome back, {username}!"
stats = f"You've logged in {login_count} times. Last login: {last_login}"
print(welcome) # Output: Welcome back, Alice!
print(stats) # Output: You've logged in 42 times. Last login: 2024-03-156.2.6) Debugging com f-Strings
O Python 3.8 introduziu o especificador = para debugging, que mostra tanto a expressão quanto o seu valor:
# fstring_debug.py
x = 10
y = 20
z = x + y
print(f"{x=}") # Output: x=10
print(f"{y=}") # Output: y=20
print(f"{z=}") # Output: z=30
print(f"{x + y=}") # Output: x + y=30Isso é extremamente útil para verificar rapidamente valores de variáveis durante o desenvolvimento sem precisar digitar o nome da variável duas vezes.
6.2.7) Escapando Chaves em f-Strings
Se você precisar de chaves literais em uma f-string, duplique-as:
# fstring_escape.py
value = 42
# Single braces are expression placeholders
print(f"Value: {value}") # Output: Value: 42
# Double braces produce literal braces
print(f"Use {{value}} as a placeholder") # Output: Use {value} as a placeholder
print(f"The value is {value}, shown as {{value}}") # Output: The value is 42, shown as {value}6.3) Formatando com format() e Especificadores de Formato
Embora as f-strings sejam a abordagem moderna preferida, o método format() ainda é amplamente usado e oferece algumas capacidades que vale a pena entender. Ele também é a base sobre a qual as f-strings são construídas, então entender format() ajuda você a entender melhor as f-strings.
6.3.1) Sintaxe Básica de format()
O método format() usa chaves {} como marcadores em uma string, e os valores a serem inseridos são passados como argumentos:
# format_basic.py
template = "Hello, {}! You are {} years old."
message = template.format("Alice", 30)
print(message) # Output: Hello, Alice! You are 30 years old.
# Multiple uses of format()
greeting = "Hello, {}!".format("Bob")
print(greeting) # Output: Hello, Bob!6.3.2) Argumentos Posicionais e Nomeados
Você pode controlar qual argumento vai para onde usando números de posição ou nomes:
Argumentos posicionais:
# format_positional.py
# Default order (0, 1, 2, ...)
template = "{} + {} = {}"
result = template.format(5, 3, 8)
print(result) # Output: 5 + 3 = 8
# Explicit positions
template = "{0} + {1} = {2}"
result = template.format(5, 3, 8)
print(result) # Output: 5 + 3 = 8
# Reordering and reusing
template = "{2} = {0} + {1}"
result = template.format(5, 3, 8)
print(result) # Output: 8 = 5 + 3
# Reusing the same value
template = "{0} times {0} equals {1}"
result = template.format(7, 49)
print(result) # Output: 7 times 7 equals 49Argumentos nomeados:
# format_keyword.py
template = "Hello, {name}! You are {age} years old."
message = template.format(name="Alice", age=30)
print(message) # Output: Hello, Alice! You are 30 years old.
# Can mix with positional (positional must come first)
template = "{0}, your score is {score} out of {1}"
result = template.format("Alice", 100, score=95)
print(result) # Output: Alice, your score is 95 out of 1006.3.3) Especificadores de Formato com format()
Especificadores de formato funcionam da mesma forma em format() e em f-strings, usando o separador ::
# format_specifiers.py
pi = 3.14159265359
print("{:.2f}".format(pi)) # Output: 3.14
print("{:.4f}".format(pi)) # Output: 3.1416
# With names
print("{value:.2f}".format(value=pi)) # Output: 3.14
# Multiple values with different formats
template = "{name}'s score is {score:.1f}%"
result = template.format(name="Bob", score=87.654)
print(result) # Output: Bob's score is 87.7%6.3.4) Quando Usar format() em Vez de f-Strings
As f-strings são geralmente preferidas, mas format() é útil em situações específicas:
1. Strings de template definidas separadamente dos dados:
# format_templates.py
# Template defined once, used multiple times with different data
email_template = "Dear {name},\n\nYour order #{order_id} has shipped.\n\nThank you!"
# Use the template with different customers
message1 = email_template.format(name="Alice", order_id=12345)
message2 = email_template.format(name="Bob", order_id=12346)
print(message1)
# Output:
# Dear Alice,
#
# Your order #12345 has shipped.
#
# Thank you!
print(message2)
# Output:
# Dear Bob,
#
# Your order #12346 has shipped.
#
# Thank you!2. Quando o template vem de fontes externas:
# format_external.py
# Template might come from a configuration file or database
# (We'll learn about reading files in Chapter 24)
user_template = input("Enter message template: ")
# User enters: "Hello, {name}! Welcome to {place}."
message = user_template.format(name="Charlie", place="Python")
print(message) # Output: Hello, Charlie! Welcome to Python.Com f-strings, o template precisa estar no seu código porque as expressões são avaliadas imediatamente. Com format(), o template pode ser uma string comum vinda de qualquer lugar.
6.3.5) Acessando Atributos de Objetos e Chaves de Dicionário
O método format() pode acessar atributos e chaves de dicionário diretamente:
# format_access.py
# Dictionary access
person = {"name": "Alice", "age": 30, "city": "Boston"}
message = "Name: {0[name]}, Age: {0[age]}, City: {0[city]}".format(person)
print(message) # Output: Name: Alice, Age: 30, City: Boston
# With keyword argument
message = "{p[name]} is {p[age]} years old".format(p=person)
print(message) # Output: Alice is 30 years oldNote: We'll learn about object attributes in Chapter 30, but this demonstrates that format() can access nested data structures.
6.4) Alinhando e Arredondando Números em Saída Formatada
Uma saída com aparência profissional geralmente exige alinhamento cuidadoso e formatação de números. Tanto f-strings quanto format() fornecem ferramentas poderosas para criar tabelas, relatórios e telas bem formatadas.
6.4.1) Alinhamento de Texto
Você pode controlar a largura e o alinhamento de valores usando especificadores de formato:
# alignment_basic.py
# Syntax: {value:width}
# Default is left-aligned for strings, right-aligned for numbers
name = "Alice"
print(f"|{name}|") # Output: |Alice|
print(f"|{name:10}|") # Output: |Alice | (left-aligned, width 10)
print(f"|{name:>10}|") # Output: | Alice| (right-aligned)
print(f"|{name:^10}|") # Output: | Alice | (center-aligned)Os especificadores de alinhamento são:
<: alinhado à esquerda (padrão para strings)>: alinhado à direita (padrão para números)^: centralizado
Alinhamento com números:
# alignment_numbers.py
value = 42
print(f"|{value}|") # Output: |42|
print(f"|{value:5}|") # Output: | 42| (right-aligned by default)
print(f"|{value:<5}|") # Output: |42 | (left-aligned)
print(f"|{value:^5}|") # Output: | 42 | (center-aligned)6.4.2) Caracteres de Preenchimento Personalizados
Você pode especificar um caractere para preencher o espaço vazio:
# alignment_fill.py
name = "Bob"
print(f"|{name:*<10}|") # Output: |Bob*******|
print(f"|{name:*>10}|") # Output: |*******Bob|
print(f"|{name:*^10}|") # Output: |***Bob****|
# Useful for creating visual separators
print(f"{name:=^20}") # Output: ========Bob=========A sintaxe é {value:fill_char align width}.
6.4.3) Combinando Alinhamento com Formatação de Números
Você pode combinar largura, alinhamento e formatação de números:
# alignment_combined.py
price = 19.99
quantity = 5
total = price * quantity
# Right-align with width 10, 2 decimal places
print(f"Price: ${price:>10.2f}") # Output: Price: $ 19.99
print(f"Quantity: {quantity:>10}") # Output: Quantity: 5
print(f"Total: ${total:>10.2f}") # Output: Total: $ 99.95
# With fill character for visual effect
print(f"Total: ${total:>10.2f}".replace(' ', '.')) # Output: Total:....$.....99.95Neste capítulo, você aprendeu técnicas essenciais de manipulação de strings que vai usar em praticamente todos os programas Python: dividir e juntar strings para processamento de texto, criar saída formatada com f-strings e especificadores de formato, alinhar e formatar números para exibições profissionais.
Essas habilidades formam a base para trabalhar com dados de texto em Python. Você pode agora processar entrada do usuário, criar relatórios formatados, lidar com dados de arquivos (o que vamos ver no Capítulo 24). À medida que você continuar aprendendo Python, vai usar essas técnicas de manipulação de strings constantemente, então pratique até que se tornem algo natural.