First of all, I should mention that I found several closely related questions. Eg here and here. However, neither do I want to use printf nor do I want to use \n (because I know already that it does not work).
Is it possible for the user to enter a newline, probably an escape sequence, without hitting enter?
As an example:
#include <iostream>
#include <string>
int main () {
std::string a,b;
std::cin >> a;
std::cin >> b;
std::cout << a << "\n" << b;
}
Is it possible for a user to provide a single line of input
hello ??? world
such that the above prints
hello
world
?
You can do like this
std::string a, b;
std::cin >> a>>b;
std::cout << a << "\n" << b;
User can give input with space.
(I assume that you do not want spaces to delimit strings. For example,
Foo bar ??? baz qux
should be two lines.)
It is not possible that you configure the streams so that ??? is automatically converted to a newline character. For the user to input a newline character, they have to input a newline character, not anything else.
You have to parse it yourself.
Here's an example parser that treats ??? as delimiter:
void read_string(std::istream& is, std::string& dest)
{
std::string str = "";
for (char c; is.get(c);) {
switch (c) {
case '?':
if (is.get(c) && c == '?') {
if (is.get(c) && c == '?') {
dest = str;
return;
} else {
str += "??";
}
} else {
str += "?";
}
default:
str += c;
}
}
}
For example, the input
? is still one question mark????? is still two question marks???
is parsed as two lines:
? is still one question mark
?? is still two question marks
live demo
Related
I want to replace hi with a bye by reading a file and outputting another file with the replaced letters.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream myfile;
ofstream output;
output.open("outputfile.txt");
myfile.open("infile.txt");
char letter;
myfile.get(letter);
while (!myfile.eof()) {
if (letter == 'H') {
char z = letter++;
if (z == 'i')
output << "BYE";
}
else output << letter;
}
output.close();
myfile.close();
return 0;
}
My outputs are repeated capital I's that is repeated infinity times.
Here is my input file
Hi
a Hi Hi a
Hi a a Hi
Don't check eof
The eof method is returning the location of the input stream read pointer, and not the status of the get. It is more like telling you whether or not get will succeed, so you could write something like:
while (!myfile.eof()) {
char letter;
myfile.get(letter);
//...
}
In this way, you would at least be getting a new letter at each iteration, and the loop ends when the read pointer reaches the end of the input.
But, there are other cases that might cause the get to not succeed. Fortunately, these are captured by the stream itself, which is returned by get. Testing the status of the stream is as easy as treating the stream as a boolean. So, a more idiomatic way to write the loop is:
char letter;
while (myfile.get(letter)) {
//...
}
Peek at the next letter
When you want to look at the next letter in the input following the detected 'H', you perform an increment.
char z = letter++;
But, this does not achieve the desired result. Instead, it just sets both letter and z variables to the numerical successor of 'H' ('H' + 1), and does not observe the next letter in the input stream.
There is another method you can use that is like get, but leaves the input in the input stream. It is called peek.
char z;
auto peek = [&]() -> decltype(myfile) {
if (myfile) z = myfile.peek();
return myfile;
};
if (peek()) {
//...
}
And now, you can check the value of z, but it is still considered input for the next get on letter.
Close to what you implemented
So, the complete loop could look like:
char letter;
while (myfile.get(letter)) {
if (letter == 'H') {
char z;
auto peek = [&]() -> decltype(myfile) {
if (myfile) z = myfile.peek();
return myfile;
};
if (peek() && z == 'i') {
myfile.get(z);
output << "BYE";
continue;
}
}
output << letter;
}
With this approach, you will be able to correctly handle troublesome cases like HHi as input, or the last letter in the input being an H.
Your two lines:
myfile.get(letter);
while (!myfile.eof()) {
are wrong.
First off you only read letter once, hence your infinite loop.
Secondly you don't use eof in a while loop.
You want something more like:
while (myfile.get(letter)) {
Also:
char z = letter++;
is wrong, you want to read another letter:
myfile.get(z);
but you have to be careful that you get something, so
if(!myfile.get(z)) {
output << letter;
break;
}
So finally:
char letter;
while (myfile.get(letter)) {
if (letter == 'H') {
char z;
if(!myfile.get(z)) {
output << letter;
break;
}
if (z == 'i') {
output << "BYE";
}
else output << letter << z;
}
else output << letter;
}
But now we are consuming the character after any H which may not be desirable.
See #jxh's answer for a way to do this with look ahead.
There is a dedicated function to replace patterns in strings. For example, you could use std::regex_replace. That is very simple. We define, what should be searched for and with what that would be replaced.
Some comments. On StackOverflow, I cannot use files. So in my example program, I use a std::istringstream instead. But this is also an std::istream. You can use any other std::istream as well. So if you define an std::ifstream to read from a file, then it will work in the same way as the std::istringstream. You can simply replace it. For the output I use the same mechanism to show the result on the console.
Please see the simple solution:
#include <iostream>
#include <sstream>
#include <regex>
// The source file
std::istringstream myfile{ R"(Hi
a Hi Hi a
Hi a a Hi)" };
// The destination file
std::ostream& output{ std::cout };
int main() {
// Temporary string, to hold one line that was read from a file
std::string line{};
// Read all lines from the file
while (std::getline(myfile, line)) {
// Replace the sub-string and write to output file
output << std::regex_replace(line, std::regex("Hi"), "Bye") << "\n";
}
return 0;
}
Suppose i have written:
...
char c;
while(condition){
cin>>c;
//do stuff
...
}
...
If 2 characters are give in cin, the next cin will take the second character without me giving any. So, i tried this:
...
char c;
while(condition){
cin<<c
//do stuff
...
cin.ignore("999 \n");
}
...
In this case the program will work keeping only the first input but, is there a way to check how many characters the user inputs in cin in order to print an appropriate message?
for example, if the input is ab it will print something like "Please type only one character".
Read a std::string and validate:
while(condition){
std::string s;
std::cin >> s;
if (s.length() != 1){
// oops - make sure s[0] is not taken
}
c = s[0];
// do stuff
}
I think what you want is std::cin.rdbuf()->in_avail() which will tell you how many chars are still in std::cin buffer. If you are going to read just 1 char, and enter 1 char, the result would be 1, because of unread \n. So keep this in mind when calculating.
#include <iostream>
int main()
{
char c;
std::cin >> c;
std::cout << "cin still contains " << std::cin.rdbuf()->in_avail() << " chars" << std::endl;
}
I am trying to remove leading whitespace and store the characters after the whitespace. I don't want the newline to be considered
This is a file that I am reading from:
Map: Out of planet
Player: Max
My expected result and what I am looking for should be
cout << kill.killMap << endl;
Out of planet // NOTICE THERE IS NO WHITESPACE
cout << kill.player << endl;
Max // NOTICE THERE IS NO WHITESPACE
If the file looks like this...
Map:
Player: Max
Nothing should be stored in the map variable and player variable.
Although the ws function removes whitespace from the stream, I don't think it does the same with char arrays. Would really appreciate it if someone could tell me a way of getting ws to work or just simply an efficient way of removing the whitespace
This is what I am getting:
cout << kill.killMap << endl;
Out of planet //THERE IS WHITESPACE
cout << kill.player << endl;
Max //THERE IS WHITESPACE
Is there a way of doing this without using C++ strings or Vectors. I intend on using C Style strings
THIS IS MY EDITED CODE, HOWEVER IT DOESN'T WORK IF THERE ARE VALID CHARACTERS AFTER THE DELIMITER :... WOULD REALLY APPRECIATE IT IF SOMEONE COULD FIX MY CODE, WOULD MEAN A LOT TO ME.
istreams.get(characters, 50, ':');
istreams.get(c);
istreams.getline(kill.killMap, 35);
while ((is.get(c) != "\n") && (is.get(c) != '\0') )
{
is >> ws;
}
is.getline(kill.killMap, DATA_FILE_SIZE);
if(kill.killMap[0] = '\0)
{
cout << "Error;
break;
}
istreams >> ws;
istreams.get(characters, 50, ':');
istreams.get(c);
while ((is.get(c) != "\n") && (is.get(c) != '\0') )
{
is >> ws;
}
istreams.getline(kill.player, 35);
if(kill.player[0] = '\0)
{
cout << "Error;
break;
}
You can do something like this:
void eatwhites(istream& stream)
{
const string skip=" \t";//put here all wanted skip chars (here i put only SPACE and TAB
while(string::npos != skip.find(stream.peek())){ //if next char in stream exist in skip string
stream.ignore();//then ignore it (1 character).
}
}
EDIT
Here is how i tested it and it works for me:
note you still have to trim the string after you read it, means put the '\0' after the last non white character.
if there is a problem you can tell what input it was and what have you got.
int main()
{
string s1,s2;
eatwhites(cin);
getline(cin,s1, ':');//read until ":"
eatwhites(cin);
getline(cin,s2); //read until "\n"
cout<<"'"<<s1<<"':'"<<s2<<"'"<<endl;
return 0;
}
inputs I've tried:
[SPACE] 123:[SPACE] 456 gives: '123':'456'
[SPACE] 123:[SPACE] gives: '123':''
EDIT2:
With char array it can be used just the same, like this:
#define MAX_FIELD 128
int main()
{
char s1[MAX_FIELD],s2[MAX_FIELD];
eatwhites(cin);
cin.getline(s1, MAX_FIELD, ':');
eatwhites(cin);
cin.getline(s2, MAX_FIELD);
cout<<"'"<<s1<<"':'"<<s2<<"'"<<endl;
return 0;
}
Same results for same input.
Code
I created the following program:
#include <iostream>
void f(char v[])
{
for(char* p = v; *p != 0; p++)
{
std::cout << *p << std::endl;
}
}
int main()
{
std::cout << int(' ') << std::endl;
char c[256];
std::cin >> c;
f(c);
return 0;
}
Compiler
I compiled with GNU GCC Compiler in Code::Blocks with the -std=c++0x flag (with no warnings).
Problem
The problem I have is that if I enter a string containing one or more spaces (i.e. "one and two") then only the letters prior to the first space are printed (i.e. 'o', 'n', 'e').
What I've tried
The only thing that sprung to mind was to do a quick reality check. I added the line:
std::cout << "Val: " << int(' ') << std::endl;
and, as expected, the value printed isn't 0 (because, obviously, it's not the null '\0' character)...
I'm not sure what I'm missing. Is it the case that the line:
std::cin >> c;
uses ' ' as some sort of termination character?
Thanks.
std::cin >> c;
will only read one word delimited by whitespace. That's the functionality for all the >> operators.
If you want to read a whole line, use the getline function instead.
Stream operators >> are formatted input, which uses whitespace as field separators. If you want to retain whitespace in your input, use std::getline() or the stream member function read().
Try getline to input your sentence, space is used as a delimiter between inputs by cin>>.
I wrote the code below that successfully gets a random line from a file; however, I need to be able to modify one of the lines, so I need to be able to get the line character by character.
How can I change my code to do this?
Use std::istream::get instead of std::getline. Just read your string character by character until you reach \n, EOF or other errors. I also recommend you read the full std::istream reference.
Good luck with your homework!
UPDATE:
OK, I don't think an example will hurt. Here is how I'd do it if I were you:
#include <string>
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
static std::string
answer (const string & question)
{
std::string answer;
const string filename = "answerfile.txt";
ifstream file (filename.c_str ());
if (!file)
{
cerr << "Can't open '" << filename << "' file.\n";
exit (1);
}
for (int i = 0, r = rand () % 5; i <= r; ++i)
{
answer.clear ();
char c;
while (file.get (c).good () && c != '\n')
{
if (c == 'i') c = 'I'; // Replace character? :)
answer.append (1, c);
}
}
return answer;
}
int
main ()
{
srand (time (NULL));
string question;
cout << "Please enter a question: " << flush;
cin >> question;
cout << answer (question) << endl;
}
... the only thing is that I have no idea why do you need to read string char by char in order to modify it. You can modify std::string object, which is even easier. Let's say you want to replace "I think" with "what if"? You might be better off reading more about
std::string and using find, erase, replace etc.
UPDATE 2:
What happens with your latest code is simply this - you open a file, then you get its content character by character until you reach newline (\n). So in either case you will end up reading the first line and then your do-while loop will terminate. If you look into my example, I did while loop that reads line until \n inside a for loop. So that is basically what you should do - repeat your do-while loop for as many times as many lines you want/can get from that file. For example, something like this will read you two lines:
for (int i = 1; i <= 2; ++i)
{
do
{
answerfile.get (answer);
cout << answer << " (from line " << i << ")\n";
}
while (answer != '\n');
}