c++ string iterator "find first of" - c++

Is there a method in string iterator like find_first_of on string ?
Something like:
string::iterator it;
string str(" h asdasf ^& saafa");
it = FIND_FIRST_OF("&az^");
std::cout << *it << std::endl;
And the result:
a

You can do it indirectly
auto pos = str.find_first_of("&az^");
then advance the iterator
if(pos != std::string::npos) // thanks to #Mike Seymour
std::advance(it, pos);
I guess you can also do some kind of std::find with a lambda, but the above is really much more simpler and concise.

I think std::find_first_of is what you're looking for.
string::iterator it;
string str(" h asdasf ^& saafa");
string find_me ("&az^");
it = std::find_first_of (str.begin(), str.end(), find_me.begin(), find_me.end());
std::cout << *it << std::endl;
I would write a function to clean up the overhead involved in constructing/using the intermediary find_me variable if using this method with any frequency.

Try this:
std::string::size_type position = example.find_first_of(".");
if (position != std::string::npos)
{
std::advance(string_iterator, position);
}
else
{
string_iterator = example.end();
}

Class std::string has its own methods find_first_of and find_last_of apart from other find methods.
Here is a demonstrative program
#include <iostream>
#include <string>
int main()
{
std::string s( " h asdasf ^& saafa" );
auto pos = s.find_first_of( "&az^" );
if ( pos != std::string::npos ) std::cout << s[pos] << std::endl;
pos = s.find_last_of( "&az^" );
if ( pos != std::string::npos ) std::cout << s[pos] << std::endl;
return 0;
}
The program output is
a
a
Here is another demonstrative program that finds all characters in the string that are specified in the character literal
#include <iostream>
#include <string>
int main()
{
std::string s( " h asdasf ^& saafa" );
for ( std::string::size_type pos = 0;
( pos = s.find_first_of( "&az^", pos ) ) != std::string::npos;
++pos )
{
std::cout << pos << ": " << s[pos] << std::endl;
}
return 0;
}
The program output is
4: a
7: a
11: ^
12: &
15: a
16: a
18: a
Knowing the found position you always can get the corresponding iterator in the object:
std::string::iterator it = std::next( s.begin(), pos );
or
auto it = std::next( s.begin(), pos );
or simply
std::string::iterator it = s.begin() + pos;
Also there is standard algorithm std::find_first_of declared in header <algorithm> that also can be used with objects of type std::string.

Related

Problem with only reading certain values in a string

For the following string string s1 = "172.16.254.01";I only want to read the numbers values and push them into a vector. It works well with this problem, but if I want to do it to let's say string s1 = "172.16.254...01"it will also push back two empty strings into my vector which I don't want to do. This will ruin my new vector, because not only do I have two empty strings but the size of the vector will also increase which will be problamatic in my case.
This is my code:
string s1 = "172.16.254.01";
vector<string> res;
string delimiter = ".";
size_t pos = 0;
while ((pos = s1.find(delimiter)) != std::string::npos) {
res.push_back(s1.substr(0, pos));
s1.erase(0, pos + delimiter.length());
}
res.push_back(s1);
for (auto value : res)
{
cout << value << endl;
}
This will output:
172
16
254
01
As you can see I use "." as a delimiter and read everything into a new string until it hits another ".". How can I manipulate my loop so that it fulfills the given requirements I mentioned at the start?
You need to check that between two delimiters there is a non-empty substring.
For example if the source string starts from the delimiter "." like ".1" then in the first iteration of the while loop an empty string will be pushed on the vector
while ((pos = s1.find(delimiter)) != std::string::npos) {
res.push_back(s1.substr(0, pos));
This statement after the while loop
res.push_back(s1);
can also append an empty string to the vector.
And there is no great sense to erase the source string.
I can suggest the following solution.
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string s( "172.16.254...01" );
std::vector<std::string> v;
const char delim = '.';
for (std::string::size_type pos = 0; pos != std::string::npos; )
{
auto last = s.find( delim, pos );
if (pos != last)
{
pos = s.find_first_not_of( ' ', pos );
if (pos != last)
{
v.push_back( s.substr( pos, last - pos ) );
}
pos = last;
}
if (pos != std::string::npos) ++pos;
}
for (const auto &item : v)
{
std::cout << item << ' ';
}
std::cout << '\n';
}
The program output is
172 16 254 01
Your code is not skipping unnecessary delimiter. It is directly inserting the values into res. So you should try something like this to skip unnecessary delimiter:
if (pos < s1.size())
{
if (s1.substr(pos + 1, delimiter.size()) == delimiter)
{
// Erase the extra delimiter
s1.erase(pos + 1, delimiter.length()); continue;
}
}
Final code:
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::string s1 = "172.16.254...01";
std::vector<std::string> res;
std::string delimiter = ".";
size_t pos = 0;
while ((pos = s1.find(delimiter)) != std::string::npos)
{
if (s1.substr(pos + 1, delimiter.size()) == delimiter)
{
// Erase the extra delimiter
s1.erase(pos + 1, delimiter.length()); continue;
}
res.push_back(s1.substr(0, pos));
s1.erase(0, pos + delimiter.length());
}
for (auto value : res)
{
std::cout << value << std::endl;
}
}
Also, you should consider not using the following line in your code:
using namespace std;
...as it's considered as bad practice. Instead use std:: everytime.

Unpredicted infinite for loop in c++ [duplicate]

This question already has answers here:
How do unsigned integers work
(3 answers)
Closed 2 years ago.
I am writing a program to return first occurrence of the character and the frequency of that character in the string.
For loop in the function is executing infinite times and if condition and block is not executing even once.
What is the problem?
string::size_type find_ch(string &str,char ch,int& i_r)
{
string::size_type first=0;
for(auto i=str.size()-1;i>=0;i--)
{
cout<<"\nInside a for loop."<<endl;
if(str[i]==ch)
{
cout<<"Inside if."<<endl;
first=i+1;
i_r++;
}
}
return first;
}
This loop:
for(auto i = str.size() - 1; i>=0; i--)
will only exit when i is less than 0. But this is not a valid value for an unsigned int. The value will wrap to the maximum unsigned int, and you get an infinite loop.
Note that .size() on a std::string returns a size_t, which is basically an unsigned int type.
One way to fix this would be to cast the return type of .size() to an int, like this:
for(auto i = static_cast<int>(str.size()) - 1; i>=0; i--)
Note that it's important to do the cast before subtracting 1, otherwise you'll get the wrong answer when str is empty.
In c++20, you can avoid this issue entirely by calling the std::ssize() free function, which returns a signed version of the size.
The function definition in general is wrong.
For example if the given character is nit found then why does the function return 0 that is a valid position?
Returning the value first=i+1; will only confuse users of the function. The function shall return std::string::npos if the given character is not found.
Also it is entirely unclear why the loop starts from the end of the string while you need to return the first position of the character.
As for the infinite loop then in the loop there is used variable i that has the unsigned integer type std::string::size_type a value of which never can be negative.
for(auto i=str.size()-1;i>=0;i--)
^^^^^^^^^^^^^^^^^^^
That is the condition i >= 0 is always true by the definition.
The function should be defined the following way
std::pair<std::string::size_type, std::string::size_type> find_ch( const std::string &str, char ch )
{
auto n = str.find( ch );
std::pair<std::string::size_type, std::string::size_type> p( n, 0 );
if ( n != std::string::npos )
{
++p.second;
while ( ( n = str.find( ch, n + 1 ) ) != std::string::npos ) ++p.second;
}
return p;
}
Here is a demonstrative program.
#include <iostream>
#include <string>
#include <utility>
std::pair<std::string::size_type, std::string::size_type> find_ch( const std::string &str, char ch )
{
auto n = str.find( ch );
std::pair<std::string::size_type, std::string::size_type> p( n, 0 );
if ( n != std::string::npos )
{
++p.second;
while ( ( n = str.find( ch, n + 1 ) ) != std::string::npos ) ++p.second;
}
return p;
}
int main()
{
std::string s( "C++ is not the same as C" );
auto p = find_ch( s, 'C' );
if ( p.first != std::string::npos )
{
std::cout << p.first << ": " << p.second << '\n';
}
return 0;
}
The program output is
0: 2
If you are not allowed to use methods of the class std::string then just substitute calls of the method find in the function above to while loops as it is shown below.
#include <iostream>
#include <string>
#include <utility>
std::pair<std::string::size_type, std::string::size_type> find_ch( const std::string &str, char ch )
{
std::pair<std::string::size_type, std::string::size_type> p( std::string::npos, 0 );
std::string::size_type n = 0;
while ( n < str.size() && str[n] != ch ) ++n;
if ( n != str.size() )
{
p.first = n;
++p.second;
while ( ++n != str.size() )
{
if( str[n] == ch ) ++p.second;
}
}
return p;
}
int main()
{
std::string s( "C++ is not the same as C" );
auto p = find_ch( s, 'C' );
if ( p.first != std::string::npos )
{
std::cout << p.first << ": " << p.second << '\n';
}
return 0;
}
Here is an answer similar to #Vlad From Moscow, but uses string functions, and the algorithm std::count.
#include <algorithm>
#include <string>
#include <utility>
#include <iostream>
std::pair<int,int> find_ch(const std::string &str, char ch)
{
std::pair<int, int> ret;
auto pos = str.find_first_of(ch);
if ( pos == std::string::npos )
return {-1,0}; // not found
return { pos, std::count(str.begin() + pos, str.end(), ch) };
}
int main()
{
auto pr = find_ch("abccabc", 'b');
std::cout << "character b is at position " << pr.first << ". Character count is " << pr.second << "\n";
pr = find_ch("abccabc", 'c');
std::cout << "character c is at position " << pr.first << ". Character count is " << pr.second;
}
Output:
character b is at position 1. Character count is 2
character c is at position 2. Character count is 3
Each line of the function basically describes what is being done:
find_first_of the character in the string. If found then return that position and the std::count of that character starting at the first occurrence.
Note the brevity and self-documented way the function is written. A C++ programmer could look at that code and immediately know what it does, due to the names of the functions that are being called.
Writing loops going backwards (as you originally did) with variables incremented here and there, the programmer has to sit down and go through the code to figure out what it is doing, and what the purpose of the function is.

Split string into key-value pairs using C++

I have a string like this:
"CA: ABCD\nCB: ABFG\nCC: AFBV\nCD: 4567"
Now ": " splits key from value while \n separates the pairs. I want to add the key-value pairs to a map in C++.
Is there any efficient way of doing this considering optimization in mind?
Well I have two methods here. The first one is the easy, obvious method that I use all the time (performance is rarely an issue). The second method is likely more efficient but I have not done any formal timings.
In my tests the second method is about 3 times faster.
#include <map>
#include <string>
#include <sstream>
#include <iostream>
std::map<std::string, std::string> mappify1(std::string const& s)
{
std::map<std::string, std::string> m;
std::string key, val;
std::istringstream iss(s);
while(std::getline(std::getline(iss, key, ':') >> std::ws, val))
m[key] = val;
return m;
}
std::map<std::string, std::string> mappify2(std::string const& s)
{
std::map<std::string, std::string> m;
std::string::size_type key_pos = 0;
std::string::size_type key_end;
std::string::size_type val_pos;
std::string::size_type val_end;
while((key_end = s.find(':', key_pos)) != std::string::npos)
{
if((val_pos = s.find_first_not_of(": ", key_end)) == std::string::npos)
break;
val_end = s.find('\n', val_pos);
m.emplace(s.substr(key_pos, key_end - key_pos), s.substr(val_pos, val_end - val_pos));
key_pos = val_end;
if(key_pos != std::string::npos)
++key_pos;
}
return m;
}
int main()
{
std::string s = "CA: ABCD\nCB: ABFG\nCC: AFBV\nCD: 4567";
std::cout << "mappify1: " << '\n';
auto m = mappify1(s);
for(auto const& p: m)
std::cout << '{' << p.first << " => " << p.second << '}' << '\n';
std::cout << "mappify2: " << '\n';
m = mappify2(s);
for(auto const& p: m)
std::cout << '{' << p.first << " => " << p.second << '}' << '\n';
}
Output:
mappify1:
{CA => ABCD}
{CB => ABFG}
{CC => AFBV}
{CD => 4567}
mappify2:
{CA => ABCD}
{CB => ABFG}
{CC => AFBV}
{CD => 4567}
This format is called "Tag-Value".
The most performance critical place where such encoding is used in the industry is probably financial FIX Protocol (= for key-value separator, and '\001' as entries delimiter). So if you are on x86 hardware then your best bet would be to google 'SSE4 FIX protocol parser github' and reuse the open sourced findings of HFT shops.
If you still want to delegate the vectorization part to the compiler and can spare few nanoseconds for readability then the most elegant solution is to store the result in a std::string (data) + boost::flat_map<boost::string_ref, boost::string_ref> (view). Parsing is a matter of taste, while-loop or strtok would be easiest for the compiler to parse. Boost-spirit based parser would be easiest for a human (familiar with boost-spirit) to read.
C++ for-loop based solution
#include <boost/container/flat_map.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/iterator_range_io.hpp>
#include <iostream>
// g++ -std=c++1z ~/aaa.cc
int main()
{
using range_t = boost::iterator_range<std::string::const_iterator>;
using map_t = boost::container::flat_map<range_t, range_t>;
char const sep = ':';
char const dlm = '\n';
// this part can be reused for parsing multiple records
map_t result;
result.reserve(1024);
std::string const input {"hello:world\n bye: world"};
// this part is per-line/per-record
result.clear();
for (auto _beg = begin(input), _end = end(input), it = _beg; it != _end;)
{
auto sep_it = std::find(it, _end, sep);
if (sep_it != _end)
{
auto dlm_it = std::find(sep_it + 1, _end, dlm);
result.emplace(range_t {it, sep_it}, range_t {sep_it + 1, dlm_it});
it = dlm_it + (dlm_it != _end);
}
else throw std::runtime_error("cannot parse");
}
for (auto& x: result)
std::cout << x.first << " => " << x.second << '\n';
return 0;
}
The format is simple enough that doing the parsing "by hand" IMO is the best option, overall remains quite readable.
This should also be reasonably efficient (the key and value strings are always the same - albeit cleared, so the reallocations inside the main loop should just stop after a few iterations); ret also should qualify for NRVO, OTOH in case of problems with that you can always change to an output parameter.
Of course std::map may not be the fastest gun in the west, but it's a request in the problem text.
std::map<std::string, std::string> parseKV(const std::string &sz) {
std::map<std::string, std::string> ret;
std::string key;
std::string value;
const char *s=sz.c_str();
while(*s) {
// parse the key
while(*s && *s!=':' && s[1]!=' ') {
key.push_back(*s);
++s;
}
// if we quit due to the end of the string exit now
if(!*s) break;
// skip the ": "
s+=2;
// parse the value
while(*s && *s!='\n') {
value.push_back(*s);
++s;
}
ret[key]=value;
key.clear(); value.clear();
// skip the newline
++s;
}
return ret;
}
If worried about performance, you should probably rethink the need for the end result to be a map. That could end up being a lot of char buffers in memory. Ideally keeping track of just the char* and length of each sub string will be faster/smaller.
Here is a solution, using strtok as a splitting means. Please note that strtok changes your string, it puts '\0' at the split char.
#include <iostream>
#include <string>
#include <map>
#include <string.h>
using namespace std;
int main (int argc, char *argv[])
{
char s1[] = "CA: ABCD\nCB: ABFG\nCC: AFBV\nCD: 4567";
map<string, string> mymap;
char *token;
token = strtok(s1, "\n");
while (token != NULL) {
string s(token);
size_t pos = s.find(":");
mymap[s.substr(0, pos)] = s.substr(pos + 1, string::npos);
token = strtok(NULL, "\n");
}
for (auto keyval : mymap)
cout << keyval.first << "/" << keyval.second << endl;
return 0;
}
I doubt you should worry about optimization for reading this string and converting it in a std::map. If you really want to optimize this fixed-content map, change it to a std::vector<std::pair<>> and sort it once.
That said, the most elegant way of creating the std::map with standard C++ features is the following:
std::map<std::string, std::string> deserializeKeyValue(const std::string &sz) {
constexpr auto ELEMENT_SEPARATOR = ": "s;
constexpr auto LINE_SEPARATOR = "\n"s;
std::map<std::string, std::string> result;
std::size_t begin{0};
std::size_t end{0};
while (begin < sz.size()) {
// Search key
end = sz.find(ELEMENT_SEPARATOR, begin);
assert(end != std::string::npos); // Replace by error handling
auto key = sz.substr(begin, /*size=*/ end - begin);
begin = end + ELEMENT_SEPARATOR.size();
// Seach value
end = sz.find(LINE_SEPARATOR, begin);
auto value = sz.substr(begin, end == std::string::npos ? std::string::npos : /*size=*/ end - begin);
begin = (end == std::string::npos) ? sz.size() : end + LINE_SEPARATOR.size();
// Store key-value
[[maybe_unused]] auto emplaceResult = result.emplace(std::move(key), std::move(value));
assert(emplaceResult.second); // Replace by error handling
}
return result;
}
The performance of this might not be ideal, though every c++ programmer understands this code.
A very simple solution using boost is the following, it works also with partial tokens (e.g. key without values or empty pairs).
#include <string>
#include <list>
#include <map>
#include <iostream>
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace boost;
int main() {
string s = "CA: ABCD\nCB: ABFG\nCC: AFBV\nCD: 4567";
list<string> tokenList;
split(tokenList,s,is_any_of("\n"),token_compress_on);
map<string, string> kvMap;
BOOST_FOREACH(string token, tokenList) {
size_t sep_pos = token.find_first_of(": ");
string key = token.substr(0,sep_pos);
string value = (sep_pos == string::npos ? "" : token.substr(sep_pos+2,string::npos));
kvMap[key] = value;
cout << "[" << key << "] => [" << kvMap[key] << "]" << endl;
}
return 0;
}
void splitString(std::map<std::string, std::string> &mymap, const std::string &text, char sep)
{
int start = 0, end1 = 0, end2 = 0;
while ((end1 = text.find(sep, start)) != std::string::npos && (end2 = text.find(sep, end1+1)) != std::string::npos) {
std::string key = text.substr(start, end1 - start);
std::string val = text.substr(end1 + 1, end2 - end1 - 1);
mymap.insert(std::pair<std::string,std::string>(key, val));
start = end2 + 1;
}
}
For example:
std::string text = "key1;val1;key2;val2;key3;val3;";
std::map<std::string, std::string> mymap;
splitString(mymap, text, ';');
Will result in a map of size 3: { key1="val1", key2="val2", key3="val3" }
More examples:
"key1;val1;key2;" => {key1="val1"} (no 2nd val, so 2nd key doesn't count)
"key1;val1;key2;val2" => {key1="val1"} (no delim at end of the 2nd val, so it doesn't count)
"key1;val1;key2;;" => {key1="val1",key2=""} (key2 holds empty string)
Have looked through the accepted answer and tried to extend a bit which seems to work in more general cases. The test run can be found here. All kind of comments or modification are welcome.
#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <algorithm>
#include <vector>
size_t find(const std::string& line, std::vector<std::string> vect, int pos=0) {
int eol1;
eol1 = 0;
for (std::vector<std::string>::iterator iter = vect.begin(); iter != vect.end(); ++iter) {
//std::cout << *iter << std::endl;
int eol2 = line.find(*iter, pos);
if (eol1 == 0 && eol2 > 0)
eol1 = eol2;
else if (eol2 > 0 && eol2 < eol1)
eol1 = eol2;
}
return eol1;
}
std::map<std::string, std::string> mappify(std::string const& s, char delim='=') {
std::map<std::string, std::string> m;
std::string::size_type key_pos = 0, i, j;
std::string::size_type key_end;
std::string::size_type val_pos;
std::string::size_type lim_pos;
std::string::size_type val_end;
while ((key_end = s.find(delim, key_pos)) != std::string::npos) {
if ((val_pos = s.find_first_not_of(delim, key_end + 1)) == std::string::npos)break;
while (key_end - 1 > 0 && (s[key_end - 1] <= 32 || s[key_end - 1] == ';'))
key_end--;
while (val_pos < s.size() && (s[val_pos] <= 32 || s[val_pos] == ';'))
val_pos++;
val_end = s.find('\n', val_pos);
i = s.find('\"', val_pos);
if (i != std::string::npos)
j = s.find('\"', i + 1);
else
j = 0;
lim_pos = find(s.substr(0, i), { " ",";","\t" }, val_pos + 1);
//std::cout << "s.substr(j):" << s.substr(j)<<std::endl;
if (lim_pos == 0 && j != std::string::npos)lim_pos = find(s.substr(j), { " ",";","\t" }) + j;
if (lim_pos < val_pos)lim_pos = val_pos + 1;
if (j > 0)val_end = j + 1;
if (val_end > lim_pos)val_end = lim_pos;
m.emplace(s.substr(key_pos, key_end - key_pos), s.substr(val_pos, val_end - val_pos));
key_pos = val_end;
while ((key_pos < s.size() && s[key_pos] <= 32 || s[key_pos] == ';'))
++key_pos;
if (val_end == 0)break;
}
return m;
}
int main() {
std::string s ="\
File=\"c:\\dir\\ocean\\\nCCS_test.txt\"\n\
iEcho=10000; iHrShift=0 rho_Co2 = 1.15d0;\n\
Liner=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
auto m = mappify(s);
for (auto const& p : m)
std::cout << '{' << p.first << " :=> " << p.second << '}' << '\n';
return 0;
}

Getting the words from a sentence and storing them in a vector of strings

Alright, guys ...
Here's my set that has all the letters. I'm defining a word as consisting of consecutive letters from the set.
const char LETTERS_ARR[] = {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
const std::set<char> LETTERS_SET(LETTERS_ARR, LETTERS_ARR + sizeof(LETTERS_ARR)/sizeof(char));
I was hoping that this function would take in a string representing a sentence and return a vector of strings that are the individual words in the sentence.
std::vector<std::string> get_sntnc_wrds(std::string S) {
std::vector<std::string> retvec;
std::string::iterator it = S.begin();
while (it != S.end()) {
if (LETTERS_SET.count(*it) == 1) {
std::string str(1,*it);
int k(0);
while (((it+k+1) != S.end()) && (LETTERS_SET.count(*(it+k+1) == 1))) {
str.push_back(*(it + (++k)));
}
retvec.push_back(str);
it += k;
}
else {
++it;
}
}
return retvec;
}
For instance, the following call should return a vector of the strings "Yo", "dawg", etc.
std::string mystring("Yo, dawg, I heard you life functions, so we put a function inside your function so you can derive while you derive.");
std::vector<std::string> mystringvec = get_sntnc_wrds(mystring);
But everything isn't going as planned. I tried running my code and it was putting the entire sentence into the first and only element of the vector. My function is very messy code and perhaps you can help me come up with a simpler version. I don't expect you to be able to trace my thought process in my pitiful attempt at writing that function.
Try this instead:
#include <vector>
#include <cctype>
#include <string>
#include <algorithm>
// true if the argument is whitespace, false otherwise
bool space(char c)
{
return isspace(c);
}
// false if the argument is whitespace, true otherwise
bool not_space(char c)
{
return !isspace(c);
}
vector<string> split(const string& str)
{
typedef string::const_iterator iter;
vector<string> ret;
iter i = str.begin();
while (i != str.end())
{
// ignore leading blanks
i = find_if(i, str.end(), not_space);
// find end of next word
iter j = find_if(i, str.end(), space);
// copy the characters in [i, j)
if (i != str.end())
ret.push_back(string(i, j));
i = j;
}
return ret;
}
The split function will return a vector of strings, each element containing one word.
This code is taken from the Accelerated C++ book, so it's not mine, but it works. There are other superb examples of using containers and algorithms for solving every-day problems in this book. I could even get a one-liner to show the contents of a file at the output console. Highly recommended.
It's just a bracketing issue, my advice is (almost) never put in more brackets than are necessary, it's only confuses things
while (it+k+1 != S.end() && LETTERS_SET.count(*(it+k+1)) == 1) {
Your code compares the character with 1 not the return value of count.
Also although count does return an integer in this context I would simplify further and treat the return as a boolean
while (it+k+1 != S.end() && LETTERS_SET.count(*(it+k+1))) {
You should use the string steam with std::copy like so:
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <vector>
int main() {
std::string sentence = "And I feel fine...";
std::istringstream iss(sentence);
std::vector<std::string> split;
std::copy(std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>(),
std::back_inserter(split));
// This is to print the vector
for(auto iter = split.begin();
iter != split.end();
++iter)
{
std::cout << *iter << "\n";
}
}
I would use another more simple approach based on member functions of class std::string. For example
const char LETTERS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::string s( "This12 34is 56a78 test." );
std::vector<std::string> v;
for ( std::string::size_type first = s.find_first_of( LETTERS, 0 );
first != std::string::npos;
first = s.find_first_of( LETTERS, first ) )
{
std::string::size_type last = s.find_first_not_of( LETTERS, first );
v.push_back(
std::string( s, first, last == std::string::npos ? std::string::npos : last - first ) );
first = last;
}
for ( const std::string &s : v ) std::cout << s << ' ';
std::cout << std::endl;
Here you make 2 mistakes, I have correct in the following code.
First, it should be
while (((it+k+1) != S.end()) && (LETTERS_SET.count(*(it+k+1)) == 1))
and, it should move to next by
it += (k+1);
and the code is
std::vector<std::string> get_sntnc_wrds(std::string S) {
std::vector<std::string> retvec;
std::string::iterator it = S.begin();
while (it != S.end()) {
if (LETTERS_SET.count(*it) == 1) {
std::string str(1,*it);
int k(0);
while (((it+k+1) != S.end()) && (LETTERS_SET.count(*(it+k+1)) == 1)) {
str.push_back(*(it + (++k)));
}
retvec.push_back(str);
it += (k+1);
}
else {
++it;
}
}
return retvec;
}
The output have been tested.

Convert iterator to int

int i;
vector<string> names;
string s = "penny";
names.push_back(s);
i = find(names.begin(), names.end(), s);
cout << i;
I'm trying to find index of an element in vector. It's ok with iterators, but I want it as int. How can I do it?
You can use std::distance for this.
i = std::distance( names.begin(), std::find( names.begin(), names.end(), s ) );
You will probably want to check that your index isn't out of bounds, though.
if( i == names.size() )
// index out of bounds!
It's probably clearer to do this with the iterator before using std::distance, though.
std::vector<std::string>::iterator it = std::find( names.begin(), names.end(), s );
if( it == names.end() )
// not found - abort!
// otherwise...
i = std::distance( names.begin(), it );
std::vector<string>::iterator it = std::find(names.begin(), names.end(), s);
if (it != names.end()) {
std::cout << std::distance(names.begin(), it);
} else {
// ... not found
}
try
i = (find( names.begin(), names.end(), s ) - names.begin());
Edit:
Although you should consider using vector::size_type instead of an int.
Assumptions that I am making about your code:
using std::vector;
using std::cout;
using std::string;
If my assumptions are correct, then you can find the distance between the beginning of the vector and the iterator (essentially the index into the vector at which you can find such element):
using std::distance;
Like so...
vector<string>::iterator i = find(names.begin(), names.end(), s);
if (i != names.end())
{
cout << "Index " << std::distance(names.begin(), i);
}
else
{
cout << s << "not found";
}
You can just dereference your iterator
int i = *name;