C++ Funções de String

Um std::string não é só uma caixa de texto: ele vem com uma caixa de ferramentas. Com elas você procura uma palavra numa frase, recorta o dia de uma data, troca "gato" por "cachorro", apaga o "R$" de um preço e pergunta se o arquivo termina em ".pdf". Nesta aula você vai conhecer as ferramentas mais usadas, uma de cada vez, sempre com a saída real. A lista completa fica na referência std::string.

Você vai aprender
  • Procurar com find e rfind, e a armadilha do std::string::npos.
  • Recortar um pedaço com substr.
  • Trocar, inserir e apagar pedaços com replace, insert e erase.
  • Comparar textos com ==, < e compare.
  • Perguntar "começa com?", "termina com?" e "contém?" com starts_with, ends_with C++20 e contains C++23.
  • Passar a string inteira para maiúsculas e inverter a ordem dos caracteres.

Todos os programas desta aula foram compilados com o g++ 15.2 na máquina fictícia da Ana, na pasta ~/cpp, com o comando padrão g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa. Lembre que as posições começam em 0 (aula Acessar Caracteres).


A ideia: uma régua embaixo do texto

Quase todas as ferramentas desta aula trabalham com posições. Imagine uma régua colada embaixo da frase, marcando o índice de cada caractere:

O gato comeu o peixe do gato
0123456789012345678901234567
          1         2

Com a régua, as perguntas ficam simples. "Onde está gato?" Na posição 2. "Recorte 5 caracteres a partir da 15": peixe. Toda vez que você se perder, desenhe a régua.


1. Procurar: find e rfind

find ("achar") procura um texto (ou um caractere) e devolve a posição onde ele começa. rfind faz o mesmo de trás para a frente (o r é de reverse, "ao contrário"): acha a última ocorrência.

#include <iostream>
#include <string>

int main() {
    std::string frase = "O gato comeu o peixe do gato";
    std::cout << frase.find("gato") << '\n';
    std::cout << frase.find("peixe") << '\n';
    std::cout << frase.find('O') << '\n';
    std::cout << frase.find("gato", 3) << '\n';
    std::cout << frase.rfind("gato") << '\n';
    std::cout << frase.find("cachorro") << '\n';
}
$ g++ -std=c++23 -Wall -Wextra find.cpp -o find
$ ./find
2
15
0
24
24
18446744073709551615     « "cachorro" não existe na frase
frase.find("gato")
Procura do começo para o fim e devolve a posição da primeira ocorrência: 2 (olhe a régua).
frase.find('O')
Também procura um único char. O O maiúsculo é o primeiro caractere: posição 0. Atenção: find diferencia maiúsculas de minúsculas.
frase.find("gato", 3)
O segundo número diz de onde começar a procurar. A partir da posição 3, o primeiro gato já ficou para trás, e ele acha o segundo, na 24.
frase.rfind("gato")
A última ocorrência: 24.
frase.find("cachorro")
Não achou. E aí ele devolve esse número gigante: 18446744073709551615. É o npos, o assunto da próxima seção.

A armadilha do std::string::npos

Quando find não acha nada, ele precisa devolver algum número. Não pode ser 0, que é uma posição válida. Então ele devolve um valor especial, std::string::npos ("no position", nenhuma posição): o maior número possível do tipo std::size_t, que na máquina da Ana (64 bits) é 18446744073709551615. Nenhuma string tem uma posição tão grande, então ele significa "não está aqui".

A forma certa de perguntar "achou?" é comparar com npos:

#include <iostream>
#include <string>

int main() {
    std::string email = "ana@exemplo.com";
    std::size_t pos = email.find('@');
    if (pos != std::string::npos) {
        std::cout << "arroba na posição " << pos << '\n';
    } else {
        std::cout << "e-mail sem arroba\n";
    }
    if (email.find('#') == std::string::npos) {
        std::cout << "sem #\n";
    }
}
$ g++ -std=c++23 -Wall -Wextra npos.cpp -o npos
$ ./npos
arroba na posição 3
sem #
std::size_t pos = email.find('@');
Guarda a posição num std::size_t, o tipo que o find devolve (inteiro sem sinal, veja Inteiros).
pos != std::string::npos
"A posição é diferente de nenhuma posição?" = "achou?". O != é "diferente" (veja Comparação).
email.find('#') == std::string::npos
"Não achou?"

Agora o erro clássico. Parece lógico usar o resultado do find direto no if, como "achou ou não":

#include <iostream>
#include <string>

int main() {
    std::string frase = "gato preto";
    if (frase.find("gato")) {
        std::cout << "achei gato\n";
    } else {
        std::cout << "não achei gato\n";
    }
    if (frase.find("cachorro")) {
        std::cout << "achei cachorro\n";
    }
    int pos = frase.find("cachorro");
    std::cout << "pos em int: " << pos << '\n';
}
$ g++ -std=c++23 -Wall -Wextra armadilha.cpp -o armadilha
$ ./armadilha
não achei gato         « errado: gato está lá!
achei cachorro         « errado: cachorro não está!
pos em int: -1

Tudo ao contrário, e o compilador não avisou nada. O if trata 0 como falso e qualquer outro número como verdadeiro (veja Booleanos). gato foi achado na posição 0, então o if entendeu "falso". cachorro não foi achado, o resultado foi npos, um número enorme, e o if entendeu "verdadeiro".

A última linha mostra outro detalhe: guardado num int, o npos "dá a volta" e vira -1. Você vai ver código antigo testando pos == -1. Funciona por acaso; o certo é std::size_t e npos.

Regra de ouro do find

Nunca use o resultado do find sozinho num if. Compare sempre com std::string::npos. Se só quer saber "tem ou não tem", use contains (seção 7), que já devolve true/false.


2. Recortar: substr

substr ("substring", um pedaço da string) devolve uma nova string com um trecho da original. Você diz onde começa e quantos caracteres quer. A original não muda.

#include <iostream>
#include <string>

int main() {
    std::string data = "16/10/2026";
    std::string dia = data.substr(0, 2);
    std::string mes = data.substr(3, 2);
    std::string ano = data.substr(6);
    std::cout << dia << " | " << mes << " | " << ano << '\n';

    std::string email = "ana@exemplo.com";
    std::size_t arroba = email.find('@');
    std::cout << "usuário: " << email.substr(0, arroba) << '\n';
    std::cout << "domínio: " << email.substr(arroba + 1) << '\n';
    std::cout << data.substr(6, 100) << '\n';
}
$ g++ -std=c++23 -Wall -Wextra substr.cpp -o substr
$ ./substr
16 | 10 | 2026
usuário: ana
domínio: exemplo.com
2026
data.substr(0, 2)
A partir da posição 0, pegue 2 caracteres: 16. O segundo número é a quantidade, não a posição final (uma confusão muito comum).
data.substr(3, 2)
A partir da 3 (pulando o 16/), 2 caracteres: 10.
data.substr(6)
Sem a quantidade: daí até o fim. 2026.
email.substr(0, arroba)
A combinação mais útil: find acha a posição, substr recorta. Do começo até antes da arroba: a posição da arroba (3) é exatamente a quantidade de caracteres antes dela.
email.substr(arroba + 1)
Do caractere seguinte à arroba até o fim.
data.substr(6, 100)
Pedir mais caracteres do que existem não é erro: ele pega até o fim.

Já uma posição de começo além do fim é erro, e o substr lança a mesma exceção do .at():

$ cat substrerro.cpp
#include <iostream>
#include <string>

int main() {
    std::string data = "16/10/2026";
    std::cout << data.substr(20) << '\n';
}
$ g++ -std=c++23 -Wall -Wextra substrerro.cpp -o substrerro
$ ./substrerro
terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::substr: __pos (which is 20) > this->size() (which is 10)
Abortado                   (imagem do núcleo gravada) ./substrerro

Isso acontece muito com find + substr quando o find não acha nada: s.substr(s.find('@') + 1) com um texto sem arroba. Por isso, confira o npos antes de recortar.

Missão: separe o e-mail em usuário e domínio usando find e substr (sem escrever bruno nem lojinha no código), para mostrar:

usuário: bruno
domínio: lojinha.com.br
#include <iostream>
#include <string>

int main() {
    std::string email = "bruno@lojinha.com.br";
    // ache a arroba e recorte os dois pedaços

}
#include <iostream>
#include <string>

int main() {
    std::string email = "bruno@lojinha.com.br";
    std::size_t arroba = email.find('@');
    std::cout << "usuário: " << email.substr(0, arroba) << '\n';
    std::cout << "domínio: " << email.substr(arroba + 1) << '\n';
}

3. Trocar um pedaço: replace

replace ("substituir") apaga um trecho e coloca outro texto no lugar, na própria string. O texto novo pode ter qualquer tamanho.

#include <iostream>
#include <string>

int main() {
    std::string frase = "Eu gosto de gato";
    std::size_t pos = frase.find("gato");
    frase.replace(pos, 4, "cachorro");
    std::cout << frase << '\n';

    std::string data = "16/10/2026";
    data.replace(2, 1, "-");
    data.replace(5, 1, "-");
    std::cout << data << '\n';
}
$ g++ -std=c++23 -Wall -Wextra replace.cpp -o replace
$ ./replace
Eu gosto de cachorro
16-10-2026
frase.replace(pos, 4, "cachorro")
Três informações: onde começa o trecho (a posição de gato), quantos caracteres apagar (4, o tamanho de gato) e o que colocar no lugar. A frase cresce sozinha para caber cachorro.
data.replace(2, 1, "-")
Troca 1 caractere na posição 2 (a primeira /) por -.

replace troca um trecho. Para trocar todas as ocorrências, repita "procure, troque, procure de novo a partir dali" até o find devolver npos. O while ("enquanto") faz essa repetição (aula while); por enquanto, use como receita:

#include <iostream>
#include <string>

int main() {
    std::string texto = "pão, leite, pão de queijo, pão doce";
    std::string velho = "pão";
    std::string novo = "bolo";
    std::size_t pos = texto.find(velho);
    while (pos != std::string::npos) {
        texto.replace(pos, velho.size(), novo);
        pos = texto.find(velho, pos + novo.size());
    }
    std::cout << texto << '\n';
}
$ g++ -std=c++23 -Wall -Wextra replacetodos.cpp -o replacetodos
$ ./replacetodos
bolo, leite, bolo de queijo, bolo doce

O pos + novo.size() faz a próxima busca começar depois do texto que acabou de entrar. Sem ele, trocar "a" por "aa" acharia o a recém-colocado para sempre, e o programa nunca terminaria.


4. Inserir: insert

insert ("inserir") coloca um texto antes da posição indicada, empurrando o resto para a direita.

#include <iostream>
#include <string>

int main() {
    std::string nome = "Ana Souza";
    nome.insert(4, "Maria ");
    std::cout << nome << '\n';
    nome.insert(0, "Sra. ");
    std::cout << nome << '\n';
    std::string cep = "50030230";
    cep.insert(5, "-");
    std::cout << cep << '\n';
}
$ g++ -std=c++23 -Wall -Wextra insert.cpp -o insert
$ ./insert
Ana Maria Souza
Sra. Ana Maria Souza
50030-230
nome.insert(4, "Maria ")
Na posição 4 (onde está o S de Souza), insere Maria . O Souza vai para a direita.
nome.insert(0, "Sra. ")
Posição 0 = no começo. É o jeito de "acrescentar na frente" sem montar uma string nova (o += da aula Juntar Strings só acrescenta no fim).
cep.insert(5, "-")
Formata o CEP: o hífen entra antes do sexto dígito.

5. Apagar: erase, pop_back e clear

erase ("apagar") remove caracteres a partir de uma posição.

#include <iostream>
#include <string>

int main() {
    std::string nome = "Ana Maria Souza";
    nome.erase(4, 6);
    std::cout << "[" << nome << "]\n";

    std::string preco = "R$ 25,90";
    preco.erase(0, 3);
    std::cout << "[" << preco << "]\n";

    std::string frase = "Bom dia!!!";
    frase.erase(7);
    std::cout << "[" << frase << "]\n";

    std::string s = "abc";
    s.pop_back();
    std::cout << "[" << s << "]\n";
}
$ g++ -std=c++23 -Wall -Wextra erase.cpp -o erase
$ ./erase
[Ana Souza]
[25,90]
[Bom dia]
[ab]
nome.erase(4, 6)
A partir da posição 4, apaga 6 caracteres: Maria (5 letras e o espaço).
preco.erase(0, 3)
Apaga os 3 primeiros: R$ .
frase.erase(7)
Sem a quantidade: apaga da posição 7 até o fim. Os três ! somem.
s.pop_back()
Apaga o último caractere ("tirar do fundo"). Numa string vazia é comportamento indefinido.

Para apagar tudo, use s.clear() (aula Strings).


6. Comparar: ==, < e compare

Strings se comparam com os mesmos operadores dos números (aula Operadores de Comparação). == pergunta "são iguais?"; < pergunta "vem antes, na ordem do dicionário?".

#include <iostream>
#include <string>

int main() {
    std::string a = "banana";
    std::string b = "maçã";
    std::string c = "Banana";
    std::cout << std::boolalpha;
    std::cout << (a == "banana") << '\n';
    std::cout << (a == c) << '\n';
    std::cout << (a < b) << '\n';
    std::cout << (c < a) << '\n';
    std::cout << a.compare(b) << '\n';
    std::cout << b.compare(a) << '\n';
    std::cout << a.compare("banana") << '\n';
    std::cout << ("10" < std::string("9")) << '\n';
}
$ g++ -std=c++23 -Wall -Wextra compare.cpp -o compare
$ ./compare
true                 « a == "banana"
false                « "banana" e "Banana" são diferentes
true                 « "banana" vem antes de "maçã"
true                 « "Banana" vem antes de "banana"!
-11
11
0
true                 « "10" vem antes de "9"!
a == "banana"
Compara caractere por caractere. Funciona com um std::string de um lado e um literal do outro.
a == c
false: maiúsculas e minúsculas são caracteres diferentes.
a < b
Ordem "de dicionário": compara o primeiro caractere; se for igual, o segundo; e assim por diante. b vem antes de m.
c < a
"Banana" < "banana": a ordem é a da tabela de caracteres (ASCII, veja Caracteres), em que todas as maiúsculas vêm antes de todas as minúsculas. Para o computador, "Zebra" < "abacate".
a.compare(b)
Responde as três perguntas de uma vez: negativo se a vem antes, zero se são iguais, positivo se vem depois. O número exato (-11 é a distância entre b e m na tabela) muda de uma biblioteca para outra; só o sinal importa.
"10" < std::string("9")
true, porque o caractere '1' vem antes de '9'. Textos com números são comparados como texto, não como números. Para comparar valores, converta antes (aula Texto ↔ Número).
== ou compare?

No dia a dia, use ==, !=, < e >: ficam mais legíveis. O compare aparece em código antigo e em situações em que você quer as três respostas numa conta só (como numa ordenação, em Algoritmos).


7. Começa com, termina com, contém

Três perguntas que você faz o tempo todo, com respostas true/false, sem posições nem npos:

#include <iostream>
#include <string>

int main() {
    std::string arquivo = "relatorio-2026.pdf";
    std::cout << std::boolalpha;
    std::cout << arquivo.starts_with("relatorio") << '\n';
    std::cout << arquivo.ends_with(".pdf") << '\n';
    std::cout << arquivo.ends_with(".txt") << '\n';
    std::cout << arquivo.starts_with('r') << '\n';
    std::cout << arquivo.contains("2026") << '\n';
    std::cout << arquivo.contains('#') << '\n';
}
$ g++ -std=c++23 -Wall -Wextra starts.cpp -o starts
$ ./starts
true
true
false
true
true
false
FunçãoPerguntaDesdeAntes dela, como se fazia
s.starts_with(x)"Começa com x?"C++20s.rfind(x, 0) == 0 ou s.substr(0, …) == x
s.ends_with(x)"Termina com x?"C++20Comparar s.substr(s.size() - x.size()) (cuidado com tamanhos)
s.contains(x)"Tem x em algum lugar?"C++23s.find(x) != std::string::npos

Como elas são recentes, compilar com um padrão antigo dá erro. O g++ 15 usa C++17 se você não pedir outro (por isso o guia sempre usa -std=c++23):

$ g++ -std=c++17 -Wall -Wextra starts.cpp -o starts
starts.cpp: In function ‘int main()’:
starts.cpp:7:26: error: ‘std::string’ {aka ‘class std::__cxx11::basic_string<char>’} has no member named ‘starts_with’
    7 |     std::cout << arquivo.starts_with("relatorio") << '\n';
      |                          ^~~~~~~~~~~
starts.cpp:8:26: error: ‘std::string’ {aka ‘class std::__cxx11::basic_string<char>’} has no member named ‘ends_with’
    8 |     std::cout << arquivo.ends_with(".pdf") << '\n';
      |                          ^~~~~~~~~
starts.cpp:9:26: error: ‘std::string’ {aka ‘class std::__cxx11::basic_string<char>’} has no member named ‘ends_with’
    9 |     std::cout << arquivo.ends_with(".txt") << '\n';
      |                          ^~~~~~~~~
starts.cpp:10:26: error: ‘std::string’ {aka ‘class std::__cxx11::basic_string<char>’} has no member named ‘starts_with’
   10 |     std::cout << arquivo.starts_with('r') << '\n';
      |                          ^~~~~~~~~~~
starts.cpp:11:26: error: ‘std::string’ {aka ‘class std::__cxx11::basic_string<char>’} has no member named ‘contains’
   11 |     std::cout << arquivo.contains("2026") << '\n';
      |                          ^~~~~~~~
starts.cpp:12:26: error: ‘std::string’ {aka ‘class std::__cxx11::basic_string<char>’} has no member named ‘contains’
   12 |     std::cout << arquivo.contains('#') << '\n';
      |                          ^~~~~~~~
$ g++ -std=c++20 -Wall -Wextra starts.cpp -o starts
starts.cpp: In function ‘int main()’:
starts.cpp:11:26: error: ‘std::string’ {aka ‘class std::__cxx11::basic_string<char>’} has no member named ‘contains’
   11 |     std::cout << arquivo.contains("2026") << '\n';
      |                          ^~~~~~~~
starts.cpp:12:26: error: ‘std::string’ {aka ‘class std::__cxx11::basic_string<char>’} has no member named ‘contains’
   12 |     std::cout << arquivo.contains('#') << '\n';
      |                          ^~~~~~~~

"std::string não tem membro chamado starts_with". A função existe, mas não naquela versão da linguagem: com -std=c++20, só o contains (do C++23) continua faltando. Quando uma função "não existe" e você tem certeza do nome, desconfie do -std (veja Versões do C++).


8. Maiúsculas e minúsculas: toupper e tolower

O std::string não tem uma função "tudo em maiúsculas". Você faz isso caractere por caractere, com std::toupper ("para maiúscula") e std::tolower ("para minúscula"), do cabeçalho <cctype>, dentro de um laço for (char& c : s) (aula Acessar Caracteres):

#include <cctype>
#include <iostream>
#include <string>

int main() {
    std::string nome = "ana souza";
    for (char& c : nome) {
        c = std::toupper(static_cast<unsigned char>(c));
    }
    std::cout << nome << '\n';
}
$ g++ -std=c++23 -Wall -Wextra maiusculas.cpp -o maiusculas
$ ./maiusculas
ANA SOUZA
#include <cctype>
Traz as funções de "tipo de caractere" (character type): toupper, tolower, isdigit, isalpha…
for (char& c : nome)
Passa por cada caractere, com & para poder mudá-lo.
static_cast<unsigned char>(c)
Converte o caractere para "sem sinal" antes de entregar ao toupper (veja Conversão de Tipos). Parece burocracia, mas é obrigatório: os bytes dos acentos são negativos num char, e toupper com número negativo é comportamento indefinido. Com o unsigned char, eles viram números positivos válidos.
c = std::toupper(…)
Guarda a versão maiúscula de volta no caractere. Espaços, números e pontuação voltam iguais.

Uma forma mais curta, que você vai encontrar muito, usa std::transform (de <algorithm>) com uma lambda, uma "função de uma linha só" (aula Lambdas). Por enquanto, use como receita:

#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>

int main() {
    std::string sigla = "Ufpe";
    std::transform(sigla.begin(), sigla.end(), sigla.begin(),
                   [](unsigned char c) { return std::toupper(c); });
    std::cout << sigla << '\n';
    std::transform(sigla.begin(), sigla.end(), sigla.begin(),
                   [](unsigned char c) { return std::tolower(c); });
    std::cout << sigla << '\n';
}
$ g++ -std=c++23 -Wall -Wextra transform.cpp -o transform
$ ./transform
UFPE
ufpe

Leia como: "transforme de sigla.begin() (o começo) até sigla.end() (o fim), guardando a partir de sigla.begin(), aplicando toupper em cada caractere". O begin/end são iteradores, marcadores de começo e fim que você vai estudar em Iteradores.

toupper não entende acentos

"maçã" vira "MAçã": o ç e o ã ficam como estavam, porque cada um ocupa dois bytes e o toupper trabalha byte a byte. A aula Acentos e UTF-8 mostra isso e as saídas possíveis.


9. Inverter: std::reverse

Para inverter a ordem dos caracteres, use std::reverse ("inverter"), do cabeçalho <algorithm>. Ela muda a própria string.

#include <algorithm>
#include <iostream>
#include <string>

int main() {
    std::string palavra = "roma";
    std::reverse(palavra.begin(), palavra.end());
    std::cout << palavra << '\n';

    std::string p = "arara";
    std::string invertida = p;
    std::reverse(invertida.begin(), invertida.end());
    std::cout << std::boolalpha << (p == invertida) << '\n';
}
$ g++ -std=c++23 -Wall -Wextra reverse.cpp -o reverse
$ ./reverse
amor
true               « "arara" lida de trás para a frente é igual: um palíndromo
std::reverse(palavra.begin(), palavra.end())
Inverte tudo do começo ao fim. Não devolve nada: a mudança fica em palavra.
std::string invertida = p;
Para guardar a original, faça uma cópia e inverta a cópia.

Com acentos, o std::reverse inverte os bytes e quebra as letras de dois bytes. Veja o resultado em Acentos e UTF-8.


Quando dá errado

O if com find funciona ao contrário

O que significa: você escreveu if (s.find(x)). Achou na posição 0 vira "falso"; não achou (npos) vira "verdadeiro". O compilador não avisa.

Como consertar: if (s.find(x) != std::string::npos), ou if (s.contains(x)) no C++23.

Aparece 18446744073709551615 (ou -1)

O que significa: você mostrou o resultado de um find que não achou nada: é o std::string::npos. Guardado num int, ele aparece como -1.

Como consertar: confira com != std::string::npos antes de usar a posição. Guarde posições em std::size_t.

what(): basic_string::substr: __pos (which is 20) > this->size() (which is 10)

O que significa: o substr (ou o erase, o insert, o replace) recebeu uma posição de começo maior que o tamanho. É um std::out_of_range. Muitas vezes a posição veio de um find que devolveu npos.

Como consertar: confira o resultado do find antes de usá-lo. Lembre que o segundo número do substr é a quantidade, não a posição final.

error: ‘std::string’ … has no member named ‘starts_with’ (ou ends_with, contains)

O que significa: a função é mais nova que o padrão com que você compilou. Sem -std, o g++ 15 usa C++17.

Como consertar: compile com -std=c++23. Se o nome estiver digitado errado (startswith, startsWith), a mensagem é a mesma: confira também a escrita.

Aparece 65 em vez de A
#include <cctype>
#include <iostream>
#include <string>

int main() {
    std::string nome = "ana";
    for (char& c : nome) {
        c = std::toupper(c);
    }
    std::cout << nome << '\n';
    std::cout << std::toupper('a') << '\n';
}
$ g++ -std=c++23 -Wall -Wextra toupper1.cpp -o toupper1
$ ./toupper1
ANA
65

O que significa: std::toupper devolve um int (o código do caractere), não um char. Guardado num char (primeira linha), vira letra de novo. Mostrado direto com std::cout, aparece o número: 65 é o código do A.

Como consertar: guarde num char antes de mostrar, ou converta: static_cast<char>(std::toupper('a')). E, com texto que pode ter acento, não esqueça o static_cast<unsigned char> na entrada.


Referência rápida

FunçãoO que fazExemplo (com s = "gato preto")
s.find(x)Posição da primeira ocorrência, ou nposs.find("preto") → 5
s.find(x, ini)O mesmo, começando em inis.find('o', 4) → 9
s.rfind(x)Posição da última ocorrências.rfind('o') → 9
std::string::npos"Não achou"s.find("x") == std::string::npos
s.substr(ini, n)Cópia de n caracteres a partir de inis.substr(0, 4) → "gato"
s.substr(ini)Cópia de ini até o fims.substr(5) → "preto"
s.replace(ini, n, x)Troca n caracteres a partir de ini por xs.replace(0, 4, "cão") → "cão preto"
s.insert(ini, x)Insere x antes da posição inis.insert(0, "o ") → "o gato preto"
s.erase(ini, n) / s.erase(ini)Apaga n caracteres / até o fims.erase(4) → "gato"
s.pop_back() / s.clear()Apaga o último / tudo
== != < >Comparam (ordem da tabela de caracteres)"Zebra" < "abacate" → true
s.compare(x)Negativo, zero ou positivos.compare("gato preto") → 0
s.starts_with(x) / s.ends_with(x)Começa / termina com x C++20s.ends_with("to") → true
s.contains(x)Contém x C++23s.contains("ato") → true
std::toupper(c) / std::tolower(c)Um caractere para maiúscula / minúscula (<cctype>)Use num laço, com unsigned char
std::reverse(s.begin(), s.end())Inverte a string (<algorithm>)"gato preto" → "oterp otag"

Todas as outras funções (find_first_of, resize, swap, c_str…) estão na referência std::string.


Exercícios

1. Achou?

Complete a condição que pergunta se "@" existe em email:

if (email.find('@') != std::string::)

2. Recortar

Com data = "16/10/2026", complete para pegar o ano (os 4 últimos caracteres, a partir da posição 6):

std::string ano = data.(6);

3. Termina com

Complete para perguntar se arquivo termina em .csv (C++20):

arquivo.(".csv")

4. Com std::string s = "abacaxi";, quanto vale s.substr(2, 3)?

5. Com std::string s = "uva";, o que if (s.find("u")) { … } faz?

6. Qual destas comparações dá true?

Missão final: arrumar o nome do arquivo

Missão: o nome do arquivo veio bagunçado. Usando as ferramentas da aula: (1) ache o espaço com find e troque-o por _ com replace; (2) passe tudo para minúsculas com std::tolower num laço; (3) responda com ends_with se é um arquivo .txt. A saída deve ser:

relatorio_final.txt
É texto? true
#include <cctype>
#include <iostream>
#include <string>

int main() {
    std::string arquivo = "Relatorio Final.TXT";
    // 1) troque o espaço por _

    // 2) tudo em minúsculas

    std::cout << arquivo << '\n';
    // 3) mostre "É texto? " e a resposta do ends_with
}
#include <cctype>
#include <iostream>
#include <string>

int main() {
    std::string arquivo = "Relatorio Final.TXT";
    std::size_t espaco = arquivo.find(' ');
    arquivo.replace(espaco, 1, "_");
    for (char& c : arquivo) {
        c = std::tolower(static_cast<unsigned char>(c));
    }
    std::cout << arquivo << '\n';
    std::cout << std::boolalpha << "É texto? " << arquivo.ends_with(".txt") << '\n';
}

Resumo

  • find/rfind devolvem a posição, ou std::string::npos quando não acham. Sempre compare com npos; nunca use o resultado sozinho num if.
  • substr(ini, n) recorta (o segundo número é a quantidade). Começo além do fim lança std::out_of_range.
  • replace(ini, n, x), insert(ini, x) e erase(ini, n) mudam a própria string.
  • == e < comparam pela tabela de caracteres: maiúsculas antes de minúsculas, "10" < "9". compare devolve negativo, zero ou positivo.
  • starts_with/ends_with C++20 e contains C++23 respondem true/false; exigem -std=c++20/c++23.
  • Maiúsculas: laço com std::toupper(static_cast<unsigned char>(c)). Inverter: std::reverse(s.begin(), s.end()). Nenhum dos dois lida bem com acentos.