How do I get all characters after a space in C++? - c++

In C++, how do I get ALL of the text after a space. I am trying to make my own coding language, so I want the user to be able to enter (/print (text here)) and print the text the user has entered. I want this to be all in one line; without having the user to input the command, then input the thing they want to output. Thank you to anyone who replies in advance.

Try this way. It will give you all the characters after the first space in the string.
std::string x = "ABC CDEFG HIJKL";
x.substr(x.find(" ") + 1);

Leveraging <algorithm>
The following will work with C++11:
#include <string>
#include <algorithm>
#include <cctype>
#include <iostream>
#include <iterator>
bool is_blank(char ch)
{
return std::isblank(static_cast<unsigned char>(ch));
}
int main() {
std::string inp = "print foo";
auto it = std::find_if(inp.begin(), inp.end(), is_blank);
it = std::find_if_not(it, inp.end(), is_blank);
std::copy(it, inp.end(), std::ostream_iterator<char>(std::cout));
}
Run this code in Compiler Explorer.
Note that we're only iterating over the input string once. Also note that this solution leverages the algorithms which come with the C++ standard library - no raw loops required :-)
Using std::string's find functions
std::string has a ton of built-in functions. I'm pretty sure if C++ could be developed from scratch most of them wouldn't be there. But since we have them we put them to some use:
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
int main() {
std::string inp = "print foo";
const std::string whitespace = " \t";
auto i = inp.find_first_of(whitespace);
i = inp.find_first_not_of(whitespace, i);
std::cout << inp.substr(i, inp.size() - i) << std::endl;
}
Run this code in Compiler Explorer.
I prefer the first solution since I find the last line a little more readable. std::copy might also be slightly more efficient. Here std::string::substr() returns a temporary string which gets destroyed once std::cout has printed it. Not ideal in terms of performance which might or might not matter here.

Related

have a programming project for an intro c++ class one of the function we need to create is a split function

i was hoping to get some feedback on if i am doing this the "smart way" or if maybe i could be doing it faster. if i were splitting on white spaces
i would probably use getline(stringstream, word, delimiter)
but i didnt know how to adapt the delimiter to all the good characters so i just looped through the whole string generated a new word until i reached a bad character but as i am fairly new to programming im not sure if its the best way to do it
thanks for any feedback
#include <iostream>
#include <string>
using std::string;
#include <vector>
using std::vector;
#include <sstream>
#include <algorithm>
#include <iterator> //delete l8r
using std::cout; using std::cin; using std::endl;
/*
void split(string line, vector<string>&words, string good_chars)
o
Find words in the line that consist of good_chars.
Any other character is considered a separator.
o
Once you have a word, convert all the characters to lower case.
You then push each word onto the reference vector words.
Important: split goes in its own file. This is both for your own benefit, you can reuse
split, and for grading purposes.We will provide a split.h for you.
*/
void split(string line, vector<string> & words, string good_chars){
string good_word;
for(auto c : line){
if(good_chars.find(c)!=string::npos){
good_word.push_back(c);
}
else{
if(good_word.size()){
std::transform(good_word.begin(), good_word.end(), good_word.begin(), ::tolower);
words.push_back(good_word);
}
good_word = "";
}
}
}
int main(){
vector<string> words;
string good_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'";
// TEST split
split("This isn't a TEST.", words, good_chars);
// words should have: {"this", "isn't", "a", "test"}, no period in test
std::copy(words.begin(), words.end(), std::ostream_iterator<string>(cout, ","));
cout << endl;
return 0;
}
I'd say that this is a reasonable approach given the context of an intro to C++ class. I'd even say that it's fairly likely that this is the approach your instructor expects to see.
There are, of course, a few optimization tweaks that can be done. Like instantiating a 256-element bool array, using good_chars to set the corresponding values to true, and all others defaulting to false, then replacing the find() call with a quick array lookup.
But, I'd predirect that if you were to hand in such a thing, you'll be suspected of copying stuff you found on the intertubes, so leave that alone.
One thing you might consider doing is using tolower when you push_back each character, instead, and removing the extra std::transform pass over the word.

why does char[1] read entire word from my input file?

this is what I have done till now: I want to read words from file in C++ and I am allowed to use only cstring library. this is my piece of code
#include <cstring>
#include <fstream>
#include <stdio.h>
using namespace std;
int main(){
ifstream file;
char word[1];
file.open("p.txt");
while (!file.eof()){
file >> word;
cout << word << endl;
}
system("pause");
return 0;
}
It is working fine and reading one word at a time. But I don't understand how this is working fine.
How can char array of any size be it char word[1] or char word[50] read only one word at a time ignoring spaces.
And further I want to store these words in dynamic array. How can I achieve this? Any guidance would be appreciated?
Your code has undefined behaviour. operator >> simply overwrites memory beyond the array.
Take into account that included by you header <stdio.h> is not used in the program. On the other hand you need to include header <cstdlib> that declares function system.
As for your second question then you should use for example standard container std::vector<std::string>
For example
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
int main()
{
std::ifstream file("p.txt");
std::string s;
std::vector<std::string> v;
v.reserve( 100 );
while ( file >> s ) v.push_back( s );
std::system( "pause" );
return 0;
}
Or you can simply define the vector as
std::vector<std::string> v( ( std::istream_iterator<std::string>( file ) ),
std::istream_iterator<std::string>() );
provided that you will include header <iterator>
For example
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <cstdlib>
int main()
{
std::ifstream file("p.txt");
std::vector<std::string> v( ( std::istream_iterator<std::string>( file ) ),
std::istream_iterator<std::string>() );
for ( const std::string &s : v ) std::cout << s << std::endl;
std::system( "pause" );
return 0;
}
Your code is invoking undefined behavior. That it doesn't crash is a roll of the dice, but its execution is not deterministic precisely because that is the nature of being undefined.
The easiest way (I've found) to load a file of words with whitespace separation is by:
std::ifstream inp("p.txt");
std::istream_iterator<std::string> inp_it(inp), inp_eof;
std::vector<std::string> strs(inp_it, inp_eof);
strs will contain every whitespace delimited char sequence as a linear vector of std::string. Use std::string for dynamic string content and don't feel the least bit guilty about exploiting the hell out of the hard work those that came before you gave us all: The Standard Library.
Your code is failing due to the overload of char * for operator>>.
An array of char, regardless the size, will decompose to the type char * where the value is the address of the start of the array.
For compatibility with the C language, the overloaded operator>>(char *) has been implemented to read one or more characters until a terminating whitespace character is reached, or there is an error with the stream.
If you declare an array of 1 character and read from a file containing "California", the function will put 'C' into the first location of the array and keep writing the remaining characters to the next locations in memory (regardless of what data type they are). This is known as a buffer overflow.
A much safer method is to read into a std::string or if you only want one character, use a char variable. Look in your favorite C++ reference for the getline methods. There is an overload for reading until a given delimiter is reached.
You only need a couple changes:
#include <cstring>
#include <fstream>
#include <stdio.h>
#include <string>
int main(){
ifstream file;
string word;
file.open("p.txt");
while (file >> word){
cout << word << endl;
}
system("pause");
return 0;
}
It works because you are lucky and you don't overwrite some critical memory. You need to allocate enough bytes for char word array, say char word[64]. And use while(file>>word) as your test for EOF. In the loop you can push_back the word into a std::vector<string> if you are allowed to use C++ STL.
If you want a simple C++11 STL-like solution, use this
#include <algorithm>
#include <iterator>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ifstream fin("./in.txt"); // input file
vector<string> words; // store the words in a vector
copy(istream_iterator<string>(fin),{}, back_inserter(words)); // insert the words
for(auto &elem: words)
cout << elem << endl; // display them
}
Or, more compactly, construct the container directly from the stream iterator like
vector<string> words(istream_iterator<string>(fin),{});
and remove the copy statement.
If instead a vector<string> you use a multiset<string> (#include <set>) and change
copy(istream_iterator<string>(fin),{}, back_inserter(words)); // insert the words
to
copy(istream_iterator<string>(fin),{}, inserter(words, words.begin())); // insert the words
you get the words ordered. So using STL is the cleanest approach in my opinion.
You're using C++, so you can avoid all that C stuff.
std::string word;
std::vector<std::string> words;
std::fstream stream("wordlist");
// this assumes one word (or phrase, with spaces, etc) per line...
while (std::getline(stream, word))
words.push_back(word);
or for multiple words (or phrases, with spaces, etc) per line separated by commas:
while (std::getline(stream, word, ','))
words.push_back(word);
or for multiple words per line separated by spaces:
while(stream >> word)
words.push_back(word);
No need to worry about buffer sizes or memory allocation or anything like that.
file>>char *
Will work with any char * and you are using
file >> word;
and it simply sees work variable as a char * but you are getting a segemntation fault somewhere and if your code grows you will see something is not working without any logical reason. GDB debugger will show you the seg fault

Reading from a text file, best way to store data C++

Basicly I have a text file which i need t read-in the values so the program can manipulate them.
Im using C++ and i have written working code to tell if the file exists or not.
The text file is formatted like this:
1 7
8 10
20 6
3 14
...
The values on the left are X values and the values on the right are Y values. (The space in the middle is a tab)
How do I extract this data? say to pass them into a class like this...
myVector(X,Y);
Also, I guess before I can use it in a class I have to TryParse to change it from a string to int right? can C++ do this?
Thank you!
I would be writing something like this if I were you. Note, this is just prototype code, and it was not even tested.
The fundamental idea is to read twice in a line, but with different delimiters. You would read with the tab delimiter first, and then just the default line end.
You need to make sure to gracefully quit the loop when you do not have anything more to read, hence the breaks, albeit the second could be enough if your file is "correct".
You will also need to make sure to convert to the proper type that your vector class expects. I assumed here that is int, but if it is string, you do not need the conversion I have put in place.
#include <string>
#include <fstream>
using namespace std;
void yourFunction()
{
..
ifstream myfile("myfile.txt");
string xword, yword;
while (1) {
if (!getline(myfile, xword, '\t'))
break;
if (!getline(myfile, yword))
break;
myVector.push_back(stoi(xword), stoi(yword));
}
...
}
This sort of parsing could be done in one line with boost.spirit:
qi::phrase_parse(begin, end, *(qi::int_ > qi::int_ > qi::eol), qi::ascii::blank, v);
The grammar could be read as: "read one int, then one int, then one EOL (end of line) (\n or \r\n, depends on locale), as many time as possible". Between ints and EOL can be found blank characters (e.g. spaces or tabs).
Advantages: rather than std::getline loops, code is more clear/concise. spirit.qi get you more powerful control and you don't need stoi calls.
Drawbacks: build-depends (no depends) to spirit.qi, compilation time.
#include <iostream>
#include <fstream>
#include <vector>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/std_pair.hpp>
namespace spirit = boost::spirit;
namespace qi = spirit::qi;
int main(int argc, char **argv)
{
std::ifstream in(argv[1], std::ios_base::in);
std::string storage;
in.unsetf(std::ios::skipws);
spirit::istream_iterator begin(in), end;
std::vector<std::pair<int, int> > v;
qi::phrase_parse(begin, end, *(qi::int_ > qi::int_ > qi::eol), qi::ascii::blank, v);
for(const auto& p : v)
std::cout << p.first << "," << p.second << std::endl;
return 0;
}

How do I concatenate a vector of strings in c++ with boost?

I have a vector of strings, like this:
{"abc"}{"def"}{"ghi"}
I want to concatenate them into a single string, with a separator like "-".
Is there a concise (pretty) way of doing this without using a typical for loop? I have c++03 and boost available to me.
Sure, boost provides a convenient algorithm for achieving what you are trying to do. In higher level languages you may have spotted a join function. Boost provides an equivalent algorithm in the join function.
#include <boost/algorithm/string/join.hpp>
using namespace std;
string data[] = {"abc","def","ghi"};
const size_t data_size = sizeof(data) / sizeof(data[0]);
vector<string> stringVector(data, data + data_size);
string joinedString = boost::algorithm::join(stringVector, "-");
Just for reference, there is currently a proposal for std::join, which you can check out here.
But since you have boost available, you can use boost::algorithm::join, which takes a sequence of strings and a separator, like so:
#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/string/join.hpp>
int main() {
std::vector<std::string> words;
words.push_back("abc");
words.push_back("def");
words.push_back("ghi");
std::string result = boost::algorithm::join(words, "-");
std::cout << result << std::endl;
}
Prints:
abc-def-ghi
Another option using only the STL is:
std::ostringstream result;
if (my_vector.size()) {
std::copy(my_vector.begin(), my_vector.end()-1,
std::ostream_iterator<string>(result, "-"));
result << my_vector.back();
}
return result.str()

Parsing String to Array of Integers

I'm looking for a way to convert a string with specified dividers (such as slashes or spaces) into an array of the integers those dividers separate.
For example, if the user inputs 12/3/875/256, I need to retrieve the array {12, 3, 875, 256}. Ideally, it would be able to handle an arbitrary length.
I tried sweeping through the string character-by-character and storing everything that's not a divider in a temporary variable, which is added to the array the next time I encounter a divider character. Unfortunately, the type conversions are being a pain in the butt. Is there an easier way to do this?
You can set '/' to a delimiter and read using getline? then you'd have to put each one into a variable, and you'd need to know the size--maybe you can pass over the array and count the slashes? then you'd know that and can set up the array first. You might need to parse each string segment into an int, which may or may not be difficult. (haven't used c++ for a while, I don't remember a convenient way.)
See here for a small example of how this is done (3 posts down).
Try using the boost::tokenizer and boost::lexical_cast
strtok and strtol? (this is somewhat tongue in cheek. Strtok is usually not a good idea)
The splitting is covered in this Parsing String to Array of Integers
COnverting strings to int in C++ has quite a number of relevant questions https://stackoverflow.com/search?q=convert+string+to+int+c%2B%2B
What is the issue with the type conversions? It doesn't seem to be a block as far as I can see.
Can you show your code?
Take a look at this other answer. It even has an example of a tokenizer code using boost::tokenizer.
EDIT:
I copied the code there with the neccessary modifications:
#include <iostream>
#include <string>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>
#include <vector>
#include <boost/lexical_cast.hpp>
#include <iterator>
#include <algorithm>
using namespace std;
using namespace boost;
int main(int argc, char** argv)
{
string text = "125/55/66";
vector<int> vi;
char_separator<char> sep("/");
tokenizer<char_separator<char> > tokens(text, sep);
BOOST_FOREACH(string t, tokens)
{
vi.push_back(lexical_cast<int>(t));
}
copy(vi.begin(), vi.end(), ostream_iterator<int>(cout, "\n"));
}
Will print:
125
55
66
You could use a combination of Boost.split and Boost.lexical_cast to break up the string by whatever delimiters you want, and then you could lexical cast it all.
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::string s = "11/23/2010";
std::vector<std::string> svec;
std::vector<int> ivec;
// split the string 's' on '/' delimiter, and the resulting tokens
// will be in svec.
boost::split(svec, s, boost::is_any_of("/"));
// Simple conversion - iterate through the token vector svec
// and attempt a lexical cast on each string to int
BOOST_FOREACH(std::string item, svec)
{
try
{
int i = boost::lexical_cast<int>(item);
ivec.push_back(i);
}
catch (boost::bad_lexical_cast &ex)
{
std::cout << ex.what();
}
}
return 0;
}
Untested...don't have boost on this machine.
Other ways you could use to convert std::string/char * to int types involve stringstream use directly, or C constructs like atoi.