Concatenate 2 lines in a vector

I have this program that cleans up some text files for me. I wanted to see if I could take any comments noted with // and move them after the line below them. These notes aren't always there. But if it is I want it to go from this:

// How to do such and such
You do such and such by....

to:

You do such and such by.... // How to do such and such

I put my code section in there that deals with finding the lines and writing them to the vector and then comparing them to make sure they aren't duplicated.

I was thinking of something like strcat or merge but not having any luck.

Thanks
V

1
2
3
4
5
6
7
          for (string line32; getline(ifs31, line32) && line32.find("</settings>") == string::npos; ) {
            line32.erase(remove_if(line32.begin(), line32.end(), isSpace), line32.end());
            line32.erase(line32.find_last_not_of(" ") + 1);
            const auto& result = slines32.insert(line32);
            if (result.second) 
                vlines32.push_back(line32);
        }
Hello Vendetto,

I have read and reread this many times and I am still confused.

Are you trying to take 2 strings from a vector and put them together?

Or is it 2 strings from a file and put them together?

The code does not appear to match the subject line.

Andy
HI Andy,

Sorry for the confusion. There are in a file together and do get written to a new file later in the program. The section I posted is where the file gets read to a vector before having parts from another file added to it. I apologize if I stated the subject wrong. I figured while it was being read into the vector for cleanup, the code is that part where it removes white spaces and checks for duplicates, that would be best time to put them together.

Thanks,
V
Hello Vendetto,

I tried to put some code together to be able to compile what you posted, but have some problems and errors that I do not know how to fix.

Having no input file to work with and not sure what to do to create on that will match what you are using I do not know what to do.

Without enough code of what you have written to compile I do not know if what I did is correct.

I find the 2 line that "erase" to be suspect because I do not know what it is erasing.

The line: const auto& result = slines32.insert(line32);. First the ".insert" takes 2 parameters, but you are just giving the function 1. Second , for me, "auto" gave the type of "std::string". Are you expecting something different?

Then in: if (result.second) . If "result is a "std::string" there is no ".second". To me the "result.second" makes me think that it is referring to something like a "std::pair", "std::map" or something else that has 2 parts.

At the moment what you are doing in the for loop does not feel right.

I am think that first you should read the file and put each line into a vector then work with that to create a new vector or just write the changes to a file.

I am also thing something like: slines32 += " " + line32; would be much easier to use. The beginning space is your choice. You do not have to use it.

To help anyone else post the input file you are using or at least a good sample to demonstrate what you need. Followed by what the file should look like when the program is done. With out that the code is out of context.

Andy
Hi Andy

Sorry for the vagueness. The program is long and has several parts to it. The text file being read is a list of settings we use when upgrading clients we sell. There are 2 files that get combined here. I'll post more of the code below. In the program the files are merged and then I am sorting it alphabetically. Later it gets added to an xml file which I have that part working out as need. However, we would put // comment lines above the settings. When I sort the final text it breaks the comments away from the settings. So that is why I am trying to move them to be behind the settings or whatever it is we add at that time. The two input files would look like this:

//This settings sets the background to black
<background>00</background>
//Allows users to colorize their buttons
<usercolorbuttons>true</usercolorbuttons>
//This is settings 3
<setting3>true</setting3>
etc...

I want it to look like this when it is done combining:

<background>00</background> //This settings sets the background to black
<usercolorbuttons>true</usercolorbuttons> //Allows users to colorize their buttons
<setting3>true</setting3> //This is settings 3
etc..

If it has to be done at a separate step that is fine. Just having trouble getting it going and I figured while I was reading it and checking for duplicates (that's the part that you are questioning I believe) that it could be done at the same time.

I don't have the sort line in there right now as it was not doing it the way I wanted because of how the 2 input files are laid out currently.

Let me know if that helps clarify.

Thanks,
V

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
        vector<string> vlines31;
        vector<string> vlines32;
        set<string>    slines31;
        set<string>    slines32;



        for (string line31; getline(ifs31, line31); vlines31.push_back(line31))
            if (line31.find("<settings>") != string::npos) {
                vlines31.push_back(line31);
                break;
            }

        for (const auto& v : vlines31)
            ofs31 << v << '\n';


        for (string line32; getline(ifs31, line32) && line32.find("<EndofFile>") == string::npos; ) {
            line32.erase(remove_if(line32.begin(), line32.end(), isSpace), line32.end());
            line32.erase(line32.find_last_not_of(" ") + 1);
            const auto& result = slines32.insert(line32);
            if (result.second) 
                vlines32.push_back(line32);
        }


        for (string line32; getline(in_newlines, line32);) {
            line32.erase(remove_if(line32.begin(), line32.end(), isSpace), line32.end());
            const auto& result = slines32.insert(line32);
            if (result.second)
                vlines32.push_back(line32);
        }

        

        for (auto it = vlines32.cbegin(); it != vlines32.cend(); ++it)
            ofs31 << '\t' << '\t' << *it << '\n';


        ifs31.close();
        ofs31.close();
        in_newlines.close();
Hello Vendetto,

It will take me awhile to go over your code and I will have to do that tomorrow.

For now I do have some questions about what I have seen.

A thought I had that you can think about is read a file line by line and put it into a vector of strings. Loop through that vector and if a line starts with (//) set a new string equal to (vector[idx] + " " + vector[idx + 1]). Do not forget to add 1 to idx before you return to the for loop or you will be off by 1 and then 2 and so on. Create a new vector to store the changes. that is both unchanged lines and changed lines.

Do this for both files then add the vector for file 2 to the vector for file 1 then yu can sort it.

Sometimes it is better to keep it simple until it works correctly first then see if you can combine it into 1 for loop.

Sorry have to go for now.

Andy
Try replacing:

1
2
  for (auto it = vlines32.cbegin(); it != vlines32.cend(); ++it)
            ofs31 << '\t' << '\t' << *it << '\n';


with C++20 (not tried):

1
2
3
4
5
6
7
8
	for (std::string comment; const auto & line : vlines32) {
		if (line.starts_with("//"))
			comment = " " + line;
		else {
			ofs31 << '\t' << '\t' << line + comment << '\n';
			comment.clear();
		}
	}

Last edited on
Hello Vendetto,

Having some time to think about it I came up with this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
int main()
{
    std::vector<std::string> vlines31;
    std::vector<std::string> newVLines31;  // <--- Added.
    std::vector<std::string> vlines32;
    std::set<std::string>    slines31;
    std::set<std::string>    slines32;
    
    std::ifstream ifs31("Input.txt"), in_newlines;
    std::ofstream ofs31("Output.txt");

    if (!ifs31)
    {
        std::cerr << "\n    File \"Input.txt\" did not open!\n\n";

        return 1;
    }

    if (!ofs31)
    {
        std::cerr << "\n    File \"Output.txt\" did not open!\n\n";

        return 2;
    }

    for (std::string line31; std::getline(ifs31, line31); vlines31.push_back(line31))
    {
        if (line31.find("<setting>") != std::string::npos)
        {
            vlines31.push_back(line31);
            break;
        }
    }

    for (size_t idx = 0; idx < vlines31.size(); idx++)
    {
        std::string newString;

        //if (vlines31[idx][0] == '/' && vlines31[idx][1] == '/')
        if (vlines31[idx].substr(0, 2) == "//")
        {
            newString = vlines31[idx + 1] + " " + vlines31[idx];

            //std::cout << '\n'; // <--- Used for testing. Comment or remove when finished.

            //ofs31 << newString << '\n';

            newVLines31.emplace_back(newString);

            idx++;  // <--- To account for "idx + 1". You have already used this element and need to go past it.
        }
        else
        {
            //ofs31 << vlines31[idx] << '\n';
            newVLines31.emplace_back(vlines31[idx]);
        }
    }

    for (const auto& v : newVLines31)
        std::cout << v << '\n';

    return 0;
}

Late last night I came up with line 39. This morning I revised it to line 40 which does the same thing.

My point is that I realized that the first 2 for loops can be combined into 1 that can create 1 vector the way you want the information. Combining the 2 for loop will take some adjustment to read from the file instead of using a vector, but it can be done.

In the 1st for loop the if statement you started with: if (line31.find("<settings>") != string::npos) will never be true. Compare what you are trying to fine to what is in the file "<setting3>". Notice the difference. The ".find" function is looking for an exact match, so <settings> will never match what you have provided. You could try ".find_first_of" or use ".find" with "<setting". Notice the missing ">" at the end.

I am guessing that you want to find this tag and stop processing the file of anything that is after this tag.

The code that follows I have yet to understand what it is for.

This is a start. You can duplicate the code to read a second file into a second vector. Then maybe combine the 2 vectors into 1 large vector that would be easier to sort.

Andy
seeplus's response worked perfectly!!
Topic archived. No new replies allowed.