Je vois quelque chose que je ne comprends pas.
319528800,string1 319528801,string2 319528801,string3 319528802,string4
Le testfile
dans le répertoire actuel a le format.
#include <iostream> #include <fstream> #include <string> int main() { std::ifstream someStream; someStream.open("testfile"); std::string current_line; if ( someStream.good() ) { while (std::getline(someStream, current_line)) { std::cout << current_line << "\n"; std::cout << std::string(std::begin(current_line), std::begin(current_line) + sizeof(long)); std::cout << "\n"; } } return 0; }
4 Réponses :
Voici un code qui recherche une virgule dans la ligne courante
while (std::getline(someStream, current_line)) { std::cout << current_line << "\n"; // get position of comma size_t pos = current_line.find(','); // get string before comma std::string tmp = current_line.substr(0, pos); // convert to long long num = stol(tmp);
Notez que ce code suppose qu'il y a une virgule dans l'entrée, il plantera probablement s'il n'y en a pas. Vous devriez toujours vérifier vos données d'entrée.
std :: stol (current_line)
fonctionne très bien; il arrête l'analyse lorsqu'il atteint un caractère qui ne peut pas faire partie d'un entier, il n'est donc pas nécessaire d'extraire cette sous-chaîne.
Vous compliquez excessivement l'analyse. Pour analyser une entrée du flux, vous pouvez faire quelque chose du genre
#include <fstream> #include <iostream> #include <string> int main() { std::ifstream someStream("testfile"); char sep; unsigned long num; std::string current_line; while (someStream >> num >> sep >> current_line) { if (sep != ',') break; // Bad separator std::cout << num << ", " << current_line << "\n"; } return 0; }
@john True, la norme ne spécifie pas la taille des types intégraux, seulement les plages. Je pense que "le plus souvent" suffirait.
semble raisonnable
std :: stoi (current_line)
fonctionne très bien; il arrête l'analyse lorsqu'il atteint un caractère qui ne peut pas faire partie d'un entier, il n'est donc pas nécessaire d'extraire cette sous-chaîne.
std :: stoi
devrait probablement être std :: stol
, car il y a une implication que le code est censé créer un long
.
@PeteBecker Merci, j'ai pensé que cela lancerait std :: invalid_argument
. J'ai dû le chercher.
Re: «a dû chercher» - transformez cela en habitude.
Tout ce dont vous avez besoin est:
long value = std::stol(current_line);
std :: stol
ignore les espaces de début, puis analyse le texte restant sous forme de valeur entière. Il s'arrête lorsqu'il touche un caractère qui ne peut pas faire partie d'un entier. Donc, il s'arrêtera quand il atteindra ce ,
.
Préfère créer une structure qui représente chaque ligne
struct input_line { long number; std::string str; operator std::pair<long, std::string>() const & { return {number, str}; } operator std::pair<long, std::string>&&() && { return {number, std::move(str)}; } }; std::istream& operator>>(std::istream& in, input_line& line) { char comma; if (in >> line.number >> comma >> line.str) { if (number < 0) throw std::runtime_error("invalid number "); if (comma != ',') throw std::runtime_error("missing comma"); if (str.empty()) throw std::runtime_error("missing string"); } } int main() { std::ifstream someStream("testfile"); std::istream_iterator<input_line> first(someStream); std::map<long, std::string> map(first, {}); for(auto&& pair : map) std::cout << pair.first << ',' << pair.second << '\n'; }
Et puis la lecture devient triviale:
int main() { std::ifstream someStream("testfile"); input_line line; while(someStream >> line) std::cout << line.number << ',' << line.str << '\n'; }
en partant de cette idée, nous peut en fait utiliser istream_iterator
pour lire directement du fichier dans la carte.
struct input_line { long number; std::string str; }; std::istream& operator>>(std::istream& in, input_line& line) { char comma; if (in >> line.number >> comma >> line.str) { if (number < 0) throw std::runtime_error("invalid number "); if (comma != ',') throw std::runtime_error("missing comma"); if (str.empty()) throw std::runtime_error("missing string"); } }
sizeof
est la taille en mémoire d'un type. Ce n'est pas le nombre de caractères nécessaires pour représenter un nombre.Pourquoi pensez-vous que
sizeof (long)
va trouver la virgule? C'est une pensée magique, si vous pensez vraiment que cela fonctionnera. FYIsizeof (long)
est une valeur fixe, généralement 4 ou 8.Cela ne répond pas à la question, mais prenez l'habitude d'initialiser les objets avec des valeurs significatives plutôt que de les initialiser par défaut et d'écraser immédiatement les valeurs par défaut. Dans ce cas, cela signifie changer
std :: ifstream someStream; someStream.open ("testfile");
àstd :: ifstream someStream ("testfile");
. De plus,if (someStream.good ()
est doublement redondant. Les objets de flux ont une conversion implicite enbool
, doncif (someStream)
est tout c'est nécessaire. Et même cela n'est pas nécessaire; si le flux n'est pas dans un bon état, l'appel àgetline
échouera et vous n'obtiendrez aucune sortie.Il n'y a aucune référence à une virgule dans le code, c'est donc important