Usuwanie pustych wierszy z pliku

0

Mam problem.
Otóż napisałem program, który według założenia ma usuwać wszystkie linie inne niż te, które zaczynają się od pewnego ciągu znaków.
Problem polega na tym, że program do pliku wyjściowego zapisuje tylko puste linie (\n). Gdzie jest błąd ??

int main() {
  int numer, i;
  fstream plik("test.txt", ios::in);
  fstream plik2("test2.txt", ios::out);
  if (plik.good()) {
    i = 0;

    while (!plik.eof()) {
      getline(plik, wiersz);
      string sprawdz = wiersz.substr(0, 4);

      if (sprawdz == "030+") {
        plik2 << wiersze[i] << "\n";
        cout << i;
        i++;
      } else {
      }
    }
    plik.close();
  }
}
1
getline(plik, wiersz);
...
plik2 << wiersze[i] << "\n";

co ma wiersz do wiersze?

0

nie wiem czy zauważyłeś, ale masz if'a: jeśli linia jest tą do usunięcia to zrób pustą linię jeśli nie to nic nie rób
... to jak ma wpisywać co innego?
poza tym nie napisałeś definicji wiersze więc jak mamy pomóc?

0

Problem chyba rozwiązałem. Działa tak, jak sobie tego życzę. Poniżej kod, abyście sprawdzili, czy ma to ręce i nogi (jeśli możecie):

fstream plik("test.txt", ios::in);
fstream plik2("test.txt", ios::in);
fstream plik3("test2.txt", ios::out);
string tmp, HEADR, sprawdz;

getline(plik2, HEADR);
plik2.close();
plik3 << HEADR << endl;
do {
  getline(plik, tmp);
  sprawdz = tmp.substr(0, 4);
  if (sprawdz == "030+")
    plik3 << tmp << endl;
} while (!plik.eof());
plik.close();

Czyli najpierw wczytuje linie, które mają owy początek, następnie z tego samego pliku wczytuje nagłówek (pierwsza linia), dopiero składa pierwsze i drugie wczytanie do kupy i zapisuje.

Ma to sens ??

0

wróć do Twojego pierwszego (lepszego rozwiązania) kodu źródłowego:

while (!plik.eof())

zły warunek/źle sprawdzasz, czy przeczytałeś już cały plik. Tutaj wczytaj linię.

plik2 << wiersze[i] << "\n";

interesującą Cię linię wczytujesz do innej zmiennej. wiersze[i] nie istnieje.

string sprawdz = wiersz.substr(0, 4);
 
if (sprawdz == "030+")

z tym nieco przekombinowałeś. Można prościej.

0

1.nie zamykasz pliku plik3
2.Jeśli substr zwraca stringa to sprawdzaj w ifie a nie zapisujesz tylko po to by sprawdzić
3.twój program w cale nie usuwa niechcianych lini tylko te chciane zapisuje do trzeciego pliku czyli twój program robi co innego niż napisałeś

0

OK. Jakie więc masz sugestie ??
Dodam, że te "oczyszczanie" chcę dodać do programu z tego teamtu

0

jakie sugestie? żarty jakieś?
1.zamknij plik3 bo mogą być z tego powodu potem problemy
2.pomiń zapis do zmiennej i od razu sprawdzaj
3.zapisuj linie do vectora stringów a potem zastąp nimi orginalny plik, dzięki temu niechciane linie znikną.

0
Niikelion napisał(a):

1.nie zamykasz pliku plik3
Wcale nie trzeba. Widziałem wręcz opinie mówiące, że nie należy, bo to jest zbędne i tylko śmieci kod.

2.Jeśli substr zwraca stringa to sprawdzaj w ifie a nie zapisujesz tylko po to by sprawdzić
Zapisanie tego do zmiennej o sensownej nazwie bardzo pomaga zrozumieć kod. Łatwiej ogarnąć dobryPrefix niż substr(0, 4)

3.twój program w cale nie usuwa niechcianych lini tylko te chciane zapisuje do trzeciego pliku czyli twój program robi co innego niż napisałeś
Język naturalny nie jest precyzyjny. Z kodu wynika, że on nie chce zmieniać początkowego pliku.

0
twonek napisał(a):
Niikelion napisał(a):

1.nie zamykasz pliku plik3
Wcale nie trzeba. Widziałem wręcz opinie mówiące, że nie należy, bo to jest zbędne i tylko śmieci kod.

2.Jeśli substr zwraca stringa to sprawdzaj w ifie a nie zapisujesz tylko po to by sprawdzić
Zapisanie tego do zmiennej o sensownej nazwie bardzo pomaga zrozumieć kod. Łatwiej ogarnąć dobryPrefix niż substr(0, 4)

Nie rozumiem co masz na myśli.

Możesz podać przykład tego wektora, bo może i to śmieszne, ale pierwsze słyszę o czymś takim.

0
twonek napisał(a):

Wcale nie trzeba. Widziałem wręcz opinie mówiące, że nie należy, bo to jest zbędne i tylko śmieci kod.

Niech będzie, że trzeba i dodałem.

Zapisanie tego do zmiennej o sensownej nazwie bardzo pomaga zrozumieć kod. Łatwiej ogarnąć dobryPrefix niż substr(0, 4)

coś takiego miałeś na myśli:

do
    {
    	getline( plik, tmp );
    	if(tmp.substr(0,4)== "030+") plik3<<tmp<<endl;
	}
    while(!plik.eof());

Język naturalny nie jest precyzyjny. Z kodu wynika, że on nie chce zmieniać początkowego pliku.

Idea jest taka, żeby plik wejściowy do programu został "oczyszczony" z zbędnych linii zanim ten właściwy program będzie uruchomiony. Także ogólnie chodzi o to, aby plik po "oczyszczeniu" miał taką samą nazwę jak plik wczytany podczas oczyszczani. Czy wektorem można coś takiego uzyskać (jak już pisałem nie umiem nic z wektorów stąd prośba o jakiś example) ??

0

no to tak:
1.te dwie pierwsze rzeczy to sugestie, co z nimi zrobisz to twoja sprawa, inni mieli rację, czytelniej jest bez
2.

vector<string>linie; 

i kiedy wczytasz linię do dodania do tego pliku to w tedylinie.push_back(linia do dodania)

 i na koniec robisz pętle która zapisuje wszystkie linie do pliku(pamiętaj, że musisz go wcześniej zamknąć i otworzyć w trybie w którym tracisz dane które były w pliku)<code class="cpp">for (int i=0; i<linie.size(); i++) 
0

OK. Dzięki, tylko jak zapisać dane będące "w wektorze" ??

1

Pomijam sprawdzanie stanu strumieni itd.

#include <fstream>
#include <string>
#include <vector>
using namespace std;

int main()
{
    ifstream input("nazwa_pliku");
    string tmp;
    vector<string> goodLines;
    while (getline(input, tmp))
    {
        if (jakis_dobry_warunek_zostal_spelniony)
        {
            goodLines.push_back(tmp);
        }
    }
    input.close();

    ofstream output("nazwa_pliku");
    for (const auto& i : goodLines)
    {
        output << i << endl;
    }
}

0

Wielkie dzięki.
Zamiast "nazwa pliku" dać taką samą nazwę ?? Tak aby zmiany były zapisane w tym pliku, z którego zostały wczytane ??

0

tak

0

twonek dałem twój kod wpisując swój warunek:

if (tmp.substr(0,4)== "030+")

i mam coś takieg:

23	22	[Error] ISO C++ forbids declaration of 'i' with no type [-fpermissive]
23	26	[Error] range-based 'for' loops are not allowed in C++98 mode
28		recipe for target 'main.o' failed
1

jak masz już zapisane dane do wektora to otwierasz plik i

for (int i=0; i<linie.size(); i++)
{
    plikwyjsciowy << linie[i] << endl;
} 
0

Nie masz C++11, to musisz użyć starej pętli:

for (size_t i = 0; i < goodLines.size(); ++i)
{
    output << goodLines[i] << endl;
}
0
twonek napisał(a):

Nie masz C++11, to musisz użyć starej pętli:

for (size_t i = 0; i < goodLines.size(); ++i)
{
    output << goodLines[i] << endl;
}

Działa. Jeden tylko problem:
funkcja wygląda tak:

void czyszczenie(const char * PLIK){
    ifstream input(PLIK);
    string tmp,HEADR;
    vector<string> goodLines;
    fstream wczytaj_HEADR (PLIK, ios::in);
    getline(wczytaj_HEADR, HEADR);
    while (getline(input, tmp))
    {
        if (tmp.substr(0,4)== "030+")
        {
            goodLines.push_back(tmp);
        }
    }
    input.close();
 
    ofstream output(PLIK);
    output<<HEADR<<endl;
    for (size_t i = 0; i < goodLines.size(); ++i)
	{
    	output << goodLines[i] << endl;
	}	
}

wywołanie jest praktycznie od razu jak wpiszę nazwę. A problem polega na tym, że po operacji "oczyszczenia" program nie "startuje' kończy działanie na powyższej funkcji, mimo, że dalej ma wczytywać (po sprawdzeniu, czy istnieje) program nic nie robi.

Małe pytanie, czy można usunąć znak, który Notepad++ wczytuje jako SUB (biały tekst w czarnej obwódce). Bo właśnie taki znak (polski znak, który Notepad wczytuje jako SUB) powoduje przerwanie programu (wczytuje wszystko, dopóki linia nie posiada takiego znaku

P.S Czy można zrobić tak, aby zapisując nie zostawiał na koniec pustego znaku ??

0

skoro wywala program na tym znaku to pewnie jest spoza zakresu char... niestety string to wektor charów więc musiałbyś innaczej wczytywać dane
więc tak da się to zrobić ale nie jest to proste

1

1.pokaż jak wykorzystujesz funkcję
2. da się:
plik << goodlines[i];

if (i!=goodlines.size()-1)
{
    plik<<endl;
} 
0
int main() {
  system("cls");
  kolor = GetStdHandle(STD_OUTPUT_HANDLE);
  SetConsoleTextAttribute(kolor, 10);
  pair<string, string> bar = czas();
  cin.clear();

  cout << "Plik: ";
  SetConsoleTextAttribute(kolor, 14);
  cin >> odczyt;

  if (odczyt == "!") {
    return 0;
  }
  if (odczyt == "?") {
    informacje();
    getch();
    main();
  } else {

    PLIK = odczyt + format;
    fstream plik(PLIK.c_str(), ios::in);

    czyszczenie(PLIK.c_str());

    if (plik.good() == false) {

      SetConsoleTextAttribute(kolor, 12);
      system("cls");
      cout << "Plik: " << PLIK.c_str() << " nie istnieje";
      SetConsoleTextAttribute(kolor, 10);
      getch();
      main();
    } else {
      do {
        getline(plik, line);
        linie = linie + 1;
      } while (!plik.eof());
      plik.close();

      typ = line.substr(0, 4);
      rekordy = linie - 1;

      menu(typ, PLIK.c_str());
    }
  }
}

Tego IF'a to muszę gdzie dać ??

Co do SUB zostaje ręczna zmiana ??

0

otwierasz plik, potem go otwierasz w funkcji... nie możesz dwukrotnie go otworzyć
to fstream plik daj po czyszczenie

0

Nie rozumiem. W main mam dwa razy otwarty ten sam plik ??

0

nie... otwierasz plik w main a potem w czyszczenie... plik jest otwarty w main więc w czyszczenie wywali błąd

0

wstaw fstream plik po czyszczenie a nie przed

0

Faktycznie. Jak byś to inaczej zmienił. Bo w czyszczenie plik otwieram tylko w celu odczytania headera (pierwszej linii). Jest to bardzo potrzebne. Jak byś inaczej pobrał te wartość ??

1

... czy ty umiesz czytać????

fstream plik(PLIK.c_str(),ios::in);
czyszczenie(PLIK.c_str()); 

tu otwierasz plik a potem w funkcji go znowu otwierasz...
zrób tak jak napisałem i zamień to na:

czyszczenie(PLIK.s_ctr());
fstream plik(PLIK.c_str(), ios::in); 
0

Jeszcze jedna sprawa, znalazłem w internecie kod, który niby ma usuwać te znaki SUB. Pytanie jest jedno, co w nim jest nie tak (sprawdziłem i nie działa). Oto kod:

using(FileStream f = File.OpenRead("plik.txt"))
{
  using(StreamReader sr = new StreamReader(f)) {
    string text = sr.ReadToEnd();
    text = text.Replace("\u001a", string.Empty);
  }
}

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