Search code examples
c++stringconcatenationifstream

Concatenation of strings is replacing first few characters


When I'm trying to concatenate two strings the second string is replacing the first letters of the first string.

I'm using the getline function to get my input from a file, regex on the line to pick out the "UIN" of 9 digits, and trying to append another string onto the original, full line. Ex:

    string line; 
    ifstream in(infile);
    ofstream out("output.csv");
    getline(in, line);
    regex pat("(\\d{9})");
    smatch matches;

    if(regex_search(line, matches, pat))
    {

        line += ",65";

        cout<<line<<endl;
        out<<line<<endl;

    }

(of course Im doing other things in this statement but none operate on the string line so I left it out)

The original line is

Alfonso Livingston,[email protected],800000092

And returned is

,65onso Livingston,[email protected],800000092

I saw this link and have tried creating new strings i.e.string newline(line); and doing string casts(?) (line += string(",65")) but it all ends with the same results. I have also tried to use the append function and the push_back function. Any help would be much appreciated!

edit:

This is my entire function. The input is coming from a comma seperated value list, input.csv. I really cannot replicate this outside of this function, so I don't know if I can give a complete verifiable example.

void combine(string infile)
{
    ifstream in(infile);
    ofstream out("output.csv");
    int size = getSize(infile);
    int hashVal;
    string line; 
    string listVals;
    getline(in, line);
    regex pat("(\\d{9})");
    smatch matches;


    if(regex_search(line, matches, pat))
    {

        hashVal = hash(stoi(matches[0]));
        listVals = table[hashVal].getFirst()->getElem();
        line += ",65";
        cout<<line<<endl;
        out<<line<<endl;

    }


}

This isn't what the entire completed function is suppposed to do, but it's where I've had to stop to figure out this issue.


Solution

  • You aren't actually writing to the beginning of the string, that's just how your terminal displays a '\r' character.

    On Windows, text files use the two characters '\r' and '\n' (ASCII code points 0x0D and 0x0A) to indicate the end of a line. Unix-like operating systems use just the '\n' character. If you are using a library built with Unix style line endings in mind and give it a file with Windows-style line endings, you'll end up with an extra '\r' character at the end of your string when you use std::getline. When you print a '\r' character to your terminal, it moves the cursor back to the beginning of the line, so the rest of the output after that '\r' character is written over the beginning of the string.

    Take this example:

    If I have the file foo.txt with the contents

    This is some text
    This is some more text

    And I run the following program:

    #include <iostream>
    #include <fstream>
    #include <string>
    
    int main() {
        std::string line;
        std::ifstream in("foo.txt");
        std::ofstream out("foo.out");
        std::getline(in, line);
    
        line += "foo";
        std::cout << line << '\n';
        out << line << '\n';
    }
    

    I see the following printed to the terminal:

    foos is some text

    If we look a bit closer, the file contains Windows style line endings:

    $ xxd foo.txt
    00000000: 7468 6973 2069 7320 736f 6d65 2074 6578  this is some tex
    00000010: 740d 0a74 6869 7320 6973 2073 6f6d 6520  t..this is some
    00000020: 6d6f 7265 2074 6578 740d 0a              more text..
    

    Notice the "0d0a" pairs at the end of each line. Also, "foo.out" contains this:

    $ xxd foo.out
    00000000: 7468 6973 2069 7320 736f 6d65 2074 6578  this is some tex
    00000010: 740d 666f 6f0a                           t.foo.
    

    You can see that the "foo" I added to the string isn't at the beginning at all, but at the end after a '\r' character.

    One way to avoid this problem is to check if the last character of your line is a '\r' and pop it off if so:

    if (line.back() == '\r') {
        line.pop_back();
    }
    

    The better way would be to convert the line endings in your input file to match your environment.