Find a string in a vector in c++ - c++

I have a vector of string , and I want to return a string from vector which is similar to a string.
For example vector contains: "load", "fox", "google", "firefox" and the string is: "mozilla firefox". The true result in this sample is "firefox".
I use the code below, but it is wrong and returns "fox" for my sample.
vector<string>::const_iterator it_found = find_if(MyVector.begin(), MyVector.end(), [&MyString](string s) -> bool
{ return( MyString.find(s) != string::npos ); });
if(it_found != MyVector.end())
{
//Do Somthing
}
What should I do?

You are returning the first string that is a substring of your search term. It seems you want the best match, so a more sophisticated approach is needed. You could calculate some score how good the match is and find the element that gives the maximum score, e.g. with std::max_element
The score could be simply the length of the matched substring or something more complicated if you later improve your matching algorithm.

You can split the input string on whitespace using this implementation of split returning a std::vector<std::string>.
std::vector<std::string> split(std::string const &input) {
std::istringstream buffer(input);
std::vector<std::string> ret((std::istream_iterator<std::string>(buffer)),
std::istream_iterator<std::string>());
return ret;
}
Then compare each string in MyVector with the candidates from the returned vector from split.
std::string MyString = "mozzilla firefox";
std::vector<std::string> MyVector = {"fire", "fox", "firefox", "mozilla"};
auto candidates = split(MyString);
auto it_found = std::find_if(MyVector.begin(), MyVector.end(), [&candidates](std::string s) -> bool{
return (std::find(candidates.begin(), candidates.end(), s) != candidates.end());
});
if(it_found != MyVector.end()){
std::cout<<"\nFound : "<<*it_found;
}
Output :
Found : firefox
Note that this only finds the first match of strings in MyVectorwith a string in the candidates.

Related

How to find certain substring in string and then go back to certain character?

I save messages in string and I need to make filter function that finds user specified word in those messages. I've split each message by '\n' so the example of one chat would be:
user1:Hey, man\nuser2:Hey\nuser1:What's up?\nuser2:Nothing, wbu?\n etc.
Now user could ask to search for word up and I've implemented a search like this:
for (auto it = msg.cbegin(); (it = std::find(it, msg.cend(), str)) != msg.cend(); it++)
and I could put that string into stringstream and use getline to \n, but how do I go backwards to previous \n so I can get full message? Also, what about first message, cause it doesn't start with \n?
Since you said you split the strings, I image you have a vector of strings where you want to find up for example. You would do something like this
for (const auto& my_string: vector_of_strings){
if (my_string.find("up") != string::npos) {
// message containing up is my_string
}
}
In case you haven't split the strings in a vector you can use this func inspired by this:
vector<string> split(const string& s, const string& delimiter){
vector<string> ret;
size_t last = 0;
size_t next = 0;
while ((next = s.find(delimiter, last)) != string::npos) {
ret.emplace_back(s.substr (last, next - last));
last = next + 1;
}
ret.emplace_back(s.substr(last));
return ret;
}
If this function doesn't work you can always take a look at How do I iterate over the words of a string?

How to create a function to extract field in string inside of vector? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
i want to make a function like this.
using namespace std;
vector<string> hj;
vector<string> feldseperator(const string& s, char delimiter) {
size_t pos = 0;
string token;
while ((pos = s.find(delimiter)) != string::npos)
{
token = s.substr(0, pos);
cout << token << endl;
hj.push_back(token);
s.erase(); // I WANT TO DELETE THE FIRST FIELD + CHAR
}
return hj;
}
int main()
{
string s = "dog;cat;fish;fax;fox;fast;";
char f = ';';
feldseperator(s, f);
cin.get();
}
Ah, I see, you're trying to break string on basis of delimiters. Your problem is you want to remove prefix of string uptil first occurrence of delimiter - as stated by comment in your code. So, you could:
Use second param of std::find, which is "Position of the first character in the string to be considered in the search" and update your code like this:
size_t last_pos = 0 , pos = 0;
while ((pos = s.find(delimiter , last_pos)) != string::npos)
{
token = s.substr(last_pos, pos - last_pos);
last_pos = pos + 1; //pos is position of delimiter, you want next search to begin from character which comes after delimiter.
..
}
Since you already have position of delimiter, you can reinitialize string s as s = s.substr(pos+1 , s.size() - pos ) but then you'd have to removes const keyword, making option 1 a better choice.
Try this,
According to std::erase (overload 3), it deletes in the range [first, last) hence the +1.
using namespace std;
vector<string> hj;
vector<string> feldseperator(const string& s, char delimiter) {
auto copy = s;
size_t pos = 0;
string token;
while ((pos = copy.find(delimiter)) != string::npos)
{
token = s.substr(0, pos);
cout << token << endl;
hj.push_back(token);
copy.erase(copy.begin(), copy.begin()+pos+1); // I WANT TO DELETE THE FIRST FIELD + CHAR
}
return hj;
}
int main()
{
string s = "dog;cat;fish;fax;fox;fast;";
char f = ';';
feldseperator(s, f);
cin.get();
}
Note that I'm passing a copy of the string, and not a reference. You may want to change that as required.
So, as I understand, you want to split a string that contains substrings, delimited by a ";". This process is called tokenizing. Becuase you want to split a string into smaller tokens.
Modern C++ has a build in functionaliyt which is exactly designed for that purpose. It is called std::sregex_token_iterator. What is this thing?
As it name says, it is an iterator. It will iterate over a string (hence the 's' in its name) and return the split up tokens. The tokens will be matched again a regular expression. Or, nagtively, the delimiter will be matched and the rest will be seen as token and returned. This will be controlled via the last flag in its constructor.
Let's have a look at this constructor:
hj(std::sregex_token_iterator(s.begin(), s.end(), delimiter, -1), {});
The first parameter is, where it should start in the source string, the 2nd parameter is the end position, up to which the iterator should work. The lase parameter is:
1, if you want to have a positive match for the regex
-1, will return everything that not matches the regex
And last but not least the regex itself. Please read in the net abot regex'es. There are tons of pages available.
So, then we check the one liner for the field extraction.
std::vector<std::string> hj(std::sregex_token_iterator(s.begin(), s.end(), delimiter, -1), {});
What is that. The first is obvious. We define a std::vector<std::string>> with the name "hj". As possible with any variable definition, we will call a constructor, to construct the std::vector<std::string>>.
If you look in std::vector range constructor (no 5), you will see that we can initialize the vector, with a other iterator (begin and end), and copy the values from there. The begin iterator is given and the end iterator is given automatically with {}, because the empty constructor for the std::sregex_token_iterator is equal to its "end()".
That's it, everything done with a one-liner.
Please see:
#include <iostream>
#include <iterator>
#include <regex>
#include <string>
#include <vector>
int main() {
// The string to split
std::string s("dog;cat;fish;fax;fox;fast;");
// The delimiter
std::regex delimiter(";");
// Tokenize and store result in vector
std::vector<std::string> hj(std::sregex_token_iterator(s.begin(), s.end(), delimiter, -1), {});
std::cin.get();
}
Byt the way, if you have an existing vector, then you can copy the result into that vector:
std::copy(std::sregex_token_iterator(s.begin(), s.end(), delimiter, -1), {}, std::back_inserter(hj));
I hope that you can see the simplicity of that approach.
Of course there are many other possible solutions, and everybdoy can select whatever he wants.

Manipulating specific position in string according to one another

I have a string which has different city names. The format like this :
string cities = "-Paris-Berlin-Cologne-"
And also there is another string which contains some voting results for these cities.
string vote = "-31.2-42.5-40-"
I need to define a function which takes input from user for ex : Berlin
Then function will find and change the result of vote in "string vote"
I tried with counting "-" separators but I couldn't succeed.
Any help would appreciate.
Thank you.
Split both strings at the separators and put the results in a map
std::vector<std::string> split(std::string const& s, std::string const& sep);
std::vector<std::string> const c = split(cities, "-");
std::vector<std::string> const v = split(votes, "-");
// now put them all in a map
assert(c.size() == v.size());
std::map<std::string, float> city2vote;
for (std::vector<std::string>::size_type i=0; i != c.size(); ++i)
{
city2vote[c[i]] = atof(v[i]);
}
// update vote for Berlin
city2vote["Berlin"] = 42.0;
The split function is strait forward, but Boost also provides an implementation if you can use libraries. I used atof for simplicity. In real life, a stringstream would be a much better choice.
Would using a regex search to find the positions in the string of the hyphens, then changing the values between those positions accordingly be an acceptable solution?
Edit - On second thoughts, you needn't overcomplicate things by using regex, you could just use a for loop to scan through the string
First I think you should map each delimited string from cities to vote. You can do it like this:
std::map<std::string, std:string> city_to_vote;
std::istringstream i1(cities), i2(vote);
for (std::string str1, str2; std::getline(i1, str1, '-') &&
std::getline(i2, str2, '-'); )
{
if (!str1.empty() && !str2.empty())
{
city_to_vote.emplace(std::make_pair(str1, str2));
}
}
Then once you receive string input from the user, check if it is inside the map, access the value that it is mapped to, and use a replace algorithm to augment the vote string.

C++ Get String between two delimiter String

Is there any inbuilt function available two get string between two delimiter string in C/C++?
My input look like
_STARTDELIMITER_0_192.168.1.18_STOPDELIMITER_
And my output should be
_0_192.168.1.18_
Thanks in advance...
You can do as:
string str = "STARTDELIMITER_0_192.168.1.18_STOPDELIMITER";
unsigned first = str.find(STARTDELIMITER);
unsigned last = str.find(STOPDELIMITER);
string strNew = str.substr (first,last-first);
Considering your STOPDELIMITER delimiter will occur only once at the end.
EDIT:
As delimiter can occur multiple times, change your statement for finding STOPDELIMITER to:
unsigned last = str.find_last_of(STOPDELIMITER);
This will get you text between the first STARTDELIMITER and LAST STOPDELIMITER despite of them being repeated multiple times.
I have no idea how the top answer received so many votes that it did when the question clearly asks how to get a string between two delimiter strings, and not a pair of characters.
If you would like to do so you need to account for the length of the string delimiter, since it will not be just a single character.
Case 1: Both delimiters are unique:
Given a string _STARTDELIMITER_0_192.168.1.18_STOPDELIMITER_ that you want to extract _0_192.168.1.18_ from, you could modify the top answer like so to get the desired effect. This is the simplest solution without introducing extra dependencies (e.g Boost):
#include <iostream>
#include <string>
std::string get_str_between_two_str(const std::string &s,
const std::string &start_delim,
const std::string &stop_delim)
{
unsigned first_delim_pos = s.find(start_delim);
unsigned end_pos_of_first_delim = first_delim_pos + start_delim.length();
unsigned last_delim_pos = s.find(stop_delim);
return s.substr(end_pos_of_first_delim,
last_delim_pos - end_pos_of_first_delim);
}
int main() {
// Want to extract _0_192.168.1.18_
std::string s = "_STARTDELIMITER_0_192.168.1.18_STOPDELIMITER_";
std::string s2 = "ABC123_STARTDELIMITER_0_192.168.1.18_STOPDELIMITER_XYZ345";
std::string start_delim = "_STARTDELIMITER";
std::string stop_delim = "STOPDELIMITER_";
std::cout << get_str_between_two_str(s, start_delim, stop_delim) << std::endl;
std::cout << get_str_between_two_str(s2, start_delim, stop_delim) << std::endl;
return 0;
}
Will print _0_192.168.1.18_ twice.
It is necessary to add the position of the first delimiter in the second argument to std::string::substr as last - (first + start_delim.length()) to ensure that the it would still extract the desired inner string correctly in the event that the start delimiter is not located at the very beginning of the string, as demonstrated in the second case above.
See the demo.
Case 2: Unique first delimiter, non-unique second delimiter:
Say you want to get a string between a unique delimiter and the first non unique delimiter encountered after the first delimiter. You could modify the above function get_str_between_two_str to use find_first_of instead to get the desired effect:
std::string get_str_between_two_str(const std::string &s,
const std::string &start_delim,
const std::string &stop_delim)
{
unsigned first_delim_pos = s.find(start_delim);
unsigned end_pos_of_first_delim = first_delim_pos + start_delim.length();
unsigned last_delim_pos = s.find_first_of(stop_delim, end_pos_of_first_delim);
return s.substr(end_pos_of_first_delim,
last_delim_pos - end_pos_of_first_delim);
}
If instead you want to capture any characters in between the first unique delimiter and the last encountered second delimiter, like what the asker commented above, use find_last_of instead.
Case 3: Non-unique first delimiter, unique second delimiter:
Very similar to case 2, just reverse the logic between the first delimiter and second delimiter.
Case 4: Both delimiters are not unique:
Again, very similar to case 2, make a container to capture all strings between any of the two delimiters. Loop through the string and update the first delimiter's position to be equal to the second delimiter's position when it is encountered and add the string in between to the container. Repeat until std::string:npos is reached.
To get a string between 2 delimiter strings without white spaces.
string str = "STARTDELIMITER_0_192.168.1.18_STOPDELIMITER";
string startDEL = "STARTDELIMITER";
// this is really only needed for the first delimiter
string stopDEL = "STOPDELIMITER";
unsigned firstLim = str.find(startDEL);
unsigned lastLim = str.find(stopDEL);
string strNew = str.substr (firstLim,lastLim);
//This won't exclude the first delimiter because there is no whitespace
strNew = strNew.substr(firstLim + startDEL.size())
// this will start your substring after the delimiter
I tried combining the two substring functions but it started printing the STOPDELIMITER
Hope that helps
Hope you won't mind I'm answering by another question :)
I would use boost::split or boost::split_iter.
http://www.boost.org/doc/libs/1_54_0/doc/html/string_algo/usage.html#idp166856528
For example code see this SO question:
How to avoid empty tokens when splitting with boost::iter_split?
Let's say you need to get 5th argument (brand) from output below:
zoneid:zonename:state:zonepath:uuid:brand:ip-type:r/w:file-mac-profile
You cannot use any "str.find" function, because it is in the middle, but you can use 'strtok'. e.g.
char *brand;
brand = strtok( line, ":" );
for (int i=0;i<4;i++) {
brand = strtok( NULL, ":" );
}
This is a late answer, but this might work too:
string strgOrg= "STARTDELIMITER_0_192.168.1.18_STOPDELIMITER";
string strg= strgOrg;
strg.replace(strg.find("STARTDELIMITER"), 14, "");
strg.replace(strg.find("STOPDELIMITER"), 13, "");
Hope it works for others.
void getBtwString(std::string oStr, std::string sStr1, std::string sStr2, std::string &rStr)
{
int start = oStr.find(sStr1);
if (start >= 0)
{
string tstr = oStr.substr(start + sStr1.length());
int stop = tstr.find(sStr2);
if (stop >1)
rStr = oStr.substr(start + sStr1.length(), stop);
else
rStr ="error";
}
else
rStr = "error"; }
or if you are using Windows and have access to c++14, the following,
void getBtwString(std::string oStr, std::string sStr1, std::string sStr2, std::string &rStr)
{
using namespace std::literals::string_literals;
auto start = sStr1;
auto end = sStr2;
std::regex base_regex(start + "(.*)" + end);
auto example = oStr;
std::smatch base_match;
std::string matched;
if (std::regex_search(example, base_match, base_regex)) {
if (base_match.size() == 2) {
matched = base_match[1].str();
}
rStr = matched;
}
}
Example:
string strout;
getBtwString("it's_12345bb2","it's","bb2",strout);
getBtwString("it's_12345bb2"s,"it's"s,"bb2"s,strout); // second solution
Headers:
#include <regex> // second solution
#include <string.h>

C++ find a sentence in list<word>

I'm trying to find an elegant way to find some text ex. "hello world" from the sentence "I compiled my first hello world. It works!"
But the sentence is a std::list<word> with some metadata.
Class Word
{
std::string m_word;
Location ... (X,Y in a picture)
....
}
Just wondering if there is nice way to do that with some std or boost functions rather than my 2 ugly loops. Thanks!
You can use std::search together with a custom predicate that only compares the m_word member:
bool wordsEqual(const Word& a, const Word& b) {
return a.getWord() == b.getWord();
}
// ...
Word needle[] = { "hello", "world" };
list<Word>::iterator it = search(lst.begin(), lst.end(),
needle, needle + 2,
wordsEqual);
This code assumes a getWord method and a constructor Word(const char*) for the array initialization.
You can look into std::search.
string pattern[] = {"hello","world"};
list<string>::iterator it = search(x.begin(),x.end(), pattern, pattern + 1);
Where x is your list. You'll probably have to provide your own binary predicate.