[C++]fprintf czy ofstream?

0

Witam
Testowałem powyższe ale mam taki problem.

Plik składa się z danych wśród których są luki, jakby puste komórki. Problem z tym że nie ma znaku rozdzielającego kolumny, znaku końca wiersza też. Powyższe metody wczytują pierwszy napotkany tekst a to niestety robi mi błędy bo tablica źle się wypełnia, tam gdzie powinna być pusta komórka wrzuca coś co było kolumnę dalej.

Która z funkcji posiada takie możliwości żeby wczytywać tylko określoną liczbę znaków???
na dole podam przykład
Plik do wczytania

S tekst1 tekst2 liczba1 liczba2
S tekst1 tekst2         liczba2  <---- np. liczba2 do kolumny ---> liczba1, a do liczba2--->S
S tekst1 tekst2 liczba1 liczba2



Myślę że jasno wyjaśniłem mój problem, najlepiej gdybym mógł określić ile znaków ma wczytywać w każdym ruchu.
Z góry dzieki Wam za pomoc!

0

skoro tak,to ofstream

0

Tzn. mógłbyś podać jaką funkcję i z jakim parametrem
przyznam że częściej używałem fprintf

Czyli najpierw pobrać całą linię - getline a później?

0

spróbuj tak:

char buff[max];
char columnSizes[] = { 2, 7, 7, 7 };
const int n = sizeof(columnSizes) / sizeof(columnSizes[0]);

ifstream f( "plikdanych.txt" );
string linia;

while( getline( f, linia) )
    {
    stringstream s( linia );
    
    for( column = 0; column<n; ++column )
        if( s.getline( buff, columnSizes[ column ]+1 ) ) // +1 jest konieczne bo parametr liczy z zerem kończącym
              {
              stringstream s( buff );
              s >> jakasDana;
              }
    }

nie jestem przekonany co do wszystkich konstruktorów stringstream, ale filozofia powinna być zrozumiała.

0

char columnSizes[] = { 2, 7, 7, 7 };
Czy nie czasami integer?

Nie rozumiem tylko tej operacji, chodzi mi po co to dzielenie, bo wiem że ma wyjść liczba kolumn.
const int n = sizeof(columnSizes) / sizeof(columnSizes[0]);
Ideę chyba rozumiem... jeszcze analizuję.

0

Tak masz rację ma być int (błąd copy/paste :) ).
a to dzielnie to rozmiar tablicy w bajtach przez rozmiar elementu tablicy w bajtach. W ten sposób zawsze dobrze policzy liczbę elementów tablicy nawet jak potem zmienisz typ w tablicy.

0

if( s.getline( buff, columnSizes[ column ]+1 ) ) // +1 jest konieczne bo parametr liczy z zerem kończącym
Tutaj chyba samo get? Czyli if( s.get( buff, columnSizes[ column ]+1 ) )

Jak mógłbyś jeszcze wytłumaczyć co ma się zrobić w

{
      stringstream s( buff );
      s >> jakasDana;
}

Powiedzmy że wczytał mi taki wyraz godzina" 1212 " chciałbym teraz wyciągnąć z tego stringa każdą z danych, hhss czy takie działania są też dostępne na ofstream'ach? Chodzi też o opuszczenie niepotrzebnych spacji. Z góry wszystkim dzięki za pomoc!

Czy może lepiej skonwertować to na typ string i na nim działać?

0

tak, to sie da zrobic, ale na IFstreamie bo teraz mowisz o odczycie..

od pomijania spacji jest manipulator skipws
a wczytywanie poszczegolnych licz to zwyklym >> na int..

0

Miałem mały problem z funkcją skipws bo próbowałem ją użyć na zmiennej buff, czyli nie będącej strumieniem :)

Ale przy szukaniu tego zrozumiałem w końcu to o co pytałem wyżej.
Cały kod podam dla innych do nauki ;)

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;

int main () {

  char buff[90]; //zrzuca tutaj tylko jedna kolumne
  int columnSizes[] = { 10, 5, 5, 12,8,10,18 }; //podaje sie tu szerokosc kolumn w pliku
  const int n = sizeof(columnSizes) / sizeof(columnSizes[0]); // dodatek sam policzy ile ma elem. 
                                                              //licząc bajty; można też ręcznie podać
  ifstream plik( "dane.txt" ); 
  string linia;  // cala linia z pliku
  string ODCZYT; //"wyczyszczony" i oddzielony od innych znak
    while( getline( plik, linia) )
    { 
    stringstream s( linia );
    cout<<"\n";
    for( int column = 0; column<n; ++column )
        if( s.get( buff, columnSizes[ column ]+1 ) ) // +1 jest konieczne bo parametr liczy z zerem kończącym
              {
                stringstream s( buff );
                s >>skipws>>ODCZYT;
                cout<<ODCZYT<<" ";
              }
    }
  plik.close(); 
  system("PAUSE");
  return 1;
}

Co do tego fragmentu

{
              1)  stringstream s( buff );
              2)  s >>skipws>>ODCZYT;
                cout<<ODCZYT<<" ";
              }
  1. zmienna char buff[90] jest konwertowana na strumień o nazwie s
  2. dzięki temu możemy się nim posługiwać jak intuicyjnie "jak przy cin>>zmienna"
    czyli do zmiennej string (może też być char) ODCZYT zapisuje się już oczyszczony ze spacji (funkcja skipws) wyraz ze strumienia.

Do testów terzeba sobie stworzyć plik z taką szerokością kolumn jak w tabelce.

Co do odczytu 3 zmiennych jednoczesnie, np.

mamy odczyt 12:34:11 
int hh,mm,ss; 

Kiedyś było coś takiego, nie pamiętam nazwy funkcji 
nazwa_funkcji( "%d:%d:%d",hh,mm,ss);
Ale to jest metoda jeszcze z C
nie chciałbym do niej wracać bo teraz skupiam się na streamach i stringach
Czy jest jakiś odpowiednik o takiej funkcjonalności w stream'ach albo stringach?

Generalnie ważne są dwie rzeczy;

  1. Czy plik jest postaci hhss -> Jeśli Nie to błąd, "zła stuktura danych"
  2. Jeśli Tak pobierz zmienne hh, mm i ss;

Czyli chodzi o dbanie o prawidłową strukturę danych a dopiero później odczyt.
Jeśli odczytał by np. "aa1255" to mógłby zrobić coś takiego
hh='aa';
mm='12:';
ss='13'; czyli jakieś wartości liczbowe z tego będą ale przez to obliczenia wyjdą błędne.

0

Powiedzmy że wczytał mi taki wyraz godzina" 1212 " chciałbym teraz wyciągnąć z tego stringa każdą z danych

int hh,mm,ss;

if(sscanf(linia.c_str(),"%i:%i:%i",&hh,&mm,&ss)==3)
{
   //OK
}
0

Tak dokładnie o to mi chodziło, małe ale :) jaki jest odpowiednik tej funkcji w strumieniach albo stringach?
Nie chciałbym mieszać tych dwóch sposobów i co kawałek konwertować char na string i odwrotnie;

Niestety jest problem z typem stringstream s( buff ), ponieważ jeśli odczyt jest pusty to nie przypisuje on pod s nic i w rezultacie pozostaje w nim stara wartość, czyli zła. Jakby to zrobić inaczej?

0

Nie chciałbym mieszać tych dwóch sposobów i co kawałek konwertować char na string i odwrotnie;

Nie widzę problemu, ale masz:

stringstream s(...);

if(!(((s>>hh).ignore()>>mm).ignore()>>ss).fail())
{
	//OK
}	

Niestetety jest problem z typem stringstream s( buff ), ponieważ jeśli odczyt jest pusty to nie przypisuje on pod s nic i w rezultacie pozostaje w nim stara wartość, czyli zła.

if((s>>ODCZYT).fail())
{
	// lipa
}
0

Wielkie dzięki, nie domyśliłbym się że to problem jest przy czytaniu z streama, a przecież to oczywiste bo to tak jakbyśmy do cin wprowadzali same spacje ;))

Ale jakby spojrzeć na optymalność tej operacji to robimy coś takiego w tym programie.

  1. czytamy linię z pliku do -----> string
  2. rozdzielamy kolumnę do -----> char [90]
    3. Konwertujemy ją na strumień --> stringstream
    4. znowu konwertujemy z usunięciem spacji do-> char[90]

Wydaje się to nieoptymalne bo przecież wynik mamy już w p. 2 tylko wystarczyłoby usunąć z niego spacje.

Czy takie konwersje nie wpływają znacząco na czas wykonania prog. przy jakiejś b.dużej próbie danych?

funkcja skipws nie działa z char, a szkoda:(
W Symfonii znalazłem funkcję z biblioteki string "find_first_not_of" tyle że tutaj potrzebna jest kolejna konwersja na string.

Co radzicie? Chodzi mi o optymalność działania, wiem że są też rozwiązania proste, działać będzie na pewno - ale przecież nie o to nam chodzi żeby to "jakoś chodziło", jak się już uczyć to porządnie.

Chcę używać tylko nowych funkcji ponieważ kiedyś zawsze używałem starszych wersji print,fprintf,fscan itd. nie było oczywiście problemu ale one pochodzą właściwie ze starego już C, a ja przymierzam sie do przesiatki z DevC++ na Visuala, no i powoli z C++ na C#

0

Wydaje się to nieoptymalne bo przecież wynik mamy już w p. 2 tylko wystarczyłoby usunąć z niego spacje.

Możesz tak spróbować:

class memory_buf:public streambuf
{
public:
	streambuf::_Myt *setbuf(streambuf::char_type* ptr, streamsize size)
	{	
		setg(ptr, ptr, ptr+size);
		return (this);
	}

	str_buff(){};
};

//...........

memory_buf 	mbuf;
istream		is(&mbuf);

while(getline( plik, linia))
{
	size_t	offset = 0;
	
	for( int column = 0; column<n; ++column )
	{
		is.rdbuf()->setbuf(linia.c_str() + offset,columnSizes[column]); //<--- to jest dość naiwne, ale nie wnikam
		is.clear();
		offset += columnSizes[column];
		
		is >>skipws>>ODCZYT;
		cout<<ODCZYT<<"";
	}
}

strumień is operuje bezpośrednio na linia, nie ma kopiowania z linia do stringstreama i po każdym setbufie strumień ma rozmiar kolejnej kolumny.

0
0x666 napisał(a)

Możesz tak spróbować:
class memory_buf:public streambuf
{
public:
streambuf::_Myt setbuf(streambuf::char_type ptr, streamsize size)
{
setg(ptr, ptr, ptr+size);
return (this);
}

str_buff(){};
};

Jest problem przy kompilacji. Czy jeszcze trzeba dołączyć jakąś bibliotekę?
Pomysł rozumiem wydaje się bardzo dobry, ale może istnieje jakaś funkcja/metoda która czyści zmienne char z spacji?

Komunikaty:

expected before '*' token
expected `;' before "str_buff" 
ISO C++ forbids declaration of `str_buff' with no type  
0

Jest problem przy kompilacji.

Jest tam mały błąd, nazwa konstruktora różni się od nazwy klasy - zmień str_buff na memory_buf.

Pomysł rozumiem wydaje się bardzo dobry, ale może istnieje jakaś funkcja/metoda która czyści zmienne char z spacji?

Nie wiem czy jest bardzo dobry, ale na pewno eliminuje część niepotrzebnych (de)alokacji i kopiowań. Co do tej funkcji, to nie wiem, co ci ona da? Jak sobie poradzisz z konwersją tekst -> liczba? Co, znowu użyjesz stringstream, albo atoi/sscanf (rozwiązania z C nie interesują Ciebie przecież)?

0

Dziękuję za pomoc. Kiedyś już robiłem sobie takie funkcje konwertujące char na int - b. prosta oparta na if (... =='1') return 1; ale to chyba nie jest najlepsze rozwiązanie.
Jeśli nie uda mi się to innymi metodami to przeproszę funkcję z C ;-) //++ chodzi mi o konwersję char na int

Dlaczego unikam C ? Bo chcę przejść na Visuala i pisać w Frameworkach. Mam jakieś dziwne złudzenie że tam metody z C już się nie używa, a używa sie więcej z String i Stream'ów może się mylę, bo z tego co widzę tam są jeszcze inne funkcje, generalnie ciężko mi jakoś tam ruszyć, a mam ciekawy pomysł na program do mojej pracy, żeby ułatwić sobie życie. Nawet już go napisałem ale wiadomo jak to program konsolowy, więc ćwiczę Visuala i chcę zrobić przyzwoicie wyglądającą wersję Windowsową.

0

b. prosta oparta na if (... =='1') return 1; ale to chyba nie jest najlepsze rozwiązanie.

No raczej... :>

Jeśli nie uda mi się to innymi metodami to przeproszę funkcję z C

Przecież dostałeś opcje "strumieniową", nie rozumiem o co chodzi :|

1 użytkowników online, w tym zalogowanych: 0, gości: 1