Regular expressions question - c++

I've got the following string :
const std::string args = "cmdLine=\"-d ..\\data\\configFile.cfg\" rootDir=\"C:\\abc\\def\""; // please note the space after -d
I'd like to split it into 2 substrings :
std::str1 = "cmdLine=...";
and
std::str2 = "rootDir=...";
using boost/algorithm/string.hpp . I figured, regular expressions would be best for this but unfortunately I have no idea how to construct one therefore I needed to ask the question.
Anyone capable of helping me out with this one?

To solve problem from your question the easiest way is to use strstr to find substring in string, and string::substr to copy substring. But if you really want to use Boost and regular expressions you could make it as in the following sample:
#include <boost/regex.hpp>
...
const std::string args = "cmdLine=\"-d ..\\data\\configFile.cfg\" rootDir=\"C:\\abc\\def\"";
boost::regex exrp( "(cmdLine=.*) (rootDir=.*)" );
boost::match_results<string::const_iterator> what;
if( regex_search( args, what, exrp ) ) {
string str1( what[1].first, what[1].second ); // cmdLine="-d ..\data\configFile.cfg"
string str2( what[2].first, what[2].second ); // rootDir="C:\abc\def"
}

Code samples
char *cstr1 = (char*)args.c_str();
char *cstr2 = strstr(cstr1, "=\""); cstr2 = strstr(cstr2, "=\"); // rootDir="
cstr2 = strrchr(cstr2, ' '); // space between " and rootDir
*cstr2++ = '\0';
//then save to your strings
std::string str1 = cstr1;
std::string str2 = cstr2;
that's all.
Notes:
Above code supports these strings
"cmdLine=\"-d ..\\data\\configFile.cfg\" rootDir=\"C:\\abc\\def\"" or
"ABCwhatever=\"-d ..\\data\\configFile.cfg\" XYZ=\"C:\\abc\\def\""

Related

C++ regex search specific chinese pattern

I need to regex search specific chinese pattern from C++ string
For example I have a source string "什么手机好" and a pattern "什么(.*)好"
I use boost::regex_search and wstring to do this , but there is something wrong
when the search string has english or number, the code doesn't work, for example , source string is "abc什么efg手机好" pattern is "什么(.*)好", the code do ACT2. And source string is "" (empty string) pattern is "什么(.*)好" , the code do ACT1
I want to know how to fix it.
func
std::wstring string2wstring(const std::string& s) {
setlocale(LC_CTYPE, "");
int iWLen = std::mbstowcs(NULL, s.c_str(), s.length());
wchar_t *lpwsz= new wchar_t[iWLen + 1];
std::mbstowcs(lpwsz, s.c_str(), s.length());
std::wstring wstrResult(lpwsz);
delete []lpwsz;
return wstrResult;
}
std::wstring ws = string2wstring(s);
boost::wregex wpattern(string2wstring(pattern));
if (boost::regex_search(ws, wpattern) == true) {
do ACT1;
} else {
do ACT2;
}
It is embarrassed that I needn't use wstring to deal chinese regex.
Just making query and pattern gbk-string can fix it.
boost::regex_search(query,pattern)

Boost::xpressive regex_search concatenate matches in a single string

I want to concatenate all matches found by regex_search into a single string, and then return it. I tried doing it with std::accumulate, but failed.
Is there a way to return something like std::accumulate(what.begin()+1, what.end(), someFunc)?
I'm not very familiar with functional programming. I know that I can make a for loop that adds strings together, but I want to try doing it otherwise. Thanks in advance!
Here is a pseudo-code snippet that might help you better understand what I want to do.
std::string foo(const std::string& text)
{
using namespace boost::xpressive;
sregex srx = +_d >> as_xpr("_") >> +_d; // some random regex
smatch what;
if (regex_search(filename, what, srx))
{
// Here I want to return a string,
// concatenated from what[1].str() + what[2].str() + ... + what[n].str();
// How do I do this?
// What about what[1].str() + "-" + what[2].str()...?
}
return std::string();
}

How do I replace the extensions of filenames using regex in c++?

I would like to replace the file extensions from .nef to .bmp. How do I do it using regex?
My code is something like -
string str("abc.NEF");
regex e("(.*)(\\.)(N|n)(E|e)(F|f)");
string st2 = regex_replace(str, e, "$1");
cout<<regex_match (str,e)<<"REX:"<<st2<<endl;
regex_match (str,e) gets me a hit, but st2 turns out blank. I am not very familiar with regex, but I expected to have something appear in st2. What I am doing wrong?
try this.
it will match .NEF or .nef
string str("abc.NEF");
regex e(".*(\.(NEF)|\.(nef))");
string st2 = regex_replace(str,e,"$1");
$1 will capture .NEF or .nef
check here
Try this
string test = "abc.NEF";
regex reg("\.(nef|NEF)");
test = regex_replace(test, reg, "your_string");
I suggest not to use regex for such a simple task.
Try this function:
#include <string>
#include <algorithm>
std::string Rename(const std::string& name){
std::string newName(name);
static const std::string oldSuffix = "nef";
static const std::string newSuffix = "bmp";
auto dotPos = newName.rfind('.');
if (dotPos == newName.size() - oldSuffix.size() - 1){
auto suffix = newName.substr(dotPos + 1);
std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower);
if (suffix == oldSuffix)
newName.replace(dotPos + 1, std::string::npos, newSuffix);
}
return newName;
}
At first we find a delimiter position, then fetching the whole file extension (suffix), converting it to lower case and compare to oldSuffix.
Of course you can set oldSuffix and newSuffix to be arguments, not static consts.
Here is a test program: http://ideone.com/D09NVL
I think boost offers the simplest and most readable solution with
auto result = boost::algorithm::ireplace_last_copy(input, ".nef", ".bmp");
I think this
string str("abc.NEF");
regex e("(.*)\\.[Nn][Ee][Ff]$");
string st2 = regex_replace(str, e, "$1.bmp");
cout<<regex_match(str, e)<<"REX:"<<st2<<endl;
will work out better for you.

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>

Converting boost std::string::const_iterator to string and int 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().