Curso
É comum recorrer a .find() ou .index() para verificar se um texto existe em uma string — e acabar esbarrando em comportamentos estranhos, como um ValueError ou um match perdido no início da string. Sensibilidade a maiúsculas/minúsculas, limites de fatias deslocados por um e o fato de não existir um método .contains() em str aumentam a confusão. A solução é direta: use a ferramenta certa para cada caso. Use o operador in para checagens de existência, .find()/.index() para posições, .count() para contagens e .replace() para substituições — além de algumas técnicas seguras para Unicode quando a insensibilidade a caixa importa.
Como o Python lida com a busca de substrings
As strings de texto do Python são Unicode. As operações com substrings são sensíveis a maiúsculas/minúsculas por padrão e são implementadas em C para desempenho. A forma mais direta de testar se um texto aparece dentro de uma string é o operador in, que retorna um Booleano usando a implementação __contains__() da string. Quando você precisa de posições ou contagens, use os métodos dedicados de str. Os parâmetros opcionais start e end seguem a semântica de slicing: início inclusivo; fim exclusivo.
Verificação de contenção com in
Use "needle" in haystack quando você só precisa saber se a substring existe. É legível e evita lidar com índices.
text = "Banana bread"
print("ban" in text) # False (case-sensitive)
print("Ban" in text) # True
Para verificações sem distinção de maiúsculas/minúsculas, normalize ambos os lados. .casefold() é mais consciente de Unicode do que .lower() e é meu padrão para matching sem caixa.
pattern = "ban"
print(pattern.casefold() in text.casefold()) # True
- Quando usar: checagens rápidas de existência, validação de entrada, filtragem de listas.
- Caso de borda:
"" in sé sempreTrue(a string vazia está em toda string).
método str.find()
Sintaxe
str.find() retorna o menor índice da substring, ou -1 se não encontrar. Os parâmetros opcionais start e end restringem a busca.
s.find(substring, start=0, end=len(s))
Exemplos e casos de uso
Use .find() quando você precisa da posição e pode lidar com um valor “não encontrado” sem exceções.
tagline = "Ship fast. Fix faster."
print(tagline.find("fast")) # 5
print(tagline.find("fast", 6)) # 16
print(tagline.find("slow")) # -1
Não escreva if s.find(sub): para checar existência. Se o match estiver no índice 0, a condição é falsy.
name = "Alice"
if name.find("A"): # Errado: 0 é falsy
print("Found A") # Não será executado
if name.find("A") != -1: # Correto
print("Found A")
método str.index()
Sintaxe
.index() espelha .find(), mas lança ValueError quando a substring não existe.
s.index(substring, start=0, end=len(s))
Exemplos e quando escolher
Use .index() quando a substring precisa existir e lançar uma exceção é o modo de falha adequado.
product = "USB-C Cable"
print(product.index("Cable")) # 6
try:
product.index("HDMI")
except ValueError:
print("Required label missing")
método str.count()
Sintaxe
.count() retorna o número de ocorrências não sobrepostas. Também aceita limites start e end.
s.count(substring, start=0, end=len(s))
Exemplos e casos de borda
Use .count() para contagens rápidas sem regex.
log_line = "ERROR: timeout. ERROR: retry. ERROR: gave up."
print(log_line.count("ERROR")) # 3
print(log_line.count("WARN")) # 0
Caso especial: a string vazia.
print("abc".count("")) # 4 (len(s) + 1)
método str.replace()
.replace() retorna uma nova string em que ocorrências de old são substituídas por new. Use count para limitar substituições.
s.replace(old, new, count=-1)
Substituição de substrings
O método não é in-place; ele retorna uma cópia.
message = "The red house is between the blue house and the old house"
print(message.replace("house", "car"))
# The red car is between the blue car and the old car
print(message.replace("house", "car", 2))
# The red car is between the blue car and the old house
Substituição sem diferenciar maiúsculas/minúsculas
Para substituições sem distinguir maiúsculas/minúsculas preservando os padrões de caixa, use re.sub() com re.IGNORECASE, ou normalize com .casefold() se você não precisar preservar a capitalização original.
Correspondência sem diferenciar maiúsculas/minúsculas com .casefold()
.casefold() oferece uma normalização agressiva e compatível com Unicode e é preferível a .lower() para checagens sem distinção de caixa.
query = "straße" # German 'straße'
text = "STRASSE und mehr" # Uppercase variant
print(query.casefold() in text.casefold()) # True
Ferramentas relacionadas para prefixos e sufixos
Para inícios/fins conhecidos, use métodos dedicados — eles são mais rápidos e claros do que slicing ou regex:
s.startswith(prefix)es.endswith(suffix)(aceitam tuplas para múltiplas opções)
s.removeprefix(prefix)es.removesuffix(suffix)(Python 3.9+)
filename = "draft_report_v2.pdf"
print(filename.removeprefix("draft_")) # report_v2.pdf
print(filename.endswith((".pdf", ".docx"))) # True
Trabalhando com colunas no pandas
Ao buscar em muitas strings em uma coluna de DataFrame, use os métodos vetorizados de string. Defina regex=False para corresponder texto literal.
import pandas as pd
cities = pd.Series(["New York", "Yorktown", None, "Toronto"], dtype="string")
mask = cities.str.contains("York", regex=False, na=False)
print(mask.tolist()) # [True, True, False, False]
Observações:
- Por padrão,
regex=True, então caracteres especiais como.correspondem a qualquer caractere, a menos que você desative o regex.
- Trate nulos via
na=.... ComStringDtype, valores ausentes viramFalsena máscara por padrão.
Armadilhas comuns e casos de borda
-
Não existe .contains() em str: use
"sub" in s."abc".contains("a")lançaAttributeError.
-
Verdade/falsidade de .find(): índice
0é falsy; compare com!= -1ou prefirainpara existência.
-
.index() lança exceção: trate
ValueErrorse a substring puder estar ausente.
-
String vazia:
"" in séTrue;s.find("")retorna0;s.count("")élen(s)+1.
-
Sensibilidade a maiúsculas/minúsculas: todas as operações são sensíveis a caixa, a menos que você normalize ou use flags de regex.
-
Bytes vs. texto: não misture
bytesestrem buscas; decodifique ou codifique para igualar os tipos.
-
Semântica de substring:
"ab" in "cat,bat"éFalsemesmo que"a"e"b"apareçam separadamente — matches precisam ser contíguos.
Exemplos práticos para você testar
Estes snippets curtos mostram padrões corretos e destacam pegadinhas comuns.
Checagens de existência
headline = "Where's Waldo?"
print("Waldo" in headline) # True
print("Wenda" in headline) # False
print(headline.find("Waldo")) # 8
print(headline.find("Wenda")) # -1
Busca limitada com start e end
O fim é exclusivo, então as posições de busca espelham a semântica de slicing.
headline = "Where's Waldo?"
print(headline.find("Waldo", 0, 6)) # -1 (buscando em "Where'")
print(headline.find("Waldo", 0, 13)) # 8 (buscando até o 'o' em Waldo)
Contar e substituir
inventory = "apple, apple, pear, apple"
print(inventory.count("apple")) # 3
print(inventory.replace("apple", "orange", 2)) # orange, orange, pear, apple
Exemplo de prática: busca e substituição de strings em Python
Este exemplo processa uma lista de sinopses de filmes. Ele demonstra checagens de existência, buscas com limites e substituições seguras sem regex.
blurbs = [
"Critics say the lead actor delivers a career-best performance.",
"Fans argue the actor actor scene was intentionally repetitive.",
"A clever cameo steals the show."
]
for blurb in blurbs:
# Check whether "actor" appears between indexes 20 and 40 (end exclusive).
window_has_actor = "actor".casefold() in blurb[20:40].casefold()
if not window_has_actor:
print("Window check: actor not found")
continue
# If "actor actor" appears, collapse to a single "actor".
if "actor actor" in blurb:
print(blurb.replace("actor actor", "actor"))
# If "actor actor actor" appears, collapse to a single "actor".
elif "actor actor actor" in blurb:
print(blurb.replace("actor actor actor", "actor"))
else:
print(blurb)
Saída:
Window check: actor not found
Fans argue the actor scene was intentionally repetitive.
Window check: actor not found
Conclusão
Use o operador in para contenção simples, .find() ou .index() quando precisar de posições, .count() para contagens não sobrepostas e .replace() para substituições. Normalize com .casefold() para checagens sem distinção de caixa e prefira os helpers dedicados de prefixo/sufixo quando fizer sentido. Evite converter resultados de .find() para Booleano e trate o comportamento com substring vazia como um caso especial para manter o código com strings correto e claro.
