简体   繁体   中英

choose portion of text file using 2 string delimiters c++

I've a little problem with split of text file; in my text file there are almost 10 thousand of recipies like

-Ing_principal

ingr 1

-Ingredients

ingr 1

ingr 2

ingr 3

-Preparation

now how I can get only ingredients between 2 delimiters that are ingredients and preparation.

So I think this solution

int main() {
string s, t;
bool i = false;
ifstream ricette;
ofstream ingredienti;
ingredienti.open("ingredienti.txt");
ricette.open("ricette.txt", ios::out);
while(ricette) {        
    getline (ricette, s);
    if (s[0] == '-' && s[1] == 'I' && s[5] != 'P') {
        i = true;
        getline(ricette, t);
            while (i) {
                if (t[0] != '-' && t[1] != 'P')
                    cout <<  t << endl;
                else i = false; 

        }
    }
}
ingredienti.close();
ingredienti.close();  }

but this return only ingr 1 in infinite loop. Anyone have good solution or suggestion?

It seems you don't read new input lines in this loop:

        while (i) {
            if (t[0] != '-' && t[1] != 'P')
                cout <<  t << endl;
            else i = false; 

            // Here you'll need to read the next line
        }

This line also looks strange:

if (s[0] == '-' && s[1] == 'I' && s[5] != 'P') {

I guess it shall be a 'p' instead of 'P':

if (s[0] == '-' && s[1] == 'I' && s[5] != 'p') {

BTW - you close the same file twice:

ingredienti.close();
ingredienti.close();

However, I would use another approach to avoid two while-statements. Something like:

int main() {
    string s;
    bool foundInterestingSection = false;
    ifstream ricette("ricette.txt");
    ofstream ingredienti("ingredienti.txt");

    while(getline (ricette, s))
    {
        if (foundInterestingSection)
        {
            if (s == "-Preparation")
            {
                // The interesting section ends now
                foundInterestingSection = false;
            }
            else
            {
                cout <<  s << endl;

                // Write to output file
                ingredienti << s << endl;
            }
        }
        else
        {
            if (s == "-Ingredients")
            {
                // The interesting section starts now
                foundInterestingSection = true;
            }
        }
    }
    ingredienti.close();
    ricette.close();
}

You want to access a portion that is delimited by two delimiters. Then the straightforward solution is to search for those two delimiters. You can then copy the intermediate contents for further use.

The approach I used buffers first the whole input from std::cin , because it doesnt't support arbitrary moving around in the input. When using a file, this is most likely not necessary.

To perform searches, the best solution is std::search from <algorithm> , you can use it to find the first occurrence of a sequence inside of another one. In your case, this is finding "-Ingredients" or "-Preparation" inside of the file.

std::string const start_delimiter{"-Ingredients"};
auto start = std::search(from, to, start_delimiter.begin(), start_delimiter.end());
// start now points to '-', assuming the string was found
std::advance(start, delimiter.size());
// start now points delimiter.size() characters AFTER the '-', which
// is the character following the delimiter string
// ...
std::string const end_delimiter{"-Preparation"};
auto end = std::search(start, to, end_delimiter.begin(), end_delimiter.end());
// Your text is between [start,end)
from = end;
std::advance(from, end_delimiter.size());

You use this to find the both delimiters, then you can use the part in between the respective iterators to extract / print / work with the text you're interested in. Note that you might need to add newline characters to your delimiters as needed.

I put together a small example , though you might want to factor the reading into some function, either returning the respective text parts, or taking a functor to work on each of the text part.


Concerning your code, there are multiple issues:

ifstream ricette;
// ...
ricette.open("ricette.txt", ios::out);
// ...
getline(ricette, t);

You take an input file stream, open it for output , then read from it?

  getline(ricette, t);
  while (i) {
            // ...
  }

You only read one line of the ingredients. You need to perform reading inside of your loop, otherwise t will never change inside of that while loop (which is why you get an infinite loop).

ingredienti.close();
ingredienti.close();

... double close ...

Then, in general, you should directly test the input operations, ie the getline :

std::string t; // Use better names, define variables near their use
while(getline(ricette, t)) {
  if (t[0] == '-' && t[1] == 'P') {
   break;
  }
}
// could be eof/failure OR "-P.." found

Then, seeing your test, think of what happens when you input an empty line? Or a line with only a single character? You need to test for the size, too:

if (t.size() > 1 && t[0] == '-' && t[1] == 'P')

And finally, your code assumes different things than what you told us. (Your delimiters are "-I" followed by a "not p" test as well as "-P")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM