Lista 07 · Arquivos¶
Exercícios da Semana 7 — Lendo e escrevendo dados. Estes exercícios testam a lógica de leitura/escrita usando std::istringstream/std::ostringstream (que simulam um arquivo em memória) em vez de arquivo de disco — assim funcionam em qualquer compilador online. O std::ifstream/std::ofstream de verdade fica só na demonstração do capítulo.
Como resolver
Copie o bloco de código de cada exercício, cole no seu compilador online, preencha a parte marcada como ESCREVA SUA SOLUCAO AQUI e rode. A saída mostra quais testes passaram.
ex01¶
Escreva parseia_linha, que recebe uma linha no formato "nome,idade" e devolve um std::pair<std::string, int> com o nome e a idade já convertida para int. Use std::istringstream e std::getline com delimitador ','.
// ex01 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
#include <sstream>
#include <utility>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX01_H
#define EX01_H
// Recebe uma linha "nome,idade" e retorna {nome, idade} (idade ja convertida para int).
std::pair<std::string, int> parseia_linha(const std::string& linha);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
std::pair<std::string, int> parseia_linha(const std::string& linha) {
// TODO: use std::istringstream(linha), std::getline(..., ',') para o nome,
// depois std::getline no resto e std::stoi para converter a idade.
return {"", 0};
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
auto r1 = parseia_linha("Ana,25");
assert(r1.first == std::string("Ana"));
assert(r1.second == 25);
auto r2 = parseia_linha("Bruno,30");
assert(r2.first == std::string("Bruno"));
assert(r2.second == 30);
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex02¶
Escreva conta_linhas, que recebe um conteúdo de "arquivo" (várias linhas separadas por \n, como std::string) e devolve quantas linhas não vazias ele tem.
conta_linhas("Ana,25\nBruno,30\nCarla,22") // -> 3
conta_linhas("") // -> 0
conta_linhas("uma linha so") // -> 1
// ex02 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
#include <sstream>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX02_H
#define EX02_H
// Retorna quantas linhas nao vazias existem em "conteudo".
int conta_linhas(const std::string& conteudo);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
int conta_linhas(const std::string& conteudo) {
// TODO: use std::istringstream(conteudo) e um while(std::getline(...))
// contando as linhas que nao estao vazias (linha.empty()).
return 0;
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
assert(conta_linhas("Ana,25\nBruno,30\nCarla,22") == 3);
assert(conta_linhas("") == 0);
assert(conta_linhas("uma linha so") == 1);
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex03¶
Dada a struct Pessoa (campos nome e idade, já declarada), escreva parseia_pessoas_validas, que recebe um conteúdo com várias linhas "nome,idade" e devolve um std::vector<Pessoa> — descartando silenciosamente as linhas malformadas, na ordem em que as boas aparecem.
Arquivo de verdade tem lixo dentro: linha em branco, linha sem vírgula, idade que não é número, nome vazio. Um programa que confia no formato quebra no primeiro arquivo real. Aqui a regra é a oposta: uma linha ruim não derruba as outras.
Uma linha é válida quando:
- tem uma vírgula;
- o pedaço antes da vírgula (o nome) não está vazio;
- o pedaço depois da vírgula é composto só de dígitos, e tem pelo menos um.
Cuidado com std::stoi: ela aceita "25anos" (converte os 25 e ignora o resto) e lança exceção em "vinte", derrubando o programa inteiro. Confira que o texto da idade só tem dígitos antes de chamá-la — com um laço e c >= '0' && c <= '9', como você fez no ex04 da Lista 03.
Para saber se a vírgula existe: depois de std::getline(linha_stream, nome, ','), se não havia vírgula na linha, o nome recebe a linha inteira e o resto vem vazio. Ler o segundo pedaço e testar se ele está vazio resolve os dois casos de uma vez.
parseia_pessoas_validas("Ana,25\nlixo\nBruno,30")
// -> { {"Ana", 25}, {"Bruno", 30} }
parseia_pessoas_validas("Ana,vinte\n,40\nCarla,22")
// -> { {"Carla", 22} }
// ex03 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX03_H
#define EX03_H
struct Pessoa {
std::string nome;
int idade;
};
// Recebe varias linhas "nome,idade" (separadas por \n) e retorna um vector
// de Pessoa, descartando as linhas malformadas.
std::vector<Pessoa> parseia_pessoas_validas(const std::string& conteudo);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
std::vector<Pessoa> parseia_pessoas_validas(const std::string& conteudo) {
// TODO: percorra o conteudo linha por linha (std::getline num while).
// Para cada linha:
// - separe nome e idade_texto com std::getline(..., ',') e std::getline;
// - descarte se o nome estiver vazio ou se idade_texto estiver vazio;
// - descarte se idade_texto tiver algum caractere que nao seja digito;
// - senao, adicione Pessoa{nome, std::stoi(idade_texto)} ao resultado.
return {};
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
auto r1 = parseia_pessoas_validas("Ana,25\nBruno,30");
assert(r1.size() == static_cast<std::size_t>(2));
assert(r1[0].nome == std::string("Ana"));
assert(r1[0].idade == 25);
assert(r1[1].nome == std::string("Bruno"));
assert(r1[1].idade == 30);
// linha sem virgula no meio: as boas continuam vindo
auto r2 = parseia_pessoas_validas("Ana,25\nlixo\nBruno,30");
assert(r2.size() == static_cast<std::size_t>(2));
assert(r2[0].nome == std::string("Ana"));
assert(r2[1].nome == std::string("Bruno"));
// idade que nao e numero (stoi lancaria excecao) e nome vazio
auto r3 = parseia_pessoas_validas("Ana,vinte\n,40\nCarla,22");
assert(r3.size() == static_cast<std::size_t>(1));
assert(r3[0].nome == std::string("Carla"));
assert(r3[0].idade == 22);
// idade com sufixo: stoi aceitaria "25anos" como 25, e nao pode
auto r4 = parseia_pessoas_validas("Ana,25anos\nBruno,30");
assert(r4.size() == static_cast<std::size_t>(1));
assert(r4[0].nome == std::string("Bruno"));
// idade vazia depois da virgula
auto r5 = parseia_pessoas_validas("Ana,\nBruno,30");
assert(r5.size() == static_cast<std::size_t>(1));
assert(r5[0].nome == std::string("Bruno"));
// linhas em branco no meio e no fim
auto r6 = parseia_pessoas_validas("Ana,25\n\nBruno,30\n");
assert(r6.size() == static_cast<std::size_t>(2));
// conteudo vazio e conteudo sem nenhuma linha valida
assert(parseia_pessoas_validas("").empty());
assert(parseia_pessoas_validas("lixo\nmais lixo").empty());
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex04¶
Escreva monta_csv, o inverso do exercício anterior: recebe um std::vector<Pessoa> e devolve o texto no formato "nome,idade" por linha, usando std::ostringstream. A última linha não deve ter \n no final.
// ex04 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX04_H
#define EX04_H
struct Pessoa {
std::string nome;
int idade;
};
// Monta o texto CSV (uma linha "nome,idade" por Pessoa, sem \n no final da ultima linha).
std::string monta_csv(const std::vector<Pessoa>& pessoas);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
std::string monta_csv(const std::vector<Pessoa>& pessoas) {
// TODO: use um std::ostringstream, escreva "nome,idade" para cada Pessoa,
// colocando "\n" ANTES de cada linha exceto a primeira (para nao sobrar
// \n no final). Ao final, retorne stream.str().
return "";
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
std::vector<Pessoa> p1 = {{"Ana", 25}, {"Bruno", 30}};
assert(monta_csv(p1) == std::string("Ana,25\nBruno,30"));
std::vector<Pessoa> p2 = {};
assert(monta_csv(p2) == std::string(""));
std::vector<Pessoa> p3 = {{"Carla", 22}};
assert(monta_csv(p3) == std::string("Carla,22"));
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex05¶
Escreva soma_idades, que recebe um conteúdo CSV (várias linhas "nome,idade") e devolve a soma de todas as idades.
// ex05 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
#include <sstream>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX05_H
#define EX05_H
// Recebe varias linhas "nome,idade" e retorna a soma de todas as idades.
int soma_idades(const std::string& conteudo);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
int soma_idades(const std::string& conteudo) {
// TODO: percorra as linhas (igual exercicio 3), some as idades de cada uma.
return 0;
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
assert(soma_idades("Ana,25\nBruno,30\nCarla,22") == 77);
assert(soma_idades("") == 0);
assert(soma_idades("Zeca,10") == 10);
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex06¶
Escreva nome_mais_velho, que recebe um conteúdo CSV não vazio (várias linhas "nome,idade") e devolve o nome da pessoa com a maior idade.
// ex06 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
#include <sstream>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX06_H
#define EX06_H
// Recebe varias linhas "nome,idade" (assume conteudo nao vazio) e retorna o
// nome da pessoa com maior idade.
std::string nome_mais_velho(const std::string& conteudo);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
std::string nome_mais_velho(const std::string& conteudo) {
// TODO: percorra as linhas guardando o nome da maior idade vista ate agora.
return "";
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
assert(nome_mais_velho("Ana,25\nBruno,30\nCarla,22") == std::string("Bruno"));
assert(nome_mais_velho("Zeca,10") == std::string("Zeca"));
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex07¶
Escreva frequencia_palavras, que recebe o conteúdo de um arquivo de texto (como std::string, do mesmo jeito que nos exercícios anteriores desta lista) e devolve um std::map<std::string, int> com quantas vezes cada palavra aparece.
Palavras são separadas por qualquer espaço em branco — inclusive quebras de linha. std::istringstream já trata os dois casos igual: basta ler com >> até acabar.
// ex07 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
#include <map>
#include <sstream>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX07_H
#define EX07_H
// Retorna quantas vezes cada palavra aparece no conteudo.
// Palavras sao separadas por espacos ou quebras de linha.
std::map<std::string, int> frequencia_palavras(const std::string& conteudo);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
std::map<std::string, int> frequencia_palavras(const std::string& conteudo) {
// TODO: crie um std::istringstream com o conteudo e leia palavra por
// palavra com >>. Para cada palavra lida, some 1 no map.
return {};
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
std::map<std::string, int> f = frequencia_palavras("um dois\num dois um");
assert(f.size() == 2);
assert(f["um"] == 3);
assert(f["dois"] == 2);
std::map<std::string, int> uma = frequencia_palavras("sozinha");
assert(uma.size() == 1);
assert(uma["sozinha"] == 1);
assert(frequencia_palavras("").empty());
assert(frequencia_palavras(" \n ").empty());
// Maiuscula e minuscula sao palavras diferentes.
std::map<std::string, int> caixa = frequencia_palavras("Led led");
assert(caixa.size() == 2);
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex08¶
Escreva filtra_por_idade, que recebe um conteúdo CSV (várias linhas "nome,idade") e uma idade mínima, e devolve um novo conteúdo CSV contendo só as linhas em que a idade é maior ou igual à mínima, na mesma ordem.
Assim como no ex04, a última linha do resultado não deve terminar com \n. Se nenhuma linha passar no filtro, devolva uma string vazia.
// ex08 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
#include <sstream>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX08_H
#define EX08_H
// Retorna as linhas "nome,idade" do conteudo em que idade >= idade_minima,
// na ordem original e sem \n no fim da ultima linha.
std::string filtra_por_idade(const std::string& conteudo, int idade_minima);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
std::string filtra_por_idade(const std::string& conteudo, int idade_minima) {
// TODO: leia o conteudo linha a linha com std::getline. Em cada linha,
// separe o que vem depois da virgula e converte com std::stoi.
// Monte a saida so com as linhas aprovadas, cuidando para nao deixar
// um \n sobrando no fim.
return "";
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
assert(filtra_por_idade("ana,20\nbruno,15\ncarla,31", 18)
== std::string("ana,20\ncarla,31"));
// A idade minima entra: a comparacao e >=.
assert(filtra_por_idade("ana,18", 18) == std::string("ana,18"));
assert(filtra_por_idade("bruno,15", 18) == std::string(""));
assert(filtra_por_idade("", 18) == std::string(""));
assert(filtra_por_idade("ana,20\nbruno,25", 18)
== std::string("ana,20\nbruno,25"));
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex09¶
Escreva linha_mais_longa, que recebe o conteúdo de um arquivo (várias linhas separadas por \n) e devolve a linha mais longa. Se houver empate, devolva a primeira; se não houver nenhuma linha não vazia, devolva a string vazia.
É o padrão "guardar o melhor até agora" da Lista 05, agora aplicado a linhas em vez de números. Nada de std::max_element.
linha_mais_longa("ab\nabcd\nabc") // -> "abcd"
linha_mais_longa("abc\nxyz") // -> "abc" (empate: a primeira)
// ex09 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
#include <sstream>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX09_H
#define EX09_H
// Retorna a primeira linha mais longa do conteudo, ou "" se nao houver
// nenhuma linha nao vazia.
std::string linha_mais_longa(const std::string& conteudo);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
std::string linha_mais_longa(const std::string& conteudo) {
// TODO: leia linha a linha com std::getline e guarde a mais longa
// vista ate agora. Use > (e nao >=) para ficar com a PRIMEIRA em
// caso de empate.
return "";
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
assert(linha_mais_longa("ab\nabcd\nabc") == std::string("abcd"));
assert(linha_mais_longa("uma linha so") == std::string("uma linha so"));
// empate: fica a primeira
assert(linha_mais_longa("abc\nxyz") == std::string("abc"));
assert(linha_mais_longa("") == std::string(""));
assert(linha_mais_longa("\n\n") == std::string(""));
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex10¶
Escreva media_notas_csv, que recebe um conteúdo não vazio com várias linhas no formato "nome,nota" (a nota é double) e devolve a média das notas.
É o mesmo parsing que você faria depois de ler um arquivo, só que recebendo o conteúdo já em memória — o que torna a função testável sem depender de arquivo nenhum.
// ex10 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX10_H
#define EX10_H
// Recebe varias linhas "nome,nota" (nao vazio) e retorna a media das notas.
double media_notas_csv(const std::string& conteudo);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
double media_notas_csv(const std::string& conteudo) {
// TODO: percorra as linhas (igual Lista 07), some as notas (std::stod
// converte string para double) e divida pela quantidade de linhas.
return 0.0;
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
assert(std::abs((media_notas_csv("Ana,8.0\nBruno,6.0")) - (7.0)) <= (0.0001));
assert(std::abs((media_notas_csv("Carla,10.0")) - (10.0)) <= (0.0001));
assert(std::abs((media_notas_csv("A,5.0\nB,5.0\nC,5.0")) - (5.0)) <= (0.0001));
std::cout << "Todos os testes passaram!\n";
return 0;
}