Converting boost std::string::const_iterator to string and int c++ - c++

I need to convert const_iterator into a type that I can do int and string operations to.
results[1] contains the text from the regex_search that I need to work with.
I've spent a couple hours already trying cast into a workable format, no success...
boost::match_results<std::string::const_iterator> results;
boost::regex ex(pattern, boost::regex::perl);
if(boost::regex_search(line, results, ex))
(results[1] > 10) ? cout << "Fail" : cout << "Pass";
Thanks,
Joe

You could create an std::string out of a match result of const string iterators like this:
std::string result_string( results[1].first, results[1].second );
...or simply:
std::string result_string = results[1].str();
You can coerce the string to an int like this:
int result_int = boost::lexical_cast< int >( result_string );
...or, as pointed by #Jonathan Wakely, if you are using C++11:
int result_int = std::stoi( result_string );

results[1].first is an iterator that points to the beginning of the text that matched; results[1].second is an iterator that points past the end of the text that matched. Use this pair of iterators to access individual characters in the match. If you just want a string object that holds a copy of the matched text, use results[1].str().

Related

How to get letter from String by index? C++

Can someone briefly explain how to get a character from index from String in C++.
I need to read the first 3 letters of a String and in java it would bestr.charAt(index) and I have been searching the internet for a solution for 2h now and still don't understand...
can some one please give me an example.
std::string provides operator[] to access a character by index:
https://en.cppreference.com/w/cpp/string/basic_string/operator_at
Example:
const std::string s("hello");
const char c = s[0];
// c is set to ‘h’
substr()
It returns a newly constructed string object with its value initialized to a copy of a substring of this object.
Syntax
substr(pos, pos+len)
Code
std::string str ("Test string"); //string declaration
string sub_string = str.substr(0,3);
String index starts from 0.
Best place to look would be cpluspluc.com: http://www.cplusplus.com/reference/string/string/
You may use as earlier mentioned: http://www.cplusplus.com/reference/string/string/operator[]/
std::string str ("Test string");
for (int i=0; i<str.length(); ++i)
{
std::cout << str[i];
}
Or better yet: http://www.cplusplus.com/reference/string/string/at/
std::cout << str.at(i);
which also checks for a valid position and throws an out of range exception otherwise.
Alternatively you could use http://www.cplusplus.com/reference/string/string/data/
to acces the raw data.
Or if you want to check that your string starts with a specific pattern: http://www.cplusplus.com/reference/string/string/rfind/
std::string str = "Hey Jude!";
if (str.rfind("Hey", 0) == 0) {
// match
}
Another option to obtain a single character is to use the std::string::at() member function. To obtain a substring of a certain length, use the std::string::substr member function.

C++ regex replace whole word

I have a small game to do in which I need to sometimes replace some group of characters with the name of the player in the sentences.
For example, I could have a sentence like :
"[Player]! Are you okay? A plane crash happened, it's on fire!"
And I need to replace the "[Player]" with some name contained in a std::string.
I have been looking for about 20 minutes in other SO questions and in the CPP reference and I really can't understand how to use the regex.
I would like to know how I can replace all instances of the "[Player]" string in a std::string.
Personally I would not use regex for this. A simple search and replace should be enough.
These are (roughly) the functions I use:
// change the string in-place
std::string& replace_all_mute(std::string& s,
const std::string& from, const std::string& to)
{
if(!from.empty())
for(std::size_t pos = 0; (pos = s.find(from, pos) + 1); pos += to.size())
s.replace(--pos, from.size(), to);
return s;
}
// return a copy of the string
std::string replace_all_copy(std::string s,
const std::string& from, const std::string& to)
{
return replace_all_mute(s, from, to);
}
int main()
{
std::string s = "[Player]! Are you okay? A plane crash happened, it's on fire!";
replace_all_mute(s, "[Player]", "Uncle Bob");
std::cout << s << '\n';
}
Output:
Uncle Bob! Are you okay? A plane crash happened, it's on fire!
Regex is meant for more complex patterns. Consider, for example, that instead of simply matching [Player], you wanted to match anything between brackets. That would be a good use for regex.
Following is an example that does just that. Unfortunately, the interface of <regex> is not flexible enough to enable dynamic replacements, so we have to implement the actual replacing ourselves.
#include <iostream>
#include <regex>
int main() {
// Anything stored here can be replaced in the string.
std::map<std::string, std::string> vars {
{"Player1", "Bill"},
{"Player2", "Ted"}
};
// Matches anything between brackets.
std::regex r(R"(\[([^\]]+?)\])");
std::string str = "[Player1], [Player1]! Are you okay? [Player2] said that a plane crash happened!";
// We need to keep track of where we are, or else we would need to search from the start of
// the string everytime, which is very wasteful.
// std::regex_iterator won't help, because the replacement may be smaller
// than the match, and it would cause strings like "[Player1][Player1]" to not match properly.
auto pos=str.cbegin();
do {
// First, we try to get a match. If there's no more matches, exit.
std::smatch m;
regex_search(pos, str.cend(), m, r);
if (m.empty()) break;
// The interface of std::match_results is terrible. Let's get what we need and
// place it in apropriately named variables.
auto var_name = m[1].str();
auto start = m[0].first;
auto end = m[0].second;
auto value = vars[var_name];
// This does the actual replacement
str.replace(start, end, value);
// We update our position. The new search will start right at the end of the replacement.
pos = m[0].first + value.size();
} while(true);
std::cout << str;
}
Output:
Bill, Bill! Are you okay? Ted said that a plane crash happened!
See it live on Coliru
Simply find and replace, e.g. boost::replace_all()
#include <boost/algorithm/string.hpp>
std::string target(""[Player]! Are you okay? A plane crash happened, it's on fire!"");
boost::replace_all(target, "[Player]", "NiNite");
As some people have mentioned, find and replace might be more useful for this scenario, you could do something like this.
std::string name = "Bill";
std::string strToFind = "[Player]";
std::string str = "[Player]! Are you okay? A plane crash happened, it's on fire!";
str.replace(str.find(strToFind), strToFind.length(), name);

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>

How to get a basic preg_match_all replacement for std::string in C++?

with "basic" is meant: Only the operators "+" (->following..) and "|" (->or) are needed.
Prototype:
preg_match_all(std::string pattern, std::string subject, std::vector<std::string> &matches)
Usage Example:
std::vector<std::string> matches;
std::string pattern, subject;
subject = "Some text with a lots of foo foo and " + char(255) + " again " + char(255);
pattern = "/" + char(255) + char(255) + "+|foo+/";
preg_match_all(pattern, subject, matches);
The matches should be available afterwardsa via matches[n]. Someone got a hint without using boost and/or PCRE? If not, how I got this realized with boost?
This will return a vector of all matches an the index they were found at.
std::vector<std::pair<std::string, unsigned int>> RegexPP::MatchAll(std::string pattern, std::string haystack) {
std::vector<std::pair<std::string, unsigned int>> matches;
std::regex p(pattern);
std::sregex_iterator start(haystack.begin(), haystack.end(), p), end;
for(; start != end; start++) {
auto match = *start; // dereference the iterator to get the match_result
matches.push_back(std::pair<std::string, unsigned int>(match.str(), match.position()));
}
return matches;
}
You could rollup something using std::string::find, doing matches via a functor, and pushing the results onto a string vector.
The way it's realized in boost is probably overkill for what you want -- you first would need to decompose the expression into lexems and then compile a state machine for parsing the given regexp.
Look into Boost.Regex, http://www.boost.org/doc/libs/1_41_0/libs/regex/doc/html/index.html