Unix c++: getline and line.empty not working - c++

Happy New Year, everyone!
I have a text file that looks like this:
A|AAAAA|1|2
R|RAAAA
R|RAAAA
A|BBBBB|1|2
R|RBBBB
R|RBBBB
A|CCCCC|1|2
R|RCCCC
The following code searches for the relevant text in the file based on the key and returns all the lines that belong to the key:
while( std::getline( ifs, line ) && line.find(search_string) != 0 );
if( line.find(search_string) != 0 )
{
navData = "N/A" ;
}
else{
navData = line + '\n' ; // result initially contains the first line
// now keep reading line by line till we get an empty line or eof
while( std::getline( ifs, line ) && !line.empty() )
{
navData += line + '\n';
}
}
ifs.close();
return navData;
In Windows I get what I need:
A|BBBBB|1|2
R|RBBBB
R|RBBBB
In Mac, however, code "&& !line.empty()" seems to get ignored, since I get the following:
A|BBBBB|1|2
R|RBBBB
R|RBBBB
A|CCCCC|1|2
R|RCCCC
Does anyone know why?
Cheers, everyone!

Windows and Mac have different opinions about how an empty line looks like. On Windows, lines are teminated by "\r\n". On Mac, lines are terminated by "\n" and the preceding "\r" leads to the line not being empty.

Related

Unknown '\\' character in C++

I am working on a legacy codebase & came across a '\\' character:
do
{
string tmpLine;
getline( *testcaseFilePtr, tmpLine );
testcaseFileLineNumber++;
if( tmpLine.size() > 0 && tmpLine[tmpLine.size() - 1] == '\\' )
{
readAnotherLine = true;
tmpLine[tmpLine.size() - 1] = ' ';
}
else
{
readAnotherLine = false;
}
line.append( tmpLine );
} while( readAnotherLine );
As I have seen in gdb debugger, 'readAnotherLine' is always turning out to be false and do while is always exiting after a single iteration.
Suppose my input file looks like:
DEFINE xyz;
DEFINE_MODULE
{
cout << "Example snippet" << endl;
do_this; USER_MACRO ( do_that );
}
The debugger is showing that line string is containing one single line at a time and processing it in further steps. It is not concatenating all the lines of the input file in line altogether.
Please suggest whether it is a typo or it may have some functionality.
Thanks in advance for your suggestion!
The code is looking for lines in the input file like:
abc\
def\
ghi
and will read them into a single line: abc def ghi. In other words, a trailing \ is being treated as a line continuation character.

how to delete comments while parsing text C++

I'm trying to parse text in C++ using "ifstream" from a .ppm file but I want to avoid comments in the file which start with character "#" and finish at the end of the line..I can track the comment character with the code below...Anyone can help on how to dismiss the rest of the words until character '\n'?
string word;
file>>word;
if(strcmp(word, "#")){
//TO DO...Dismiss all characters till the end of the line
}
Use std::getline() & continue the while loop if line[0] == '#':
std::ifstream file( "foo.txt" );
std::string line;
while( std::getline( file, line ) )
{
if( line.empty() )
continue;
if( '#' == line[0] )
continue;
std::istringstream liness( line );
// pull words out of liness...
}
Or if the # can occur mid-line you can just ignore everything after it:
std::ifstream file( "foo.txt" );
std::string line;
while( std::getline( file, line ) )
{
std::istringstream liness( line.substr( 0, line.find_first_of( '#' ) ) );
// pull words out of liness...
}
Depending on the complexity of the comments you want to strip, you might consider using regular expressions:
Removing hash comments that are not inside quotes
For example, which of these would be considered comments:
# Start of line comment
Stuff here # mid-line comment
Contact "Tel# 911"
Would you want to strip all three of the above examples after the #?
Or are you only considering it a comment if the very first character of the line is a #?

how to print X amount of lines after finding a string in a file using C++

I'm trying to implement a function in C++ that searches for a string in a file, then prints the the line containing the string AND X subsequent lines.
I have the following code that works for finding the string and printing the line, but I can't get it to work to print the lines under the line with the string.
void repturno(void){
system("cls");
string codemp, line,output;
bool found = false;
ifstream myfile ("Pacientes.csv");
//captures the string that i need to look for, in this case an employee code
cout<<"\nBienvenida enfermera en turno, por favor introduzca su codigo"<<endl;
cin.ignore();
getline(cin,codemp);
system("cls");
/*reads the file and searches for the string, then prints the whole line, then searches again for
the string and if finds it, will print the whole line again*/
while (getline(myfile, line)) {
if (line.find(codemp) != string::npos) {
cout<<line<<endl;
getline(myfile,line);
found = true;
}
}
//using this to check if the code was working, and verifying if the string was found or not :P
if( found == false){
cout <<"No se encontro la cadena"<< endl;
}
system("pause");
return menu();
}
Here are my problems:
I can't get the cursor to go down to the next line and print it (need to do this 4 times), everything just gets messy and I end up with the same string and its line printed all over the screen many times.
I can't save all the data pertinent to each employee in a single line (it would solve the problem in this function, but would create other problems); there's too much info for each employee, way more than the 80 characters allowed in the console and it messes up other parts of my program where I have to display the information on the screen and it looks really bad when i print it, even when trying to use gotoxy or '\t' for proper spacing. I had to save the data line by line, each category in a different line, so I can properly display it in other parts of my programs.
I came with 2 solutions in pseudo-code, but i don't know how to translate them into C++ sentences:
NOTE: the search loop is already defined in the code above, so won't break it down step by step in the pseudo-code, will refer to it as SEARCH LOOP
Pseudo-code #1
START SEARCH LOOP
SEARCH for the desired string(`codemp`) line by line
IF string is found
PRINTLINE containing the STRING
MOVE CURSOR one line below
PRINT the entire line
MOVE CURSOR one line below
PRINT the entire line
MOVE CURSOR one line below
PRINT the entire line
MOVE CURSOR one line below
PRINT the entire line
Move CURSOR one line below
RESTART SEARCH LOOP in the current line
IF NO matching string is found AND EOF
END IF
END SEARCH LOOP
END PROGRAM
Psuedo-code #2
START SEARCH LOOP
SEARCH for the desired string(codemp) line by line
IF string is found
PRINTLINE containing the string
PRINTING LOOP
MOVE CURSOR one line below
ASSIGN line to a temp_string
IF temp_string = "\n\n"
//each employee is separated by 2 whitelines after its info
DO NOTHING
ELSE
PRINTLINE temp_string
RESTART PRINTING LOOP
END IF
END PRINTING LOOP
RESTART SEARCH LOOP
IF NO string is found AND EOF
END SEARCH LOOP
END PROGRAM
I hope this is clear and detailed enough. That's what I want to do with my program, but I can't find a way to translate it into c++ sentences. Please let me know if there's a better, or more efficient way to do what I want to do.
I didn't test it but that should work :
while( getline(myfile,line) )
{
if( line.find( codemp ) != string::npos )
{
cout << line << endl;
for( int i = 0; i < nbLines && getline( myfile, line ); ++i )
cout << line << endl;
}
}
It iterate the file with a while and when it find the string it print "nbLines" other lines"
Since what you have is working for you, let's look at that first. Here I've xtracted just the relevant portion, with a small addition. All we need to do is print a four more lines in the case that the code was found, so:
while (getline(myfile, line)) {
if (line.find(codemp) != string::npos) {
cout<<line<<endl;
getline(myfile,line);
found = true;
for (int i=4; i; --i) { <== new code begins
cout << line << '\n';
getline(myfile, line);
} <== new code ends
}
}
Simple as that.

copying after a line has been found from a file from that position till the end of that file in c++

I have a file which holds protein coordinates as well as other information preceding it. My aim is to look for a certain line called "$PARAMETERS" and then copy from there every line succeeding it till the end of the file.
How can I get that done? This is the small code I wrote part of the entire program (that someone else wrote years ago, and I took over to upgrade his code for my research):
ifstream InFile;
InFile.open (DC_InFile.c_str(), ios::in);
while ( not InFile.eof() )
{
Line = NextLine (&InFile);
if (Line.find ("#") == 0) continue; // skip lines starting with # (comments)
if (Line.length() == 0) continue; // skip empty lines
size_t pos = Line.find("$PARAMETERS");
Line.copy(Line.begin("$PARAMETERS")+pos, Line.end("$END"));
&Line.copy >> x_1 >> y_2 >> z_3;
}
Bearing in mind that I defined Line as string
I guess you need to read data between $PARAMETERS and $END, not from $PARAMETERS until end of file. If so, you can use the following code:
string str;
while (getline(InFile, str))
{
if (str.find("#") == 0)
continue;
if (str.length() == 0)
continue;
if (str.find("$PARAMETERS") == 0)
{
double x_1, y_2, z_3; // you want to read numbers, i guess
while (getline(InFile, str))
{
if (str.find("$END") == 0)
break;
stringstream stream(str);
if (stream >> x_1 >> y_2 >> z_3)
{
// Do whatever you want with x_1, y_2 and z_3
}
}
}
}
This will handle multiple sections of data; not sure if you really want this behavior.
For example:
# comment
$PARAMETERS
1 2 3
4 5 6
$END
#unrelated data
100 200 300
$PARAMETERS
7 8 9
10 11 12
$END
I'm not sure what you want on the first line of the copied file but assuming you get that straight and you haven't read beyond the current line, you can copy the tail of the fike you are reading like this:
out << InFile.rdbuf();
Here out is the std::ostream you want to send the data to.
Note, that you should not use InFile.eof() to determine whether there is more data! Instead, you should read what you want to read and then check that the read was successful. You need to check after reading because the stream cannot know what you are trying to read before you have done so.
Following up on Dietmar's answer: it sounds to me like you
should be using std::getline until you find a line which
matches your pattern. If you want that line as part of your
output, then output it, then use Dietmar's solution to copy the
rest of the file. Something like:
while ( std::getline( in, line ) && ! isStartLine( line ) ) {
}
if ( in ) { // Since you might not have found the line
out << line << '\n'; // If you want the matching line
// You can also edit it here.
out << in.rdbuf();
}
And don't put all sorts of complicated parsing information,
with continue and break, in the loop. The results are both
unreadable and unmaintainable. Factor it out into a simple
function, as above: you'll also have a better chance of getting
it right. (In your case, should you match "$PARAMETERS #
xxx", or not?) In a separate function, it's much easier to get
it right.

std::fstream error

I'm having some trouble parsing a file
The last two lines of the file I want to parse are:
f 814/866/896 1035/1100/989 817/965/898
[nothing, effect from \n]
This is how I read the file:
while(!inFile.eof())
{
inFile>>sCommand;
if(sCommand == L"#")
{}
else if(sCommand == L"f")
{
int iPos, iTex, iNorm;
iPos=iTex=iNorm = -1;
for(auto face=0; face<3; ++face)
{
inFile>>iPos;
--iPos;
if(inFile.peek() == L'/')
{
inFile.ignore();
inFile>>iTex;
--iTex;
if(inFile.peek() == L'/')
{
inFile.ignore();
inFile>>iNorm;
--iNorm;
}
}
objVertexIndex iObj;
iObj.iPos=iPos;
iObj.iTex=iTex;
iObj.iNorm=iNorm;
this->AddVertex(iObj);
}
m_MaterialIndices_C.push_back(m_CurrentMaterial);
} //END IF
inFile.ignore( 1000, '\n' );
} //END WHILE
inFile.close();
However, I have some trouble with that last line of the file that contains nothing.
Before the last line of the file, inFile.ignore( 1000, '\n' ); will happen and I would expect std::fstream::eof() to be detected, but for some reason it's not.
And apparently sCommand will still be the same command from the previous line if there is nothing on a line, which is giving me some trouble.
Is there a way to check for this? And if yes, how?
Not really an answer but a comment (I don't know how to comment). If you have 2 \n after the last line with numbers eof will not trigger. I had similar problems using .eof() and might be better to check the content of what you read as a condition to keep reading or not.