Pular para o conteúdo

Fundamentos

Strings a fundo em Python: fatiamento e métodos mais usados

Domine as strings em Python: índices e fatias, imutabilidade, split, join, replace, find, formatação, e o que o MicroPython da ESP32 não tem.

Por Prof. Rodrigo Faustino · Atualizado em · 15 min de leitura

Uma string, ou texto, é uma sequência de caracteres. Como a lista e a tupla, ela tem índice, fatia e len, e se percorre com for. Diferente da lista, ela não pode ser alterada no lugar: todo método de texto devolve um texto novo e deixa o original como estava. A maior parte do trabalho com strings é saber quais métodos existem, o que cada um devolve e como juntar poucos deles para resolver problemas reais, como limpar o que o usuário digitou, separar os campos de uma mensagem ou alinhar números numa tela.

Os artigos anteriores já usaram o texto de várias formas: print e input, a conversão com str() e int(), strip e isdigit para validar, as f-strings. Aqui o assunto ganha o espaço próprio. Veremos os índices e as fatias, a imutabilidade, os métodos mais usados em grupos, a formatação, os caracteres e as sequências de escape, algumas receitas, usos na ESP32, e uma parte importante: vários métodos de texto do Python de computador não existem no MicroPython, e o simulador, que o imita, reproduz essa falta.

Texto é uma sequência

A palavra Python escrita em seis caixas com os índices de 0 a 5 acima e de menos 6 a menos 1 abaixo. As caixas y, t e h estão destacadas por uma chave com texto de 1 até 4, que dá yth. Embaixo aparecem os atalhos texto até 2, que dá Py, texto a partir de 3, que dá hon, e texto de menos 1, que dá n. Um aviso em vermelho diz que a fatia com passo menos 1 dá NotImplementedError no simulador e mostra a saída de reversed e join, que dá nohtyP.
O texto se indexa como uma lista. No simulador, a fatia com passo diferente de 1 não funciona.
texto = "Python"
print(texto[0], texto[1], texto[-1], texto[-2])
print(texto[1:4], texto[:2], texto[3:], texto[:])
print(texto[2:100], repr(texto[4:1]))
print(len(texto), texto + "!", texto * 2)
print("th" in texto, "ht" in texto, "Py" in texto)
for letra in texto:
    print(letra, end="-")
print()
print(ord("A"), ord("a"), chr(66), chr(97))
print("a" < "b", "B" < "a", "casa" < "casaco", "10" < "9")
print("fim")

A saída é P y n o, yth Py hon Python, thon '', 6 Python! PythonPython, True False True, P-y-t-h-o-n-, 65 97 B a, True True True True e fim.

Tudo o que o artigo sobre listas disse sobre índices e fatias vale aqui: o primeiro caractere está no índice 0, o -1 é o último, texto[1:4] vai do índice 1 até antes do 4, e uma fatia fora dos limites não dá erro. A diferença está no resultado: a fatia de um texto é outro texto, e a de uma lista é outra lista.

O operador in aplicado a texto procura um pedaço, e não só um caractere. "th" in "Python" dá True, e "ht" dá False, porque a ordem importa. O + junta textos, e o * repete.

As duas últimas linhas lembram que o computador guarda cada caractere como um número. O ord("A") devolve 65, e o chr(66) devolve B. A comparação entre textos usa esses números, caractere a caractere, e por isso "B" < "a" é verdadeiro, já que as maiúsculas vêm antes das minúsculas na tabela. E "10" < "9" também, porque o "1" vem antes do "9": comparar números escritos como texto dá ordem alfabética, e não numérica. É o mesmo cuidado que o artigo sobre conversão de tipos pediu ao ler dados do teclado.

A fatia com passo não funciona no simulador

No Python de computador, texto[::-1] é a receita mais conhecida para inverter um texto. No simulador, que imita o MicroPython, a fatia de texto com passo diferente de 1 não existe, como já acontecia com a tupla:

texto = "Python"
print(texto[::-1])
NotImplementedError: only slices with step=1 (aka None) are supported

A solução é pedir ao reversed, que percorre de trás para frente, e juntar o resultado:

texto = "Python"
print("".join(reversed(texto)))
print("".join(reversed("abc")))
print(list(texto)[::-1])
print("".join(list(texto)[::-1]))
print(texto[::1])
print(texto[0:6:1])
print("fim")

A saída é nohtyP, cba, ['n', 'o', 'h', 't', 'y', 'P'], nohtyP, Python, Python e fim. O "".join(reversed(texto)) é o caminho mais curto. A lista aceita a fatia com passo, e por isso list(texto)[::-1] funciona, mas a fatia direta no texto, só com o passo 1.

FastMindAssistente de IA local

A IA que lembra da sua vida e mora no seu computador

  • Memória de longo prazo com a fonte de cada resposta
  • Funciona offline: seus dados ficam no seu PC
  • Lê PDFs, slides, fotos e gravações de reunião
Baixar grátis para Windows

Plano Essencial grátis para sempre

O texto não muda: os métodos devolvem outro

Tentar trocar uma letra dá erro, e os métodos de transformação, como o upper, não alteram a variável:

s = "Ana"
print(s.upper(), s)
t = s.upper()
print(t, s)
print("a" + "b" * 3, "ab" "cd")
print("=" * 10)
print("Python".lower().startswith("py"), "x".join("abc"))
print("fim")

A saída é ANA Ana, ANA Ana, abbb abcd, uma linha de dez sinais de igual, True axbxc e fim. O s.upper() entregou ANA, e a variável s continuou Ana. Para guardar o resultado é preciso atribuir, como em t = s.upper(), ou s = s.upper() se o original não for mais necessário. Os métodos se encadeiam: "Python".lower().startswith("py") primeiro baixa as letras e depois pergunta pelo começo. O "x".join("abc") usa o x como separador entre as letras de abc, e o "ab" "cd" mostra que dois textos escritos lado a lado se juntam sozinhos.

Os métodos mais usados

Quatro quadros com métodos de texto. Limpar e trocar: strip, upper, lower e replace. Procurar: find devolve a posição ou menos 1, count conta as ocorrências e startswith devolve verdadeiro ou falso. Dividir e juntar: split separa em lista, join une uma lista com um separador e partition separa em três partes. Perguntar: isdigit, isalpha, isspace e isupper. Uma faixa diz que todos devolvem um texto novo ou uma resposta, e que o original nunca muda.
Os métodos de texto mais usados, agrupados pelo que fazem. Todos existem no simulador.

Os métodos que existem no simulador cabem em quatro famílias. A figura traz um exemplo de cada um, e o exemplo abaixo roda os principais:

s = "  Ola, Mundo  "
print(repr(s.strip()), repr(s.lstrip()), repr(s.rstrip()))
t = "Ola, Mundo"
print(t.upper(), t.lower())
print(t.replace("o", "0"), t.replace("o", "0", 1))
print(t.find("o"), t.find("z"), t.rfind("o"), t.count("o"))
print(t.index("M"))
print(t.startswith("Ola"), t.endswith("do"), t.startswith("ola"))
print(t.split(","), t.split())
print("a;b;c".split(";"), "a;b;c".split(";", 1))
print("-".join(["a", "b", "c"]), "".join(["x", "y"]), ", ".join(["1", "2"]))
print("fim")

A saída é 'Ola, Mundo' 'Ola, Mundo ' ' Ola, Mundo', depois OLA, MUNDO ola, mundo, Ola, Mund0 Ola, Mund0, 9 -1 9 1, 5, True True False, ['Ola', ' Mundo'] ['Ola,', 'Mundo'], ['a', 'b', 'c'] ['a', 'b;c'], a-b-c xy 1, 2 e fim.

Limpar e trocar. O strip tira os espaços das duas pontas, o lstrip só os da esquerda e o rstrip só os da direita. O repr foi usado para mostrar os espaços que sobram. O upper e o lower mudam a caixa. O replace(antigo, novo) troca todas as ocorrências, e um terceiro argumento limita quantas.

Procurar. O find devolve a posição da primeira ocorrência, ou -1 se não houver, e o rfind procura a partir do fim. O index faz o mesmo que o find, mas dá erro se não achar. O count conta as ocorrências, sem sobrepor. Repare que o t.count("o") deu 1, e não 2: o O maiúsculo de Ola não é um o, e a busca diferencia maiúsculas de minúsculas. O startswith e o endswith perguntam pelo começo e pelo fim.

Dividir e juntar. O split(sep) corta o texto em uma lista. Sem argumento, ele corta em qualquer sequência de espaços, e é por isso que t.split() deu ['Ola,', 'Mundo']. Com um separador, como ",", ele corta exatamente ali e conserva os espaços, e o segundo item ficou ' Mundo', com o espaço na frente. Um segundo argumento limita o número de cortes. O join faz o contrário: o separador vem antes do ponto, e a lista, entre parênteses: "-".join(lista). Os itens da lista precisam ser textos.

Mais dois que cabem aqui, e a lista de perguntas sobre o conteúdo:

print("123".isdigit(), "12a".isdigit(), "abc".isalpha(), "ab1".isalpha())
print("   ".isspace(), "ABC".isupper(), "abc".islower(), "Abc".isupper(), "Abc".islower())
print("ab".center(6) + "|")
print("a,b,c".partition(","), "a,b,c".rpartition(","))
print("a b c d".rsplit(" ", 1), "a b c d".split(" ", 1))
print("linha1\nlinha2".splitlines())
print("banana".rfind("an"), "banana".find("an"), "banana".rindex("a"))
print("fim")

A saída é True False True False, True True True False False, ab |, ('a', ',', 'b,c') ('a,b', ',', 'c'), ['a b c', 'd'] ['a', 'b c d'], ['linha1', 'linha2'], 3 1 5 e fim.

Perguntar. O isdigit, o isalpha, o isspace, o isupper e o islower dão True ou False. Atenção: elas são verdadeiras só quando todos os caracteres passam, e o texto vazio não passa. "Abc".isupper() e "Abc".islower() dão False os dois, porque o texto tem as duas caixas. O partition(sep) corta uma vez e devolve três partes numa tupla: antes, o separador e depois, e o rpartition corta na última ocorrência. O splitlines separa por quebras de linha. O center(6) centraliza o texto numa largura, e aqui, no simulador, aceita só a largura, sem o caractere de preenchimento.

O que o computador tem e a placa não

Tabela de duas colunas. À esquerda, métodos do Python de computador que não existem no simulador: capitalize, title, ljust, rjust, zfill, isalnum e a fatia com passo menos 1. À direita, o que escrever no lugar de cada um: primeira letra maiúscula com s de 0 upper mais s a partir de 1, a junção de palavras com a inicial maiúscula, f-strings com alinhamento menor e maior, f-string com 03d, um all com isalpha ou isdigit e join com reversed.
Alguns métodos de texto do computador faltam no MicroPython. Cada um tem um substituto simples.

Se você aprendeu métodos de texto num curso de Python para computador, vai esbarrar em uma surpresa: vários métodos que parecem básicos não existem no MicroPython. No simulador, os seguintes dão AttributeError: capitalize, title, swapcase, casefold, ljust, rjust, zfill, isalnum, isidentifier, istitle, removeprefix, removesuffix, translate e format_map, entre outros. Todos existem no Python de computador. A figura mostra o que escrever no lugar dos mais usados, e o exemplo abaixo confirma:

frase = "a ordem dos fatores"
palavras = frase.split()
print(len(palavras), palavras)
print([p[0].upper() + p[1:] for p in palavras])
print(" ".join(p[0].upper() + p[1:] for p in palavras))
print("".join(p[0] for p in palavras))
s = "7"
print("0" * (3 - len(s)) + s, f"{7:03d}")
nome = "ana"
print(nome[0].upper() + nome[1:])
print(f"{'ab':>5}|{'ab':<5}|{'ab':^5}|")

def so_letras_e_digitos(t):
    return all(c.isalpha() or c.isdigit() for c in t)

print(so_letras_e_digitos("ab1"), so_letras_e_digitos("ab 1"))
print("fim")

A saída é 4 ['a', 'ordem', 'dos', 'fatores'], ['A', 'Ordem', 'Dos', 'Fatores'], A Ordem Dos Fatores, aodf, 007 007, Ana, ab|ab | ab |, True False e fim.

O substituto da primeira letra maiúscula é t[0].upper() + t[1:]. Para o title, junta-se a mesma conta em cada palavra do split. Para alinhar à esquerda, à direita ou ao centro, a f-string resolve com :<, :> e :^. Para completar com zeros à esquerda, o :03d faz o trabalho de zfill em números, e "0" * (3 - len(s)) + s faz em textos. O que o isalnum perguntaria vira um all sobre os caracteres.

A regra de ouro é testar o método no simulador antes de usá-lo num programa para a placa. Se aparecer AttributeError: 'str' object has no attribute ..., o método não existe, e a lista acima dá o caminho.

FastTeacherPara professores

Da ementa ao semestre planejado

  • Plano de ensino e calendário montados sozinhos
  • Diário de aulas pronto para colar no SIGA
  • Slides e listas de exercícios com gabarito
Conhecer o FastTeacher

Versão Community grátis · Windows

Formatar textos

As f-strings já foram apresentadas no artigo sobre print e input. Aqui, o resumo das opções de formato, e as duas formas mais antigas, que ainda aparecem em código por aí:

nome = "Ana"
idade = 20
nota = 8.5
print(f"{nome} tem {idade} anos")
print(f"{nota:.2f} | {idade:5d}| {idade:<5d}| {idade:05d}")
print(f"{nome:>6}|{nome:<6}|{nome:^7}|")
print("{} tem {} anos".format(nome, idade))
print("{0} e {1} e {0}".format("a", "b"))
print("%s tem %d anos" % (nome, idade))
print("%.1f%%" % 45.5)
print(f"{255:x} {255:X} {5:08b}")
print(f"{'aspas'} {nome!r}")
print("fim")

A saída é Ana tem 20 anos, 8.50 | 20| 20 | 00020, Ana|Ana | Ana |, Ana tem 20 anos, a e b e a, Ana tem 20 anos, 45.5%, ff FF 00000101, 'aspas' 'Ana' e fim.

Depois dos dois pontos vem a especificação: .2f dá duas casas decimais, 5d reserva cinco posições para um inteiro, <, > e ^ alinham à esquerda, à direita e ao centro, 05d completa com zeros, e x, X e b escrevem em hexadecimal e em binário. O !r mostra o repr, com as aspas. O método format usa {} no texto e recebe os valores nos parênteses, com ou sem números de posição, e o operador % usa %s, %d e %f. As três formas dão o mesmo resultado, e a f-string é a mais legível. Se você usar :d com um texto, o erro é ValueError, como se vê adiante.

Caracteres especiais, aspas e acentos

print("linha1\nlinha2")
print("coluna1\tcoluna2")
print("barra \\ e aspas \" e '")
print('aspas "duplas" dentro')
print("""varias
linhas""")
print(r"c:\novo")
print(len("ação"), "ação"[2], "ação".upper())
print("ç" < "d", ord("ç"))
print(len("a\nb"))
print("fim")

A saída é linha1 e linha2 em duas linhas, coluna1 e coluna2 separadas por tabulação, barra \ e aspas " e ', aspas "duplas" dentro, varias e linhas em duas linhas, c:\novo, 4 ã AçãO, False 231, 3 e fim.

A barra invertida inicia uma sequência de escape: \n é a quebra de linha, \t é a tabulação, \\ é uma barra e \" é uma aspa dentro de um texto delimitado por aspas. O texto entre aspas simples pode ter aspas duplas dentro, e o contrário. As aspas triplas guardam o texto em várias linhas. O prefixo r (de raw, cru) desliga os escapes, e é útil para caminhos do Windows como c:\novo, em que o \n não é quebra de linha. O texto "a\nb" tem 3 caracteres, porque a quebra conta como um.

Com acentos, o simulador conta os caracteres do jeito esperado: len("ação") dá 4, e "ação"[2] é o ã. Mas há uma pegadinha nas duas últimas contas: "ação".upper() devolveu AçãO, com ç e ã intactos. No MicroPython, upper e lower só trocam as letras sem acento. No Python de computador, o resultado seria AÇÃO. A comparação "ç" < "d" também deu False, porque o código de ç é 231, bem maior que o de d, e por isso ordenar palavras acentuadas pela comparação direta não segue a ordem alfabética do português. Se o programa precisa ignorar maiúsculas em texto com acento, trate as letras acentuadas à mão, ou evite depender disso.

Receitas com texto

Alguns problemas clássicos mostram os métodos trabalhando juntos:

def eh_palindromo(t):
    t = t.lower().replace(" ", "")
    return t == "".join(reversed(t))

print(eh_palindromo("Ana"), eh_palindromo("Python"), eh_palindromo("A base do teto desaba"))

def cesar(t, k):
    r = ""
    for c in t:
        if "a" <= c <= "z":
            r += chr((ord(c) - ord("a") + k) % 26 + ord("a"))
        else:
            r += c
    return r

print(cesar("abc xyz", 3), cesar(cesar("abc xyz", 3), -3))
vogais = 0
for c in "programacao":
    if c in "aeiou":
        vogais += 1
print(vogais)
print("fim")

A saída é True False True, def abc abc xyz e 5, seguidos de fim. O palíndromo (texto que se lê igual nos dois sentidos) baixa as letras, tira os espaços e compara o texto com o seu inverso, e a inversão usa o join com reversed que vimos. A cifra de César desloca cada letra k posições no alfabeto: ord(c) - ord("a") dá a posição de 0 a 25, a soma com k e o % 26 dão a volta no alfabeto, e o chr converte de volta. Os caracteres fora de a a z, como o espaço, passam sem mudar, e aplicar a cifra com -3 desfaz a de 3. O contador de vogais usa o in para testar se a letra está em "aeiou". Atenção: o exemplo da cifra e o das vogais só tratam letras minúsculas sem acento.

Na ESP32: mensagens, comandos e colunas

Em projetos com a placa, o texto chega de fora em formatos simples: uma linha com campos separados, um comando digitado, uma resposta de sensor. O split e o startswith resolvem a maioria:

mensagem = "temp=24;umid=61;modo=auto"
dados = {}
for par in mensagem.split(";"):
    chave, valor = par.split("=")
    dados[chave] = valor
print(sorted(dados.items()))
temp = int(dados["temp"])
print(temp + 1)
comando = "LED ON"
if comando.startswith("LED"):
    estado = comando.split()[1]
    print("estado", estado)
nomes = ["Temp", "Umid"]
valores = [24, 61]
for nome, v in zip(nomes, valores):
    print(f"{nome:<6}{v:>4}")
print(f"{24:>3}C {61:>3}%")
print("fim")

A saída é [('modo', 'auto'), ('temp', '24'), ('umid', '61')], 25, estado ON, Temp 24, Umid 61, 24C 61% e fim. O primeiro bloco quebra a mensagem em pares com split(";"), abre cada par em chave e valor com split("="), e guarda num dicionário, como o artigo sobre dicionários apresentou. Os valores continuam textos, e o int(...) converte o que for número. O sorted na impressão evita depender da ordem do dicionário. O segundo bloco lê um comando: startswith("LED") reconhece a família e split()[1] pega a palavra seguinte. O terceiro monta colunas alinhadas com a f-string, o que é útil numa tela como a do artigo sobre I2C com OLED e LCD, em que cada linha tem largura fixa.

Erros comuns

As mensagens abaixo são as do simulador, que imita o MicroPython. O tipo do erro costuma ser o mesmo no Python de computador, e o texto pode mudar.

s = "Python"
s[0] = "J"
TypeError: 'str' object doesn't support item assignment

O texto não aceita troca de letra. O jeito é montar outro: "J" + s[1:].

s = "Python"
print(s[6])
IndexError: string index out of range

O texto tem 6 caracteres, e os índices vão de 0 a 5. É o mesmo erro do lista[len(lista)].

print("idade: " + 20)
TypeError: unsupported types for __add__: 'str', 'int'

O + entre texto e número não é uma conta válida. Use str(20), a vírgula do print ou uma f-string.

print("abc".index("z"))
ValueError: substring not found

O index dá erro quando o pedaço não existe. O find devolve -1, e é a escolha quando a ausência é normal.

print("a,b".split(",")[2])
IndexError: list index out of range

O split devolveu uma lista de dois itens, e o índice 2 não existe. O erro aparece na lista, e não no texto.

print(",".join([1, 2, 3]))
TypeError: join expects a list of str/bytes objects consistent with self object

O join só junta textos. Converta antes: ",".join([str(n) for n in lista]).

x, y = "a=b=c".split("=")
ValueError: too many values to unpack (expected 2)

O split encontrou dois sinais de igual e devolveu três partes. Para cortar só na primeira, use split("=", 1).

print(f"{'x':d}")
ValueError: unknown format code 'd' for object of type 'str'

O formato d é para inteiros. Num texto, o formato correto é o s, ou nenhum.

print("abc"[1.5])
TypeError: string indices must be integers, not float

O índice precisa ser inteiro, como na lista. A causa costuma ser uma divisão com /, e a correção, o //.

O que costuma aparecer em sala

Estes padrões se repetem em turmas de todos os níveis.

O primeiro é escrever s.upper() sozinho numa linha e achar que s mudou. Não dá erro, e a linha não faz nada: o resultado é descartado. A outra variante é s.strip() antes de um if, e depois testar a variável original. Toda vez que um método de texto "não funciona", a primeira pergunta é se o resultado foi guardado.

O segundo é o + com número, visto acima, que continua sendo o erro mais frequente de quem acabou de aprender o input.

O terceiro é a comparação de números escritos como texto. "10" < "9" dá True, e sorted(["10", "9", "100"]) ordena como dicionário, e não como número. A cura é converter com int antes de comparar.

O quarto é o split(",") em dados que têm espaços, que deixa os espaços colados nos itens, e o programa deixa de reconhecer "b" porque o item é " b". O strip em cada item resolve.

O quinto é procurar com in e depois usar o index sem lembrar que o texto pode aparecer mais de uma vez, ou com outra caixa. "Python" e "python" são textos diferentes, e a busca diferencia.

O sexto é levar os métodos do computador para a placa. O programa roda no PC, e no simulador ou na ESP32 o title ou o zfill dão AttributeError. É o tipo de erro que só aparece na hora de gravar.

O sétimo é a fatia [::-1], que funciona no PC e não funciona na placa, e é a razão pela qual a seção das fatias existe.

Exercício: analisar um e-mail

Escreva um programa que leia um e-mail, tire os espaços das pontas, passe tudo para minúsculas e mostre o usuário, o domínio, a extensão (a última parte do domínio) e as iniciais das partes do usuário separadas por ponto. Se o texto não tiver @, ele deve avisar que é inválido.

email = input("email: ").strip().lower()
if "@" not in email:
    print("invalido")
else:
    usuario, dominio = email.split("@")
    print("usuario", usuario)
    print("dominio", dominio)
    print("extensao", dominio.split(".")[-1])
    print("iniciais", "".join(p[0].upper() for p in usuario.split(".")))

Com a entrada Ana.Silva@Escola.com.br, as quatro linhas finais são usuario ana.silva, dominio escola.com.br, extensao br e iniciais AS. O split("@") separa as duas partes, e o desempacotamento do artigo sobre tuplas as entrega em usuario e dominio. O split(".")[-1] pega a última parte do domínio, e a compreensão pega a primeira letra de cada parte do usuário. Para treinar, trate o caso de um e-mail com dois @, que hoje quebra o desempacotamento, e verifique se a extensão tem pelo menos dois caracteres.

Perguntas frequentes

Posso alterar uma letra de um texto? Não. Monte outro texto com fatias, como "J" + s[1:], ou converta para lista com list(s), altere e junte de volta com "".join(...).

Qual a diferença entre find e index? O find devolve -1 quando não acha, e o index dá ValueError. Escolha pelo que a ausência significa no seu programa.

Aspas simples ou duplas? Tanto faz, e o resultado é o mesmo. Use as que evitam escapar: "it's" ou 'diz "oi"'.

Como comparo textos sem diferenciar maiúsculas? Passe os dois para lower() antes de comparar. Com letras acentuadas, lembre da limitação do upper e do lower no MicroPython.

Como junto números e textos numa linha só? Com f-string, que converte sozinha: f"{nome} tem {idade} anos".

O split() sem argumento é igual ao split(" ")? Não. O sem argumento trata qualquer sequência de espaços como um separador só e ignora os das pontas. O split(" ") corta em cada espaço, e dois espaços seguidos geram um item vazio.

Para continuar

Os desafios Tamanho do Nome, Repetir Texto e Comparar Textos praticam o len, a repetição e a comparação de textos. Para rever as bases, os artigos sobre print e input, conversão de tipos e dicionários completam este.

O próximo artigo trata das matrizes: listas de listas para guardar tabelas com linhas e colunas, como percorrê-las com laços aninhados e onde elas aparecem em projetos com a placa.

Para praticar no PyPlaca

Trilhas

Lições

Fichas de componentes

FastTeacherPara professores

Da ementa ao semestre planejado

  • Plano de ensino e calendário montados sozinhos
  • Diário de aulas pronto para colar no SIGA
  • Slides e listas de exercícios com gabarito
Conhecer o FastTeacher

Versão Community grátis · Windows

FastMindAssistente de IA local

A IA que lembra da sua vida e mora no seu computador

  • Memória de longo prazo com a fonte de cada resposta
  • Funciona offline: seus dados ficam no seu PC
  • Lê PDFs, slides, fotos e gravações de reunião
Baixar grátis para Windows

Plano Essencial grátis para sempre

FastTeacherPara professores

Da ementa ao semestre planejado

  • Plano de ensino e calendário montados sozinhos
  • Diário de aulas pronto para colar no SIGA
  • Slides e listas de exercícios com gabarito
Conhecer o FastTeacher

Versão Community grátis · Windows