01 / 25
Lógica de Programação · Semana 19 · Dia 1 (aulas 1 e 2)

Strings:
índice, fatia e métodos

Quase todo dado que entra no sistema entra como texto — e texto quase nunca chega do jeito que a gente precisa. Hoje o texto vira matéria-prima manipulável.

ProfessorGuilherme Antunes CursoTécnico em Desenvolvimento de Sistemas ConteúdoManipulação de strings CódigosSISANO1C1B3S19A1 · A2
02 / 25
Objetivos do dia

Ao final, você será capaz de.

01

Acessar caracteres por índice — positivo e negativo — e percorrer uma string com laço

02

Fatiar strings com [inicio:fim:passo] e explicar por que o fim não entra

03

Aplicar os métodos essenciais — strip, lower, replace, find, split, join

04

Reconhecer a imutabilidade e saber que todo método devolve uma nova string

Onde estamos: na Semana 18 aprendemos a documentar, testar e depurar. Cada função de string que criarmos hoje já nasce com docstring e teste — a rede de proteção continua ligada.
03 / 25
Parte 1 Ponto de partida

Todo dado chega como texto

Formulário, arquivo, planilha, API, teclado: a porta de entrada é sempre uma sequência de caracteres. Antes de virar número, data ou registro no banco, alguém precisa ler, limpar e recortar esse texto.

nome digitado:  "  ana  MARIA   silva  "
o que o sistema precisa:  "Ana Maria Silva"

Virem e conversem: onde vocês já viram um sistema errar por causa de texto mal tratado? (nome duplicado por causa de espaço, login que não aceita maiúscula, CEP com traço…)

04 / 25
Construindo o conceito

String é uma sequência de caracteres

Assim como o vetor da Semana 15, a string tem posições numeradas a partir do zero. A diferença: cada posição guarda um caractere, não um valor qualquer.

P0-6
Y1-5
T2-4
H3-3
O4-2
N5-1
linha do meio: índice positivo (da esquerda) linha de baixo: índice negativo (da direita)
linguagem = "PYTHON"

print(linguagem[0])    # P
print(linguagem[3])    # H
print(linguagem[-1])   # N  (último)
print(len(linguagem))  # 6
Regra de bolso do índice negativo: -1 é sempre o último caractere, independentemente do tamanho. É o jeito seguro de pegar o fim sem calcular len() - 1.
linguagem[6] não existe: IndexError. Com 6 caracteres, o último índice válido é 5.
05 / 25
Sequência = dá para percorrer

Duas formas de atravessar o texto

Por caractere (mais comum)

palavra = "AULA"

for letra in palavra:
    print(letra)
A
U
L
A

Por índice (quando a posição importa)

palavra = "AULA"

for i in range(len(palavra)):
    print(i, "->", palavra[i])
0 -> A
1 -> U
2 -> L
3 -> A
Escolha certa: use o laço por caractere quando só quer olhar cada letra (contar vogais, validar). Use o laço por índice quando precisa da posição — comparar com o vizinho, detectar palíndromo, marcar onde algo aparece.
06 / 25
O conceito que mais gera bug

String é imutável

Você consegue ler qualquer posição, mas não consegue escrever em nenhuma. Uma string, depois de criada, nunca muda: o que a gente faz é criar outra.

Não funciona

nome = "ana"
nome[0] = "A"
TypeError: 'str' object does not
support item assignment

Funciona — cria uma nova

nome = "ana"
nome = "A" + nome[1:]
print(nome)      # Ana
Ana
Consequência prática: texto.upper() não altera texto. Ele devolve uma string nova. Se você não guardar o retorno em algum lugar, o resultado é jogado fora — e o programa segue com o texto velho, sem dar erro nenhum. Erro de lógica clássico (Semana 18).
07 / 25
Operação central do dia

Fatiamento: [início:fim]

O fatiamento (slicing) recorta um pedaço da string. Começa no início e para antes do fim — o índice final não entra na fatia.

P0
Y1
T2
H3
O4
N5
s = "PYTHON"

s[1:4]    # "YTH"  (1, 2 e 3)
s[:3]     # "PYT"  (do começo)
s[3:]     # "HON"  (até o fim)
s[:]      # "PYTHON" (cópia inteira)
s[-3:]    # "HON"  (últimos três)
Por que o fim não entra: assim fim - início dá exatamente o tamanho da fatia. s[1:4] tem 4-1 = 3 caracteres. E s[:3] + s[3:] reconstrói a string inteira, sem sobrar nem faltar letra.
Fatia com limite exagerado não dá erro: s[0:99] devolve "PYTHON". Diferente do índice solto, o fatiamento perdoa.
08 / 25
Terceiro parâmetro

O passo: [início:fim:passo]

ExpressãoResultadoLeitura
s[::1]"PROGRAMAR"de um em um — o padrão
s[::2]"PORMR"de dois em dois, pulando um
s[1::2]"RGAA"começa em 1 e pula um
s[::-1]"RAMARGORP"inverte a string inteira
s[3:7:2]"GA"de 3 a 6, de dois em dois
def eh_palindromo(texto):
    """Diz se o texto é igual de trás para frente."""
    limpo = texto.lower().replace(" ", "")
    return limpo == limpo[::-1]

print(eh_palindromo("Arara"))        # True
print(eh_palindromo("Ame a ema"))    # True
print(eh_palindromo("Python"))       # False
[::-1] é a inversão idiomática em Python. Repare que a função combina três ideias do dia: método (lower), método (replace) e fatiamento com passo negativo — em uma linha só.
Amarração com a Semana 18: essa função é pequena, recebe parâmetro, devolve return e tem docstring. Ou seja: testável. Guarde — vamos testá-la no Dia 2.
09 / 25
Pause e responda

Qual o valor de s[2:5]?

Considerando s = "ALGORITMO":

A"GORI" — inclui as posições 2, 3, 4 e 5
B"GOR" — inclui as posições 2, 3 e 4 ✓
C"LGO" — começa a contar do 1
D"ALG" — pega os três primeiros
Por que B: a contagem começa em 0 (A=0, L=1, G=2) e o índice final não entra. Vai de 2 até 4 → "GOR", com 5-2 = 3 caracteres.
10 / 25
Operadores que funcionam em texto

Somar, repetir e procurar

a = "bom"
b = "dia"

a + " " + b       # "bom dia"   (concatenação)
"-" * 20          # "--------------------"
"dia" in "bom dia"      # True
"noite" not in "bom dia"  # True
len("bom dia")    # 7

O operador in em decisão

email = input("E-mail: ")

if "@" not in email:
    print("E-mail inválido")
Não dá para somar tipos diferentes: "idade: " + 15 gera TypeError. É preciso converter: "idade: " + str(15) — ou, melhor, usar f-string (próximo slide).
in é o teste de contém mais barato que existe — devolve True/False direto e serve para qualquer trecho, não só um caractere.
11 / 25
Montando texto de saída

Concatenar é remendo. f-string é costura

Concatenação — frágil

nome = "Ana"
nota = 8.5

msg = "Aluno " + nome + \
      " tirou " + str(nota) + \
      " no bimestre."
Precisa converter tudo com str() e é fácil esquecer um espaço.

f-string — legível

nome = "Ana"
nota = 8.5

msg = f"Aluno {nome} tirou {nota} no bimestre."

# formatando dentro da chave:
f"Média: {nota:.2f}"      # Média: 8.50
f"{nome:>10}"             # alinhado à direita
A variável aparece no lugar onde ela vai sair. Converte sozinha.
Regra: o f vem antes das aspas e cada { } é avaliado como expressão — inclusive {nota * 2} ou {nome.upper()}.
12 / 25
Parte 2 Métodos · ponto de partida

O texto real chega sujo

"  ANA maria SILVA  "
"ana.maria@Escola.COM.BR "
"1.234,50"
"11/09/2026"

Nenhum desses valores está pronto para uso. Cortar na mão, caractere por caractere, funcionaria — mas seria reinventar o que a linguagem já traz pronto. Os métodos de string são funções que já vêm acopladas a todo texto.

Pense: quantas linhas você escreveria, usando só laço e índice, para remover os espaços das pontas de um texto? E se existisse um método que faz isso com uma palavra?

13 / 25
Grupo 1 · caixa

Padronizando maiúsculas e minúsculas

MétodoEntradaSaída
.upper()"ana maria""ANA MARIA"
.lower()"ANA Maria""ana maria"
.title()"ana maria""Ana Maria"
.capitalize()"ana maria""Ana maria"
senha_digitada = "AdMiN"

# comparação à prova de caixa
if senha_digitada.lower() == "admin":
    print("acesso liberado")
Padrão de mercado: antes de comparar dois textos vindos do usuário, coloque os dois na mesma caixa. É o que evita "o cadastro existe mas o login não acha".
.title() não conhece português: "maria de souza" vira "Maria De Souza". Para nomes formais, ainda é preciso tratar as preposições.
14 / 25
Grupo 2 · limpeza

strip e replace: a dupla da faxina

strip — tira das pontas

t = "   dados   "

t.strip()    # "dados"
t.lstrip()   # "dados   "
t.rstrip()   # "   dados"

"###total###".strip("#")   # "total"

replace — troca em todo lugar

cpf = "123.456.789-00"

cpf.replace(".", "").replace("-", "")
# "12345678900"

"1.234,50".replace(".", "").replace(",", ".")
# "1234.50"  → pronto para float()
Cuidado: .strip() só limpa as pontas. Espaços do meio continuam lá — "ana maria".strip() continua com três espaços entre os nomes. Para isso serve " ".join(texto.split()), daqui a três slides.
Encadeamento: como todo método devolve uma string nova, dá para chamar o próximo em seguida: texto.strip().lower().replace(" ", "_"). Lê-se da esquerda para a direita, em ordem de execução.
15 / 25
Pause e responda

O que sai no print?

texto = "  python  "
texto.strip().upper()
print(texto)
APYTHON — os dois métodos foram aplicados
B" PYTHON " — só o upper valeu
C" python " — a variável não mudou ✓
DErro: não se pode encadear métodos de string
Por que C: string é imutável. Os métodos rodaram e produziram "PYTHON", mas o resultado não foi atribuído a ninguém — foi descartado. O certo é texto = texto.strip().upper(). Nenhum erro é lançado: é o erro de lógica silencioso da Semana 18.
16 / 25
Grupo 3 · busca

Onde está e quantas vezes

MétodoDevolveSe não achar
.find("@")índice da 1ª ocorrência-1 (não quebra)
.index("@")índice da 1ª ocorrênciaValueError (quebra)
.count("a")quantas vezes aparece0
.startswith("R$")True / FalseFalse
.endswith(".com")True / FalseFalse
email = "ana@escola.com"
pos = email.find("@")

if pos == -1:
    print("sem arroba")
else:
    print("usuário:", email[:pos])
    print("domínio:", email[pos+1:])
usuário: ana
domínio: escola.com
Combo do dia: find devolve uma posição; a posição alimenta um fatiamento. É assim que se quebra um texto sem saber de antemão onde ele quebra.
find ou index? Use find quando "não achar" é uma possibilidade normal que você vai tratar com if. Use index quando não achar significa que os dados estão corrompidos e o programa deve parar.
17 / 25
Grupo 4 · texto ⇄ lista

split — de texto para lista

frase = "ana maria silva"
frase.split()
# ['ana', 'maria', 'silva']

linha = "Ana;8.5;9.0;7.5"
linha.split(";")
# ['Ana', '8.5', '9.0', '7.5']

"2026-09-11".split("-")
# ['2026', '09', '11']

O caso especial do split() vazio

bagunca = "ana    maria   silva"

bagunca.split(" ")
# ['ana', '', '', '', 'maria', '', '', 'silva']

bagunca.split()
# ['ana', 'maria', 'silva']  ← ignora repetição
Sem argumento, o split() quebra por qualquer quantidade de espaço em branco (inclusive tabulação e quebra de linha) e descarta os vazios. É quase sempre o que você quer para texto digitado por gente.
Ponte com a Semana 15: o split transforma texto em vetor. A partir daí vale tudo que vocês já sabem: percorrer com for, acessar por índice, usar len.
18 / 25
Grupo 4 · texto ⇄ lista

join — de lista para texto

partes = ['ana', 'maria', 'silva']

" ".join(partes)     # "ana maria silva"
"-".join(partes)     # "ana-maria-silva"
"".join(partes)      # "anamariasilva"

# o combo mais útil do dia:
sujo = "  ana    MARIA   silva "
limpo = " ".join(sujo.split()).title()
print(limpo)         # "Ana Maria Silva"
A sintaxe assusta: quem chama o join é o separador, não a lista. Leia como: "cole os itens da lista usando este separador entre eles".
Só junta texto: " ".join([1, 2, 3]) dá TypeError. Se a lista tem números, converta antes.
split e join são inversos: um desmonta, o outro remonta. Quase toda limpeza de texto é um split, alguma coisa no meio, e um join.
19 / 25
Juntando tudo

Uma função que normaliza nome

def normalizar_nome(bruto):
    """
    Padroniza um nome digitado por usuário.

    Args:
        bruto (str): nome como veio do formulário.

    Returns:
        str: nome sem espaços sobrando e com
             cada palavra capitalizada.
    """
    partes = bruto.split()          # limpa espaços
    juntas = " ".join(partes)       # remonta com 1 espaço
    return juntas.title()           # padroniza a caixa
>>> normalizar_nome("  ana  MARIA silva ")
'Ana Maria Silva'

>>> normalizar_nome("PEDRO")
'Pedro'

>>> normalizar_nome("   ")
''
Três linhas, três métodos, um problema real resolvido. Repare que cada linha faz uma coisa — isso é o que torna a função fácil de depurar com breakpoint.
Caso de borda já visível: nome só com espaços devolve string vazia. Isso é bug ou comportamento aceito? Essa pergunta é exatamente o terceiro teste da Semana 18.
20 / 25
Pause e responda

Qual expressão devolve "9.0"?

A linha do arquivo é linha = "Ana;8.5;9.0;7.5". Você precisa da segunda nota.

Alinha.split(";")[3]
Blinha.split(";")[2] ✓
Clinha.join(";")[2]
Dlinha[2]
Por que B: o split(";") produz ['Ana', '8.5', '9.0', '7.5'] — o nome ocupa a posição 0, então a segunda nota está na posição 2. A alternativa D devolve o caractere 'a': linha ainda é texto, e texto se indexa por caractere.
21 / 25
Mapa do dia

Os métodos que resolvem 90%

Preciso…UsoExemplo
padronizar caixa.lower() / .upper() / .title()"ANA".lower() → "ana"
tirar espaço das pontas.strip()" x ".strip() → "x"
remover/trocar trecho.replace(velho, novo)"a-b".replace("-","") → "ab"
saber se contémin / .startswith / .endswith"@" in email → True
achar a posição.find(x)"a@b".find("@") → 1
contar ocorrências.count(x)"banana".count("a") → 3
quebrar em pedaços.split(sep)"a,b".split(",") → ['a','b']
juntar pedaçossep.join(lista)"-".join(['a','b']) → "a-b"
recortar por posição[início:fim:passo]"PYTHON"[:3] → "PYT"
22 / 25
Colocando em prática · 35 minutos

Quatro funções, quatro linhas cada

O que entregar

1

contar_vogais(texto) — devolve quantas vogais existem, ignorando a caixa.

2

iniciais(nome) — "ana maria silva" → "A.M.S."

3

mascarar_email(email) — "ana@escola.com" → "a**@escola.com"

4

so_numeros(texto) — "(11) 98765-4321" → "11987654321"

Critério de pronto

  • Cada função tem docstring com Args e Returns
  • Cada função tem um teste com assert (padrão AAA da Semana 18)
  • Nenhuma função usa print — todas usam return
  • Você testou pelo menos um caso de borda: texto vazio, só espaços, ou sem o separador esperado
Dica para a 3: ache a posição do @ com find, fatie o usuário, e monte a máscara com [0] + "*" * (tamanho - 1).
23 / 25
Então ficamos assim…

Fechando o Dia 1 ✓

  • String é sequência → índice de 0 em diante, -1 é o último, len() dá o tamanho
  • String é imutável → todo método devolve uma nova string; sem atribuição, o resultado se perde
  • Fatiamento → [início:fim:passo], o fim não entra, [::-1] inverte
  • Limpeza → strip nas pontas · replace em todo lugar · lower/title na caixa
  • Busca → in pergunta, find localiza, count conta
  • split ⇄ join → desmonta em lista, remonta em texto
Próxima aula

No Dia 2, o texto deixa de ser recortado e passa a ser julgado: sanitizar, validar e formatar dados de entrada — com um validador de cadastro que nasce testado.

24 / 25
Cola de bolso

Strings em oito linhas

  • Índice começa em 0; o último é -1; o inválido é len(s)
  • Fatia: o fim nunca entra — s[a:b] tem b - a caracteres
  • Método de string nunca altera a variável: s = s.metodo()
  • Comparou texto de usuário? Passe .strip().lower() nos dois lados antes
  • find devolve -1 quando não acha; index quebra o programa
  • " ".join(texto.split()) resolve espaço duplicado em qualquer lugar
  • Montou texto de saída? Use f-string, não concatenação
  • Encadear é ler da esquerda para a direita: s.strip().lower().replace(...)
A pergunta do dia: "eu preciso de uma posição (então é fatiamento) ou de uma transformação (então é método)?".
25 / 25
Referências

De onde veio cada coisa

SEDUC-SP. Educação Profissional Paulista — Técnico em Desenvolvimento de Sistemas. Lógica de Programação — Manipulação de strings (Semana 19, aulas 1 e 2). Códigos: SISANO1C1B3S19A1 e A2.

ASCENCIO, A. F. G.; CAMPOS, E. A. V. Fundamentos da programação de computadores. São Paulo: Pearson Education do Brasil, 2012.

FORBELLONE, A. L. V.; EBERSPÄCHER, H. F. Lógica de programação: a construção de algoritmos e estruturas de dados. São Paulo: Pearson, 2005.

MENEZES, N. N. C. Introdução à programação com Python. 3. ed. São Paulo: Novatec, 2019.

PYTHON SOFTWARE FOUNDATION. Built-in Types — Text Sequence Type str. Documentação oficial. Disponível em: docs.python.org. Acesso em: 14 ago. 2026.

Aula compilada (dobradinha) · adaptação para apresentação HTML por Guilherme Antunes