Erro ao converter string para inteiro[RESOLVIDO]

1. Erro ao converter string para inteiro[RESOLVIDO]

César
dark777

(usa Debian)

Enviado em 07/04/2024 - 03:59h

Ola galera beleza?

tenho o seguinte programa para ler os dados de um arquivo csv para calculos de probabilidade porem nao estou conseguindo converter a string para int ao executar ele da erro de:

terminate called after throwing an instance of 'std::invalid_argument'
what(): stoi
Abortado (imagem do núcleo gravada)


Esses dias fiz o teste e tina funcionado ele estava convertendo o numero do concurso para inteiro nao sei o que aconteceu. Como converter a string para inteiro corretamente?


#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <algorithm>

// Estrutura para leitura dos dados de um arquivo csv
struct ReadData
{
int numbers;

std::vector<int> colunas;
};

// Função para limpar uma string removendo espaços em branco
std::string isSpace(const std::string& str)
{
std::string resultado;

for (char c : str)
{
if (!std::isspace(c))
{
resultado += c;
}
}

return resultado;
}

// Função para ler os dados do arquivo CSV
std::vector<ReadData> getDetails(const std::string& filename)
{
std::vector<ReadData> details;

std::ifstream arquivo(filename);

if (!arquivo.is_open())
{
std::cerr << "Erro ao abrir o arquivo " << filename << std::endl;

return details;
}

std::string linha;

// Descartar a primeira linha (cabeçalho)
std::getline(arquivo, linha);

while (std::getline(arquivo, linha))
{
std::stringstream ss(linha);

std::string celula;

ReadData get;

// Lê o número da celula
std::getline(ss, celula, ',');

get.numbers = std::stoi(isSpace(celula));

// Descartar a 2ª coluna
std::getline(ss, celula, ',');

// Ler os números sorteados
for(int i = 2; i < 7; ++i)
{
std::getline(ss, celula, ',');

// Verifica se a célula contém apenas dígitos
if (celula.find_first_not_of("0123456789") == std::string::npos)
{
// Converte string para int e adiciona ao vetor
get.colunas.push_back(std::stoi(celula));
}
}

details.push_back(get);
}

return details;
}


// Função para exibir os dados
void printDetails(const std::vector<ReadData>& dados)
{
for (const auto& get : dados)
{
std::cout << "Concurso: " << get.numbers << std::endl;

std::cout << "Números: ";

for (int num : get.colunas) std::cout << num << " ";

std::cout << "\n\n";
}
}

int main()
{
std::vector<ReadData> dados = getDetails("./historico_megasena.csv");

printDetails(dados);

return 0;
}


wiki.anon


  


2. Re: Erro ao converter string para inteiro

Paulo
paulo1205

(usa Ubuntu)

Enviado em 07/04/2024 - 07:00h

std::stoi() e semelhantes disparam essa exceção quando não conseguem aproveitar nenhum pedaço da string na hora de converter para inteiro.

Você tem controle sobre a geração do arquivo CSV?

Você tem ciência de que existe variabilidade para a formatação de arquivos CSV, tais como usar ponto-e-vírgula (“;”) em lugar de vírgula como separador (o que inclusive é comum em CSVs gerados a partir programas traduzidos para o Português, pois a vírgula pode ser usada como separador de casas decimais em números não-inteiros), ou colocar os valores de cada célula entre aspas, inclusive a fim de permitir que possa haver não apenas a presença de vírgulas (ou de pontos-e-vírgulas) dentro de uma célula, mas até mesmo de quebras de linha, certo?

Se acontecer qualquer uma dessas variações, seu código de leitura do CSV pode falhar. Então eu sugiro que você veja se o problema não pode estar justamente em o arquivo de entrada usar uma variação de formato diferente do que o seu parser espera.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


3. Re: Erro ao converter string para inteiro

César
dark777

(usa Debian)

Enviado em 07/04/2024 - 16:45h

paulo1205 escreveu:

std::stoi() e semelhantes disparam essa exceção quando não conseguem aproveitar nenhum pedaço da string na hora de converter para inteiro.

Você tem controle sobre a geração do arquivo CSV?

Você tem ciência de que existe variabilidade para a formatação de arquivos CSV, tais como usar ponto-e-vírgula (“;”) em lugar de vírgula como separador (o que inclusive é comum em CSVs gerados a partir programas traduzidos para o Português, pois a vírgula pode ser usada como separador de casas decimais em números não-inteiros), ou colocar os valores de cada célula entre aspas, inclusive a fim de permitir que possa haver não apenas a presença de vírgulas (ou de pontos-e-vírgulas) dentro de uma célula, mas até mesmo de quebras de linha, certo?

Se acontecer qualquer uma dessas variações, seu código de leitura do CSV pode falhar. Então eu sugiro que você veja se o problema não pode estar justamente em o arquivo de entrada usar uma variação de formato diferente do que o seu parser espera.


originalmente a saida dos dados estava no seguinte formato:
"12345" "00/00/00" "01" "02" "03" "04" "05" "06" 


wiki.anon


4. Re: Erro ao converter string para inteiro

Paulo
paulo1205

(usa Ubuntu)

Enviado em 07/04/2024 - 20:24h

dark777 escreveu:

originalmente a saida dos dados estava no seguinte formato:
"12345" "00/00/00" "01" "02" "03" "04" "05" "06" 


Com esse formato, eu entendo que não dá nem para dizer que é um CSV, pois não tem vírgulas separando os valores, somente espaços, e os valores de cada célula estão entre aspas.

Se o formato vai ser seguramente sempre esse em todas as linhas, eu acho que a forma mais enxuta e segura de pegar as partes que lhe interessam é ler a linha inteira, e submeter a linha linha a uma chamada a sscanf(), pegando as partes que lhe interessarem, mais ou menos da seguinte maneira.
struct data_record {
unsigned id_number;
int cols[6];
};

[[nodiscard]] std::vector<data_record> read_file_data(const std::string &filename){
std::vector<data_record> result;
std::ifstream is;
is.exceptions(std::ios::badbit);
is.open(filename);
std::string line;
unsigned lineno=0;
while(getline(is, line)){
++lineno;
data_record r;
int used_chars=0;
int rc=sscanf(line.c_str(), R"("%u" "%*u/%*u/%*u" "%d" "%d" "%d" "%d" "%d" "%d" %n)", &r.id_number, &r.cols[0], &r.cols[1], &r.cols[2], &r.cols[3], &r.cols[4], &r.cols[5], &used_chars);
if(rc==7 && static_cast<size_t>(used_chars)==line.length())
result.emplace_back(std::move(r));
else
std::cerr << "Invalid line in file " << filename << ", line number " << lineno << ".\n";
}
return result;
}


Em tempo: no exemplo acima, eu mudei o nome de o tipo de dados, de um de um dos seus campos, da função que faz a leitura e da variável intermediária que armazena os campos da linha lida, porque os nomes que você usou no seu programa original não estavam refletindo muito bem o propósito de cada um desses símbolos. Entre eles, para mim o pior era a variável temporária que você chamou de get porque, além de ser um verbo, que costuma ser usado para indicar funções, em vez de variáveis, ainda é um nome de uso muito comum, inclusive na própria biblioteca padrão do C++. Eu entendo que a atribuição de nomes às vezes é meio complicada de fazer, e que não existe regra universal que seja perfeita, mas eu entendo que uma boa escolha de nomes ajuda inclusive no entendimento do programa.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


5. Re: Erro ao converter string para inteiro

César
dark777

(usa Debian)

Enviado em 18/04/2024 - 11:53h

paulo1205 escreveu:

dark777 escreveu:

originalmente a saida dos dados estava no seguinte formato:
"12345" "00/00/00" "01" "02" "03" "04" "05" "06" 


Com esse formato, eu entendo que não dá nem para dizer que é um CSV, pois não tem vírgulas separando os valores, somente espaços, e os valores de cada célula estão entre aspas.

Se o formato vai ser seguramente sempre esse em todas as linhas, eu acho que a forma mais enxuta e segura de pegar as partes que lhe interessam é ler a linha inteira, e submeter a linha linha a uma chamada a sscanf(), pegando as partes que lhe interessarem, mais ou menos da seguinte maneira.
struct data_record {
unsigned id_number;
int cols[6];
};

[[nodiscard]] std::vector<data_record> read_file_data(const std::string &filename){
std::vector<data_record> result;
std::ifstream is;
is.exceptions(std::ios::badbit);
is.open(filename);
std::string line;
unsigned lineno=0;
while(getline(is, line)){
++lineno;
data_record r;
int used_chars=0;
int rc=sscanf(line.c_str(), R"("%u" "%*u/%*u/%*u" "%d" "%d" "%d" "%d" "%d" "%d" %n)", &r.id_number, &r.cols[0], &r.cols[1], &r.cols[2], &r.cols[3], &r.cols[4], &r.cols[5], &used_chars);
if(rc==7 && static_cast<size_t>(used_chars)==line.length())
result.emplace_back(std::move(r));
else
std::cerr << "Invalid line in file " << filename << ", line number " << lineno << ".\n";
}
return result;
}


Em tempo: no exemplo acima, eu mudei o nome de o tipo de dados, de um de um dos seus campos, da função que faz a leitura e da variável intermediária que armazena os campos da linha lida, porque os nomes que você usou no seu programa original não estavam refletindo muito bem o propósito de cada um desses símbolos. Entre eles, para mim o pior era a variável temporária que você chamou de get porque, além de ser um verbo, que costuma ser usado para indicar funções, em vez de variáveis, ainda é um nome de uso muito comum, inclusive na própria biblioteca padrão do C++. Eu entendo que a atribuição de nomes às vezes é meio complicada de fazer, e que não existe regra universal que seja perfeita, mas eu entendo que uma boa escolha de nomes ajuda inclusive no entendimento do programa.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


Estive ocupado por estes dias e me baseei na sua resposta para fazer as modificações no meu codigo mas nao entendi bem o funcionamento desta linha:

int rc=sscanf(line.c_str(), R"("%u" "%*u/%*u/%*u" "%d" "%d" "%d" "%d" "%d" "%d" %n)", &r.id_number, &r.cols[0], &r.cols[1], &r.cols[2], &r.cols[3], &r.cols[4], &r.cols[5], &used_chars);

O que seria o que nesta linha?
`%u` entendo que é unsigned int mas `%d` e `%n` nao entendi bem.

E que diferença tem um vetor de inteiros do tipo?

std::vector<int>cols;
int cols[6];


eu fiz a conversão do arquivo original em outra site e ele converteu os dados de maneira melhor, porem no programa original meu objetivo é descartar a primeira e segunda linha, ler a primeira coluna, pular a segunda coluna e ler da terceira coluna em diante os dados do novo arquivo convertido ficaram assim:

"Todos os resultados da Mega Sena — Loteria da Caixa","","","","","","","","",""
"Conc.","Data","1","2","3","4","5","6","Gan.","Prêmio"
"2669","16/12/2023","04","07","16","35","46","54","0",""
"2668","14/12/2023","01","27","30","41","46","57","0",""
"2667","12/12/2023","01","04","08","21","46","51","0",""
"2666","09/12/2023","05","25","29","30","43","47","1","30,781,665.32"
"2665","07/12/2023","03","14","21","22","37","39","0",""
"2664","05/12/2023","12","15","17","30","40","52","0",""
"2663","02/12/2023","07","11","27","41","56","59","0",""
"2662","30/11/2023","17","20","31","34","40","42","1","35,852,142.15"
"2661","28/11/2023","06","30","35","38","41","56","0",""
"2660","25/11/2023","06","12","13","20","38","60","0",""
"2659","23/11/2023","11","36","46","53","55","60","0",""

wiki.anon


6. Re: Erro ao converter string para inteiro

Paulo
paulo1205

(usa Ubuntu)

Enviado em 21/04/2024 - 23:43h

dark777 escreveu:

Estive ocupado por estes dias e me baseei na sua resposta para fazer as modificações no meu codigo mas nao entendi bem o funcionamento desta linha:
int rc=sscanf(line.c_str(), R"("%u" "%*u/%*u/%*u" "%d" "%d" "%d" "%d" "%d" "%d" %n)", &r.id_number, &r.cols[0], &r.cols[1], &r.cols[2], &r.cols[3], &r.cols[4], &r.cols[5], &used_chars); 

O que sesia o que nesta linha?
`%u` entendo que é unsigned int mas `%d` e `%n` nao entendi bem.


"%d" é para converter para int, mas difere de "%i" por o primeiro só trabalha com números na base 10 (decimal), ao passo que o segundo aceita números números em base 8 (octal), se o primeiro dígito for 0, ou 16 (hexadecimal), se começar com o prefixo 0x. Além disso, eu usei "%d", em lugar de "%u", porque, pelo seu exemplo, eu não sabia se os números poderiam ser negativos ou não. Se não puderem, você pode trocar tudo por "%u" e o tipo para unsigned.

O "%n" é uma forma de medir a quantidade de caracteres consumidos, e eu a usei para testar se todos os caracteres da linha tinham sido consumidos.

(Se é que eu não cometi nenhum bug... Eu não testei o código; escrevi diretamente na página do VoL.)

E que diferença tem um vetor de inteiros do tipo?
std::vector<int>cols;
int cols[6];


Um array tradicional do C++, herdado do C, é um agregado de elementos de um mesmo tipo e que reside num bloco contíguo de memória. O tamanho de um array tradicional é fixo, e deve ser conhecido no momento da compilação, a fim de que o compilador possa emitir o código que vai alocar tal bloco de tamanho já conhecido na memória, o que normalmente acontece em memória estática (fixo ao longo de toda a execução do programa) ou automática (geralmente na pilha do processador, a cada vez que a função ou bloco é executado, mas sempre com um tamanho fixo). A grande vantagem de arrays de tamanho fixo é sua simplicidade e velocidade, ao custo de pouca flexibilidade para acomodar situações em que a quantidade de elementos não seja conhecida de antemão, obrigando o programador que precise usar um array tradicional a chutar limites que podem vir a ser ou muito grandes, levando a desperdício de memória, ou muito pequenos, limitando a aplicabilidade do programa.

std::vector é um template de classe para um container de dados com alocação dinâmica de múltiplos elementos em um bloco contíguo de memória, permitindo inclusive operações de realocação de memória de forma relativamente “limpa” e sucinta para o usuário da classe. Isso torna algo como, segundo o seu exemplo, std::vecotr<int> interessante em aplicações em que a quantidade de elementos não seja conhecida com precisão a priori. Assim como um array tradicional, a alocação em bloco contíguo de memória permite um desempenho rápido (incluindo aspectos tais como bom aproveitamento de caches de memória). O custo dessa flexibilidade, no entanto, é que as operações de realocação podem vir a ser computacionalmente caras, proporcionais à quantidade de elementos já presentes no vetor, e pode ser cara em memória também (por exemplo: caso se precise realocar um vetor de 1M elementos para acrescentar apenas mais um elemento, é possível que a implementação interna desse vetor tenha de, pelo menos durante um período de tempo, alocar internamente um segundo vetor de 1M+1 elementos (totalizando 2M+1 elementos ocupados em memória), e então copiar todos os elementos do vetor original para o novo vetor, e só então poder apontar internamento para o novo vetor (liberando finalmente o antigo), antes de poder inserir o novo elemento que provocou a realocação). Por esse motivo, é frequente que, mesmo com a flexibilidade oferecida pela realocação, usuários de std::vector utilizem a operação de reserva de espaço no vetor antes de começar a preenchê-lo com dados, e também que, ao perceber que há uma realocação iminente, uma nova reserva de um bloco suficientemente grande seja providenciada antecipadamente, a fim de evitar várias realocações sucessivas, cada uma delas provocada pela inserção de um elemento de cada vez.

eu fiz a conversão do arquivo original em outra site e ele converteu os dados de maneira melhor, porem no programa original meu objetivo é descartar a primeira e segunda linha, ler a primeira coluna, pular a segunda coluna e ler da terceira coluna em diante os dados do novo arquivo convertido ficaram assim:
"Todos os resultados da Mega Sena — Loteria da Caixa","","","","","","","","",""
"Conc.","Data","1","2","3","4","5","6","Gan.","Prêmio"
"2669","16/12/2023","04","07","16","35","46","54","0",""
"2668","14/12/2023","01","27","30","41","46","57","0",""
"2667","12/12/2023","01","04","08","21","46","51","0",""
"2666","09/12/2023","05","25","29","30","43","47","1","30,781,665.32"
"2665","07/12/2023","03","14","21","22","37","39","0",""
"2664","05/12/2023","12","15","17","30","40","52","0",""
"2663","02/12/2023","07","11","27","41","56","59","0",""
"2662","30/11/2023","17","20","31","34","40","42","1","35,852,142.15"
"2661","28/11/2023","06","30","35","38","41","56","0",""
"2660","25/11/2023","06","12","13","20","38","60","0",""
"2659","23/11/2023","11","36","46","53","55","60","0",""


No código que eu usei como exemplo eu não mostrei o descarte das duas primeiras linhas porque é algo fácil de fazer, se você tiver certeza de sempre haverá essas duas linhas para descartar. Mas, se você reparar bem, o meu código descarta, sim, as linhas que não contenham dados numéricos, e inclusive faz com que sejam impressas mensagens avisando desse descarte. Você poderia simplesmente se desfazer da impressão do alerta, e assim descartar silenciosamente não apenas as duas primeiras linhas, mas qualquer outra linha que aparecesse como ruído ao longo do arquivo.

Mas o meu código também faz o descarte da segunda coluna, pois ele lê uma data entre aspas com três valores numéricos inteiros e sem sinal separados por barras. No entanto, esses valores numéricos são lidos, porém não são atribuídos a nenhuma variável, graças à presença do asterisco como modificador da conversão "%u" de sscanf() (ou seja, aquele pedaço que traz “"%*u/%*u/%*u"”). Uma verificação de integridade que não implica alocar nenhuma variável adicional.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


7. Re: Erro ao converter string para inteiro[RESOLVIDO]

César
dark777

(usa Debian)

Enviado em 24/04/2024 - 15:26h


paulo1205 escreveu:

dark777 escreveu:

Estive ocupado por estes dias e me baseei na sua resposta para fazer as modificações no meu codigo mas nao entendi bem o funcionamento desta linha:
int rc=sscanf(line.c_str(), R"("%u" "%*u/%*u/%*u" "%d" "%d" "%d" "%d" "%d" "%d" %n)", &r.id_number, &r.cols[0], &r.cols[1], &r.cols[2], &r.cols[3], &r.cols[4], &r.cols[5], &used_chars); 

O que sesia o que nesta linha?
`%u` entendo que é unsigned int mas `%d` e `%n` nao entendi bem.


"%d" é para converter para int, mas difere de "%i" por o primeiro só trabalha com números na base 10 (decimal), ao passo que o segundo aceita números números em base 8 (octal), se o primeiro dígito for 0, ou 16 (hexadecimal), se começar com o prefixo 0x. Além disso, eu usei "%d", em lugar de "%u", porque, pelo seu exemplo, eu não sabia se os números poderiam ser negativos ou não. Se não puderem, você pode trocar tudo por "%u" e o tipo para unsigned.

O "%n" é uma forma de medir a quantidade de caracteres consumidos, e eu a usei para testar se todos os caracteres da linha tinham sido consumidos.

(Se é que eu não cometi nenhum bug... Eu não testei o código; escrevi diretamente na página do VoL.)

E que diferença tem um vetor de inteiros do tipo?
std::vector<int>cols;
int cols[6];


Um array tradicional do C++, herdado do C, é um agregado de elementos de um mesmo tipo e que reside num bloco contíguo de memória. O tamanho de um array tradicional é fixo, e deve ser conhecido no momento da compilação, a fim de que o compilador possa emitir o código que vai alocar tal bloco de tamanho já conhecido na memória, o que normalmente acontece em memória estática (fixo ao longo de toda a execução do programa) ou automática (geralmente na pilha do processador, a cada vez que a função ou bloco é executado, mas sempre com um tamanho fixo). A grande vantagem de arrays de tamanho fixo é sua simplicidade e velocidade, ao custo de pouca flexibilidade para acomodar situações em que a quantidade de elementos não seja conhecida de antemão, obrigando o programador que precise usar um array tradicional a chutar limites que podem vir a ser ou muito grandes, levando a desperdício de memória, ou muito pequenos, limitando a aplicabilidade do programa.

std::vector é um template de classe para um container de dados com alocação dinâmica de múltiplos elementos em um bloco contíguo de memória, permitindo inclusive operações de realocação de memória de forma relativamente “limpa” e sucinta para o usuário da classe. Isso torna algo como, segundo o seu exemplo, std::vecotr<int> interessante em aplicações em que a quantidade de elementos não seja conhecida com precisão a priori. Assim como um array tradicional, a alocação em bloco contíguo de memória permite um desempenho rápido (incluindo aspectos tais como bom aproveitamento de caches de memória). O custo dessa flexibilidade, no entanto, é que as operações de realocação podem vir a ser computacionalmente caras, proporcionais à quantidade de elementos já presentes no vetor, e pode ser cara em memória também (por exemplo: caso se precise realocar um vetor de 1M elementos para acrescentar apenas mais um elemento, é possível que a implementação interna desse vetor tenha de, pelo menos durante um período de tempo, alocar internamente um segundo vetor de 1M+1 elementos (totalizando 2M+1 elementos ocupados em memória), e então copiar todos os elementos do vetor original para o novo vetor, e só então poder apontar internamento para o novo vetor (liberando finalmente o antigo), antes de poder inserir o novo elemento que provocou a realocação). Por esse motivo, é frequente que, mesmo com a flexibilidade oferecida pela realocação, usuários de std::vector utilizem a operação de reserva de espaço no vetor antes de começar a preenchê-lo com dados, e também que, ao perceber que há uma realocação iminente, uma nova reserva de um bloco suficientemente grande seja providenciada antecipadamente, a fim de evitar várias realocações sucessivas, cada uma delas provocada pela inserção de um elemento de cada vez.

eu fiz a conversão do arquivo original em outra site e ele converteu os dados de maneira melhor, porem no programa original meu objetivo é descartar a primeira e segunda linha, ler a primeira coluna, pular a segunda coluna e ler da terceira coluna em diante os dados do novo arquivo convertido ficaram assim:
"Todos os resultados da Mega Sena — Loteria da Caixa","","","","","","","","",""
"Conc.","Data","1","2","3","4","5","6","Gan.","Prêmio"
"2669","16/12/2023","04","07","16","35","46","54","0",""
"2668","14/12/2023","01","27","30","41","46","57","0",""
"2667","12/12/2023","01","04","08","21","46","51","0",""
"2666","09/12/2023","05","25","29","30","43","47","1","30,781,665.32"
"2665","07/12/2023","03","14","21","22","37","39","0",""
"2664","05/12/2023","12","15","17","30","40","52","0",""
"2663","02/12/2023","07","11","27","41","56","59","0",""
"2662","30/11/2023","17","20","31","34","40","42","1","35,852,142.15"
"2661","28/11/2023","06","30","35","38","41","56","0",""
"2660","25/11/2023","06","12","13","20","38","60","0",""
"2659","23/11/2023","11","36","46","53","55","60","0",""


No código que eu usei como exemplo eu não mostrei o descarte das duas primeiras linhas porque é algo fácil de fazer, se você tiver certeza de sempre haverá essas duas linhas para descartar. Mas, se você reparar bem, o meu código descarta, sim, as linhas que não contenham dados numéricos, e inclusive faz com que sejam impressas mensagens avisando desse descarte. Você poderia simplesmente se desfazer da impressão do alerta, e assim descartar silenciosamente não apenas as duas primeiras linhas, mas qualquer outra linha que aparecesse como ruído ao longo do arquivo.

Mas o meu código também faz o descarte da segunda coluna, pois ele lê uma data entre aspas com três valores numéricos inteiros e sem sinal separados por barras. No entanto, esses valores numéricos são lidos, porém não são atribuídos a nenhuma variável, graças à presença do asterisco como modificador da conversão "%u" de sscanf() (ou seja, aquele pedaço que traz “"%*u/%*u/%*u"”). Uma verificação de integridade que não implica alocar nenhuma variável adicional.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)



no arquivo csv baixado sempre haverá as linhas a serem descarnatas no cabeçalho, consegui resolver o problema de conversão para inteiros de outa maneira criando uma função generica para isso porem o codigo em si funcionou bem após isso mas uma coisa me intriga, eu criei um objeto da classe "ReadData obj" fora do loop while na função getDetails, e ao chamar o objeto dentro do loop while ele simplemente nao aceira converter e adicionar os dados no objeto "obj" ele mostra o erro:

terminate called after throwing an instance of 'std::invalid_argument'
what(): invalid conversion!
Aborted (core dumped)

Apenas se o objeto da classe "ReadData obj" estiver dentro do loop while funciona normalmente sem retornar este erro de "invalid conversion" se vc ou alguem que entende mais sobre a logica e melhor clareza na escrita do codigo em c++ em si puder me orientar para tal agradeço o codigo "consertado parcialmente" é este abaixo queria entender por que ele faz isso se o objeto for declarado fora do loop while e o que poderia ser feito para resolver isso.

#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <algorithm>


// Estrutura para leitura dos dados de um arquivo csv
struct ReadData
{
int contests;

std::string lines;

std::vector<int> drawn;

std::vector<std::string> cols;

std::vector<std::string> split(const std::string& str, char delimiter)
{
std::string token;

std::istringstream iss(str);

while (std::getline(iss, token, delimiter))
{
// Remove espaços em branco e aspas
token.erase(std::remove(token.begin(), token.end(), ' '), token.end());
token.erase(std::remove(token.begin(), token.end(), '\"'), token.end());

if (!token.empty()) cols.push_back(token);
}

return cols;
}

//Função para converter os dados para um tipo específico desejado.
template <typename T>
inline T strToNum(const std::string& str)
{
T result;

std::istringstream iss(str);

if (!(iss >> result))
{
throw std::invalid_argument("invalid conversion!");
}

return result;
}

// Sobrecarga da função para aceitar um objeto ReadData
template<typename T>
inline T strToNum(const ReadData& obj)
{
return strToNum<T>(obj.lines);
}

std::vector<ReadData> getDetails(const std::string&);

void printDetails(const std::vector<ReadData>&);
};

// Função para ler os dados do arquivo CSV
std::vector<ReadData> ReadData::getDetails(const std::string &filename)
{
ReadData lr;

//Objeto declarado fora do loop while retorna invalid conversion?
ReadData rd;

std::vector<ReadData> details;

std::ifstream csvfile(filename);

if (!csvfile.is_open())
{
std::cerr << "Erro ao abrir o arquivo " << filename << std::endl;

return details;
}

// Descarta a primeira linha (cabeçalho)
std::getline(csvfile, lr.lines);

while (std::getline(csvfile, lr.lines))
{
//descomenta o objeto dentro do loop a convesão nao fica invalida.
//ReadData rd;

rd.cols = rd.split(lr.lines, ',');

std::istringstream iss(rd.cols[0]);

// Ignora a segunda linha (cabeçalho)
if (lr.lines.find("Conc.") != std::string::npos || lr.lines.find("1 2 3 4 5 6 Gan.") != std::string::npos) continue;

//Lê o número do concurso
iss >> lr.lines;

//Armazena o numero do concurso
rd.contests = rd.strToNum<int>(lr.lines);

// Ler os números sorteados
for (size_t i = 2; i < 9; ++i)
{
//se nenhum caractere diferente de numeros for encontrado
if (rd.cols[i].find_first_not_of("0123456789") == std::string::npos)
{
// Converte string para int e adiciona ao vetor
rd.drawn.push_back(std::stoi(rd.cols[i]));
}
}

details.push_back(rd);
}

return details;
}

// Função para exibir os dados
void ReadData::printDetails(const std::vector<ReadData>& dados)
{
for (const auto &get : dados)
{
std::cout << "Concurso: " << get.contests << std::endl;

std::cout << "Números: ";
for (int num : get.drawn) std::cout << num << " ";

std::cout << "\n\n";
}
}

int main()
{
ReadData objRead;

std::vector<ReadData> dados;

dados = objRead.getDetails("historico_megasena.csv");

objRead.printDetails(dados);

return 0;
}

wiki.anon






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts