Lesen Sie ganze Zahlen aus einer Textdatei mit C++ ifstream

Lesezeit: 2 Minuten

Benutzer-Avatar
esneuling

Ich möchte Graph-Adjazenzinformationen aus einer Textdatei lesen und in einem Vektor speichern.

  • Die Datei hat eine beliebige Anzahl von Zeilen

  • Jede Zeile hat eine beliebige Anzahl von Ganzzahlen, die mit ‘\n’ enden

zum Beispiel,

First line:
0 1 4
Second line:
1 0 4 3 2
Thrid line:
2 1 3
Fourth line:
3 1 2 4
Fifth line:
4 0 1 3

Wenn ich getline() verwende, um jeweils eine Zeile zu lesen, wie kann ich die Zeile analysieren (da jede Zeile eine variable Anzahl von Ganzzahlen hat)?

Irgendwelche Vorschläge?

  • Sie könnten auf folgendes verweisen: stackoverflow.com/questions/236129/how-to-split-a-string-in-c

    – Ryan Li

    14. November 2011 um 3:00 Uhr

Benutzer-Avatar
Kerrek SB

Die Standardzeilen-Lesesprache:

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


std::ifstream infile("thefile.txt");
std::string line;

while (std::getline(infile, line))
{
  std::istringstream iss(line);
  int n;
  std::vector<int> v;

  while (iss >> n)
  {
    v.push_back(n);
  }

  // do something useful with v
}

Hier ist eine einzeilige Version mit a for Schleife. Wir brauchen eine Hilfskonstruktion (Dank an @Luc Danton!), die das Gegenteil von tut std::move:

namespace std
{
  template <typename T> T & stay(T && t) { return t; }
}

int main()
{
  std::vector<std::vector<int>> vv;

  for (std::string line;
       std::getline(std::cin, line);
       vv.push_back(std::vector<int>(std::istream_iterator<int>(std::stay(std::istringstream(line))),
                                     std::istream_iterator<int>())
                    )
       ) { }

  std::cout << vv << std::endl;
}

  • Das bedeutet, dass dies die C ++ 11-Funktion verwendet, wie && ist nur in C++11 verfügbar.

    – Nawaz

    14. November 2011 um 3:37 Uhr

  • @Nawaz: Meine frühere Version beinhaltet eine ausgefeiltere Struktur und einen Const-Cast, der C++ 98 ist. Sprich mich privat an, wenn du interessiert bist, es ist nicht für höfliche Gespräche geeignet 🙂

    – Kerrek SB

    14. November 2011 um 3:38 Uhr

  • @Kerrek, danke für deine Lösung. Wenn ich einen verschachtelten STL-Container habe, sagen wir, vector >, wie iteriere ich ihn? Ich habe folgendes versucht: std::vector > iter1; std::vector::iterator iter2; for (iter1 = vv.begin(); iter1 != vv.end(); ++iter1) { for (iter2 = (*vv).begin(); iter2 != (*vv).end(); + +iter2) cout << *iter2 << " "; cout << endl; } Es kompiliert nicht. Was ist der richtige Weg, um einen verschachtelten STL-Container zu durchlaufen? Vielen Dank.

    – esneuling

    15. November 2011 um 3:35 Uhr


  • @itnovice: Es ist so etwas. for (std::vector<std::vector<int>>::const_iterator it1 = v.begin(), end1 = v.end(); it1 != end1; ++it1) { for ( std::vector<int>::const_iterator it2 = it1->begin(), end2 = it1->end(); it2 != end2; ++it2) { ... } } etc.

    – Kerrek SB

    15. November 2011 um 3:38 Uhr

  • std::stay„Seit wann darf man Namen hinzufügen std?

    – Neugieriger

    29. November 2011 um 3:54 Uhr

Benutzer-Avatar
Nawaz

Lesen Sie zuerst eine Zeile mit std::getline Funktion, dann verwenden std::stringstream um die ganzen Zahlen aus der Zeile zu lesen als:

std::ifstream file("input.txt");

std::vector<std::vector<int>> vv;
std::string line;
while(std::getline(file, line))
{
    std::stringstream ss(line);
    int i;
    std::vector<int> v;
    while( ss >> i ) 
       v.push_back(i);
    vv.push_back(v);
}

Sie können den Loop-Body auch schreiben als:

while(std::getline(file, line))
{
    std::stringstream ss(line);
    std::istream_iterator<int> begin(ss), end;
    std::vector<int> v(begin, end);
    vv.push_back(v);
}

Das sieht kürzer und besser aus. Oder führen Sie die letzten beiden Zeilen zusammen:

while(std::getline(file, line))
{
    std::stringstream ss(line);
    std::istream_iterator<int> begin(ss), end;
    vv.push_back(std::vector<int>(begin, end));
}

Machen Sie es jetzt nicht kürzer, da es hässlich aussehen würde.

  • Oder auch for (std::string line; std::getline(file, line); vv.push_back(std::vector<int>(std::istream_iterator<int>(std::istringstream(line)), std::istream_iterator<int>()))) {}

    – Kerrek SB

    14. November 2011 um 3:08 Uhr

  • @KerrekSB: Hehe. Gut. Ich mag die Idee, den Umfang von zu minimieren line Variable.

    – Nawaz

    14. November 2011 um 3:11 Uhr


  • Teste es nur, aber es kann sein, dass du den Iterator nicht aus einem temporären String-Stream bekommen kannst 🙁

    – Kerrek SB

    14. November 2011 um 3:12 Uhr

  • @Nawaz: beeindruckend – nein, ich bin mir nicht sicher, ob ich es verstehe. Warum ist der Rückgabewert kein Rvalue mehr? Kann dasselbe einfacher mit einer Funktion erreicht werden, die eine Referenz auf ihr Argument zurückgibt?

    – Kerrek SB

    15. November 2011 um 9:37 Uhr

  • Es sollte also ein Mixin-Template geben can_use_as_temporary<T>von denen Sie ableiten und die exponiert sind T & lvalue() { return *this; }!

    – Kerrek SB

    15. November 2011 um 10:21 Uhr

1013160cookie-checkLesen Sie ganze Zahlen aus einer Textdatei mit C++ ifstream

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy