Reputation: 34185
Using std::istringstream
it is easy to read words separated by white space. But to parse the following line, I need the character /
to be treated like white space.
f 104/387/104 495/574/495 497/573/497
How can I read values separated by either slash or white space?
Upvotes: 1
Views: 2565
Reputation: 390
I'm sure this isn't the best way at all, but I was working on an exercise in the book Programming Principles and Practice Using C++ 2nd Ed. by Bjarne Stroustrup and I came up with a solution that might work for you. I searched around to see how others were doing it (which is how I found this thread) but I really didn't find anything.
First of all, here's the exercise from the book:
Write a function vector<string> split(const string& s, const string& w) that returns a vector of whitespace-separated substrings from the argument s, where whitespace is defined as "ordinary whitespace" plus the characters in w.
Here's the solution that I came up with, which seems to work well. I tried commenting it to make it more clear. Just want to mention I'm pretty new to C++ (which is why I'm reading this book), so don't go too hard on me. :)
// split a string into its whitespace-separated substrings and store
// each string in a vector<string>. Whitespace can be defined in argument
// w as a string (e.g. ".;,?-'")
vector<string> split(const string& s, const string& w)
{
string temp{ s };
// go through each char in temp (or s)
for (char& ch : temp) {
// check if any characters in temp (s) are whitespace defined in w
for (char white : w) {
if (ch == white)
ch = ' '; // if so, replace them with a space char ('')
}
}
vector<string> substrings;
stringstream ss{ temp };
for (string buffer; ss >> buffer;) {
substrings.push_back(buffer);
}
return substrings;
}
Then you can do something like this to use it:
cout << "Enter a string and substrings will be printed on new lines:\n";
string str;
getline(cin, str);
vector<string> substrings = split(str, ".;,?-'");
cout << "\nSubstrings:\n";
for (string s : substrings)
cout << s << '\n';
I know you aren't wanting to split strings, but this is just an example of how you can treat other characters as whitespace. Basically, I'm just replacing those characters with ' ' so they literally do become whitespace. When using that with a stream, it works pretty well. The for loop(s) might be the relevant code for your case.
Upvotes: 0
Reputation: 74028
If you know when to split by either slash or whitespace, you can use std::getline
std::istringstream is("f 104/387/104 495/574/495 497/573/497");
std::string f, i, j, k;
std::getline(is, f, ' ');
std::getline(is, i, '/');
std::getline(is, j, '/');
std::getline(is, k, ' ');
Alternatively, you can use formatted input and discard the slashes manually
std::string f;
int i, j, k;
char slash;
is >> f >> i >> slash >> j >> slash >> k;
Upvotes: 2
Reputation: 490138
One way is to define a ctype facet that classifies /
as white-space:
class my_ctype : public std::ctype<char> {
public:
mask const *get_table() {
static std::vector<std::ctype<char>::mask>
table(classic_table(), classic_table()+table_size);
table['/'] = (mask)space;
return &table[0];
}
my_ctype(size_t refs=0) : std::ctype<char>(get_table(), false, refs) { }
};
From there, imbue the stream with a locale using that ctype facet, then read words:
int main() {
std::string input("f 104/387/104 495/574/495 497/573/497");
std::istringstream s(input);
s.imbue(std::locale(std::locale(), new my_ctype));
std::copy(std::istream_iterator<std::string>(s),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
Upvotes: 9
Reputation: 121971
If boost is available, then boost::split()
would be a possible solution. Populate a std::string
using std::getline()
and then split the line:
#include <iostream>
#include <vector>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
int main()
{
std::vector<std::string> tokens;
std::string line("f 104/387/104 495/574/495 497/573/497");
boost::split(tokens, line, boost::is_any_of("/ "));
for (auto& token: tokens) std::cout << token << "\n";
return 0;
}
Output:
f 104 387 104 495 574 495 497 573 497
Upvotes: 4