• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

C++ czytanie danych z pliku

Object Storage Arubacloud
0 głosów
524 wizyt
pytanie zadane 11 kwietnia 2019 w C i C++ przez Lisu Początkujący (270 p.)

Witam,
Wiem jak czytać i zapisywać dane do plików, lecz problem pojawia się przy większej złożoności zadania.

W pliku mam dane w postaci:

Kolo [(0,0)-(4,4)]

Kolo [(0,0)-(3,3)]

Trojkat [(0,0)-(8,8)] [(8,8)-(3,3)] [(3,3)-(0,0)] 

Kolo [(0,0)-(2,2)]

Kolo [(0,0)-(1,1)]

Kolo [(0,0)-(0,0)]

Czy jest jakiś prosty sposób w C++, żeby dostać się do liczb np. w linijce z Trójkątem chciałbym otrzymać Napis oraz 3 tablice dwuelementowe wskazujące na punkt.

Czy istnieje może jakiś obiekt, który by działaj jak stringstream, ale żeby czytać z niego danie np dla koła:
 

int x, y, w, q;

obj >> Nazwa_Figury >> " " >> "[(" >> x >> "," >> y >> ")-(" >> w >> "," << q ")]";

 

2 odpowiedzi

+2 głosów
odpowiedź 11 kwietnia 2019 przez Bondrusiek Maniak (61,370 p.)

Wydaje mi się że najlepszym sposobem byłoby czytanie pojedynczych lini z pliku a następnie parsowanie danych

#include <sstream>
#include <string>

std::string line;
while (std::getline(infile, line))
{
//obróbka zmiennej line
}

 

komentarz 11 kwietnia 2019 przez Teslum_369 Gaduła (4,190 p.)
Też tak uważam
+1 głos
odpowiedź 11 kwietnia 2019 przez mokrowski Mędrzec (155,460 p.)

Cel prosty. Masz zrozumieć więc jest to "boleśnie linearne".

Uprzedzam, po zmianie formatu danych, kod jest "bardzo kruchy".

#include <iostream>
#include <sstream>
#include <string>

struct Point {
    int x;
    int y;
};

struct Segment {
    Point startPoint;
    Point endPoint;
};

Point pointParse(const std::string& str) {
    std::string msg{str.cbegin() + 1, str.cend() - 1};
    std::stringstream ss;
    ss.str(msg);
    char comma;
    int x;
    int y;
    ss >> x >> comma >> y;
    return Point{x, y};
}

Segment segmentParse(const std::string& str) {
    std::string msg{str.cbegin() + 1, str.cend() - 1};
    std::stringstream ss;
    ss.str(msg);
    std::string msg1;
    std::string msg2;
    std::getline(ss, msg1, '-');
    std::getline(ss, msg2);
    return Segment{pointParse(msg1), pointParse(msg2)};
}

void showSegment(const Segment& seg) {
    std::cout << "Segment:\n"
      << "Start point:\tx = " << seg.startPoint.x << '\t'
      << "y = " << seg.startPoint.y << '\n'
      << "End point:\tx = " << seg.endPoint.x << '\t'
      << "y = " << seg.endPoint.y << '\n';
}

int main() {
    std::string record = "Trojkat [(0,0)-(8,8)] [(8,8)-(3,3)] [(3,3)-(0,0)]";
    std::string objName;
    std::string segment1;
    std::string segment2;
    std::string segment3;
    std::stringstream ss;
    ss.str(record);
    ss >> objName >> segment1 >> segment2 >> segment3;
    Segment sg1 = segmentParse(segment1);
    showSegment(sg1);
}

Innym rozwiązaniem była by gramatyka regularna... ale to bardziej skomplikowane.

komentarz 11 kwietnia 2019 przez j23 Mędrzec (194,920 p.)
edycja 11 kwietnia 2019 przez j23

Dodajmy zatem regexy:

struct Point {
    int x;
    int y;
};

struct Segment {
    Point startPoint;
    Point endPoint;
};

struct Object {
	std::string name;
	std::vector<Segment> segments;
};

template<typename Iter>
int toInt(Iter beg, Iter end)
{
	char tab[50];
	*std::copy(beg, end, tab) = 0;
	return atoi(tab);
}

Object parseObject(const std::string &line)
{
	static std::regex r(R"-(\[\(([+-]?\d+),([+-]?\d+)\)-\(([+-]?\d+),([+-]?\d+)\)\])-");
	std::smatch m;
	
	Object obj;
	
	auto it = line.cbegin();
	while(it != line.cend() && !isspace(*it)) ++it;
	obj.name.assign(line.cbegin(), it);
	
    while(regex_search(it, line.cend(), m, r))
    {
		obj.segments.push_back(Segment{{ toInt(m[1].first, m[1].second), toInt(m[2].first, m[2].second) }, 
									   { toInt(m[3].first, m[3].second), toInt(m[4].first, m[4].second) }});
		
		it = m.suffix().first;
    }

	return obj;
}
    std::string s = "Trojkat [(0,0)-(8,8)] [(8,8)-(3,3)] [(3,3)-(0,0)]";
    
	auto o = parseObject(s);

	std::cout << o.name << '\n';
	for(auto &s : o.segments)
	{
		std::cout << s.startPoint.x << ' ' << s.startPoint.y << ' ';
		std::cout << s.endPoint.x << ' ' << s.endPoint.y << '\n';
	}

 

Podobne pytania

0 głosów
2 odpowiedzi 4,856 wizyt
pytanie zadane 9 maja 2016 w C i C++ przez Leonnn Nowicjusz (150 p.)
0 głosów
1 odpowiedź 918 wizyt
pytanie zadane 13 kwietnia 2019 w Python przez yteicosf Użytkownik (640 p.)
0 głosów
2 odpowiedzi 151 wizyt

92,579 zapytań

141,432 odpowiedzi

319,664 komentarzy

61,965 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...