C++ Go back a line - c++

I'm writing a multiple lines system, like this:
string readLines(string x)
{
string temp = "a";
vector<string> lines(0);
string result;
while (1)
{
cout << x;
getline(cin, temp)
if(temp != "")
{
result = result + "\n" + temp;
lines.push_back(temp);
}
else
break;
}
return result;
}
Is working fine, but I want be able to edit the previous line, for example, I'm typing something like this:
Helo,
World
I want to back on helo and fix my typo. How can I do this?

There is no portable way to go back one line in C++.
You can go to the beginning of the line by printing \r, but moving to the previous line requires platform dependent code.
If don't want to use libraries like Curses, you can try ANSI escape codes. Depending on the terminal, cout << "\033[F" will move the cursor one line up.
On Windows, there is also the SetConsoleCursorPosition API.

Related

Why is C++'s file I/O ignoring initial empty lines when reading a text file? How can I make it NOT do this?

I'm trying to build myself a mini programming language using my own custom regular expression and abstract syntax tree parsing library 'srl.h' (aka. "String and Regular-Expression Library") and I've found myself an issue I can't quite seem to figure out.
The problem is this: When my custom code encounters an error, it obviously throws an error message, and this error message contains information about the error, one bit being the line number from which the error was thrown.
The issue comes in the fact that C++ seems to just be flat out ignoring the existence of lines which contain no characters (ie. line that are just the CRLF) until it finds a line which does contain characters, after which point it stops ignoring empty lines and treats them properly, thus giving all errors thrown an incorrect line number, with them all being incorrect by the same offset.
Basically, if given a file which contains the contents "(crlf)(crlf)abc(crlf)def", it'll be read as though its content were "abc(crlf)def", ignoring the initial new lines and thus reporting the wrong line number for any and all errors thrown.
Here's a copy of the (vary messily coded) function I'm using to get the text of a text file. If one of y'all could tell me what's going on here, that'd be awesome.
template<class charT> inline std::pair<bool, std::basic_string<charT>> load_text_file(const std::wstring& file_path, const char delimiter = '\n') {
std::ifstream fs(file_path);
std::string _nl = srl::get_nlp_string<char>(srl::newline_policy);
if (fs.is_open()) {
std::string s;
char b[SRL_TEXT_FILE_MAX_CHARS_PER_LINE];
while (!fs.eof()) {
if (s.length() > 0)
s += _nl;
fs.getline(b, SRL_TEXT_FILE_MAX_CHARS_PER_LINE, delimiter);
s += std::string(b);
}
fs.close();
return std::pair<bool, std::basic_string<charT>>(true, srl::string_cast<char, charT>(s));
}
else
return std::pair<bool, std::basic_string<charT>>(false, std::basic_string<charT>());
}
std::ifstream::getline() does not input the delimiter (in this case, '\n') into the string and also flushes it from the stream, which is why all the newlines from the file (including the leading ones) are discarded upon reading.
The reason it seems the program does not ignore newlines between other lines is because of:
if (s.length() > 0)
s += _nl;
All the newlines are really coming from here, but this cannot happen at the very beginning, since the string is empty.
This can be verified with a small test program:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream inFile{ "test.txt" }; //(crlf)(crlf)(abc)(crlf)(def) inside
char line[80]{};
int lineCount{ 0 };
std::string script;
while (inFile.peek() != EOF) {
inFile.getline(line, 80, '\n');
lineCount++;
script += line;
}
std::cout << "***Captured via getline()***" << std::endl;
std::cout << script << std::endl; //prints "abcdef"
std::cout << "***End***" << std::endl << std::endl;
std::cout << "Number of lines: " << lineCount; //result: 5, so leading /n processed
}
If the if condition is removed, so the program has just:
s += _nl;
, newlines will be inserted instead of the discarded ones from the file, but as long as '\n' is the delimiter, std::ifstream::getline() will continue discarding the original ones.
As a final touch, I would suggest using
while (fs.peek() != EOF){};
instead of
while(fs){}; or while(!fs.eof()){};
If you look at int lineCount's final value in the test program, the latter two give 6 instead of 5, as they make a redundant iteration in the end.

Parsing Data of data from a file

i have this project due however i am unsure of how to parse the data by the word, part of speech and its definition... I know that i should make use of the tab spacing to read it but i have no idea how to implement it. here is an example of the file
Recollection n. The power of recalling ideas to the mind, or the period within which things can be recollected; remembrance; memory; as, an event within my recollection.
Nip n. A pinch with the nails or teeth.
Wodegeld n. A geld, or payment, for wood.
Xiphoid a. Of or pertaining to the xiphoid process; xiphoidian.
NB: Each word and part of speech and definition is one line in a text file.
If you can be sure that the definition will always follow the first period on a line, you could use an implementation like this. But it will break if there are ever more than 2 periods on a single line.
string str = "";
vector<pair<string,string>> v; // <word,definition>
while(getline(fileStream, str, '.')) { // grab line, deliminated '.'
str[str.length() - 1] = ""; // get rid of n, v, etc. from word
v.push_back(make_pair<string,string>(str,"")); // push the word
getline(fileStream, str, '.'); // grab the next part of the line
v.back()->second = str; // push definition into last added element
}
for(auto x : v) { // check your results
cout << "word -> " << x->first << endl;
cout << "definition -> " << x->second << endl << endl;
}
The better solution would be to learn Regular Expressions. It's a complicated topic but absolutely necessary if you want to learn how to parse text efficiently and properly:
http://www.cplusplus.com/reference/regex/

C++ About connect two string

This is a part of my code. I don't know why the string was partially overwrite by another string.
for(int xd = 0 ; xd < 10; xd++)
{
if(booklist[xd].length() != 0)
{
string d = string(booklist[xd]);
string e = "1,2,3,4";
string f = d + e;
cout << d.length() << endl;
cout << d << endl;
cout << f.length() << endl;
cout << f << endl;
}
}
The result of this code is:
16
brave new world
23
1,2,3,4ew world
28
nineteen eighty-four (1984)
35
1,2,3,4n eighty-four (1984)
I don't know why i got this wrong result.
Could someone help me?
Are you populating booklist by pulling from a file that you copied from Windows to a linux machine?
Windows will add a carriage return '\r' to the end of each line in addition to a newline. If you're reading from a windows file and using getline, it'll pull the carriage return into the string.
When a carriage return is output in the terminal, it resets the cursor to the beginning of the line, which would result in the behavior you're seeing.
To fix this, see this question on trimming whitespace from a string. The function you're looking for from that answer is rtrim (or "right trim"):
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
return !std::isspace(ch);
}).base(), s.end());
}
It's likely that your booklist entries have trailing carriage returns, causing line 4 (for instance) to print brave new world, return to column 1, and print 1,2,3,4 over it. (That's why the character count is greater on line 3 than line 1, despite the two lines having the same apparent length.)
Strip the trailing whitespace from booklist entries (or figure out why it's getting in there in the first place, and deal with that) and things should be fine.
Yes i got the reason why it shows wrong.
Just like what scohe001 said: when i use getline to put the file in to an array, it will add \r after each element, so i use substr to remove the \r .Now it get work. Thanks every one.

Simple Sentence Reverser in C++

I'm trying to build a program to solve a problem in a text book I bought recently and it's just driving me crazy.
I have to built a sentence reverser so I get the following:
Input = "Do or do not, there is no try."
Output = "try. no is there not, do or Do"
Here's what I've got so far:
void ReverseString::reversalOperation(char str[]) {
char* buffer;
int stringReadPos, wordReadPos, writePos = 0;
// Position of the last character is length -1
stringReadPos = strlen(str) - 1;
buffer = new char[stringReadPos+1];
while (stringReadPos >= 0) {
if (str[stringReadPos] == ' ') {
wordReadPos = stringReadPos + 1;
buffer[writePos++] = str[stringReadPos--];
while (str[wordReadPos] != ' ') {
buffer[writePos] = str[wordReadPos];
writePos++;
wordReadPos++;
}
} else {
stringReadPos--;
}
}
cout << str << endl;
cout << buffer << endl;
}
I was sure I was on the right track but all I get for an output is the very first word ("try.") I've been staring at this code so long I can't make any headway. Initially I was checking in the inner while look for a '/0' character as well but it didn't seem to like that so I took it out.
Unless you're feeling masochistic, throw your existing code away, and start with std::vector and std::string (preferably an std::vector<std::string>). Add in std::copy with the vector's rbegin and rend, and you're pretty much done.
This is utter easy in C++, with help from the standard library:
std::vector< std::string > sentence;
std::istringstream input( str );
// copy each word from input to sentence
std::copy(
(std::istream_iterator< std::string >( input )), std::istream_iterator< std::string >()
, std::back_inserter( sentence )
);
// print to cout sentence in reverse order, separated by space
std::copy(
sentence.rbegin(), sentence.rend()
, (std::ostream_iterator< std::string >( std::cout, " " ))
);
In the interest of science, I tried to make your code work as is. Yeah, it's not really the C++ way to do things, but instructive nonetheless.
Of course this is only one of a million ways to get the job done. I'll leave it as an exercise for you to remove the trailing space this code leaves in the output ;)
I commented my changes with "EDIT".
char* buffer;
int stringReadPos, wordReadPos, writePos = 0;
// Position of the last character is length -1
stringReadPos = strlen(str) - 1;
buffer = new char[stringReadPos+1];
while (stringReadPos >= 0) {
if ((str[stringReadPos] == ' ')
|| (stringReadPos == 0)) // EDIT: Need to check for hitting the beginning of the string
{
wordReadPos = stringReadPos + (stringReadPos ? 1 : 0); // EDIT: In the case we hit the beginning of the string, don't skip past the space
//buffer[writePos++] = str[stringReadPos--]; // EDIT: This is just to grab the space - don't need it here
while ((str[wordReadPos] != ' ')
&& (str[wordReadPos] != '\0')) // EDIT: Need to check for hitting the end of the string
{
buffer[writePos] = str[wordReadPos];
writePos++;
wordReadPos++;
}
buffer[writePos++] = ' '; // EDIT: Add a space after words
}
stringReadPos--; // EDIT: Decrement the read pos every time
}
buffer[writePos] = '\0'; // EDIT: nul-terminate the string
cout << str << endl;
cout << buffer << endl;
I see the following errors in your code:
the last char of buffer is not set to 0 (this will cause a failure in cout<
in the inner loop you have to check for str[wordReadPos] != ' ' && str[wordReadPos] != 0 otherwise while scanning the first word it will never find the terminating space
Since you are using a char array, you can use C string library. It will be much easier if you use strtok: http://www.cplusplus.com/reference/clibrary/cstring/strtok/
It will require pointer use, but it will make your life much easier. Your delimiter will be " ".
What where the problems with your code and what are more cplusplusish ways of doing is yet well written. I would, however, like to add that the methodology
write a function/program to implement algorithm;
see if it works;
if it doesn't, look at code until you get where the problem is
is not too productive. What can help you resolve this problem here and many other problems in the future is the debugger (and poor man's debugger printf). It will make you able to see how your program actually works in steps, what happens to the data etc. In other words, you will be able to see which parts of it works as you expect and which behaves differently. If you're on *nix, don't hesitate to try gdb.
Here is a more C++ version. Though I think the simplicity is more important than style in this instance. The basic algorithm is simple enough, reverse the words then reverse the whole string.
You could write C code that was just as evident as the C++ version. I don't think it's necessarily wrong to write code that isn't ostentatiously C++ here.
void word_reverse(std::string &val) {
size_t b = 0;
for (size_t i = 0; i < val.size(); i++) {
if (val[i] == ' ') {
std::reverse(&val[b], &val[b]+(i - b));
b = ++i;
}
}
std::reverse(&val[b], &val[b]+(val.size() - b));
std::reverse(&val[0], &val[0]+val.size());
}
TEST(basic) {
std::string o = "Do or do not, there is no try.";
std::string e = "try. no is there not, do or Do";
std::string a = o;
word_reverse(a);
CHECK_EQUAL( e , a );
}
Having a multiple, leading, or trailing spaces may be degenerate cases depending on how you actually want them to behave.

How to compare a string with certain words and if a match is found print the whole string

I am trying to write a little program that will load in a file, compare each line with a specific array of words, and if that line has any of those words in it then I want to "print" that line out to a file.
My current code is:
int main()
{
string wordsToFind[13] =
{"MS SQL", "MySQL", "Virus", "spoof", "VNC", "Terminal", "imesh", "squid",
"SSH", "tivo", "udp idk", "Web access request dropped", "bounce"};
string firewallLogString = "";
ifstream firewallLog("C:\\firewalllogreview\\logfile.txt");
ofstream condensedFirewallLog("C:\\firewalllogreview\\firewallLog.txt");
if(firewallLog.fail())
{
cout << "The file does not exist. Please put the file at C:\\firewalllogreview and run this program again." << endl;
system("PAUSE");
return 0;
}
while(!firewallLog.eof())
{
getline(firewallLog, firewallLogString);
for(int i = 0; i < 13; i++)
{
if(firewallLogString == wordsToFind[i])
{
firewallLogString = firewallLogString + '\n';
condensedFirewallLog << firewallLogString;
cout << firewallLogString;
}
}
}
condensedFirewallLog.close();
firewallLog.close();
}
When I run the program it will compare the string, and if it matches it will only print out the specific word instead of the string. Any help would be much appreciated.
If I understand your problem correctly, you want to check if the line contains one of the word and print it if it does.
Right now what you are doing is this:
if(firewallLogString == wordsToFind[i])
Which checks if the string exactly matches the word. So, if the string contains one of the word but has other words in it, the test will fail.
Instead, check if the word is part of the string, like this:
if(firewallLogString.find(wordsToFind[i]) != string::npos)
There is something wrong in your code.
in this line
getline(firewallLog, firewallLogString);
you are reading a line, not a word, but then later you are comparing the whole line with a word from your array. Your IF shall not work actually.
Instead you need to use strstr method, to lookup for any word in your firewallLogString and if it finds you do the rest of your code.
Use std::string's find method to find the occurrence of your pattern words.