I have a problem with boost::replace_all. My string looks like:
""Date"":1481200838,""Message"":""
And I would like it to look like:
"Date":1481200838,"Message":"
So i would like to replace "" with single ":
boost::replace_all(request_json_str, """", """);
But it doesn't work at all. Same with:
boost::replace_all(request_json_str, "\"\"", "\"");
How could I make this to work?
You need to correctly escape the " character in your call to boost::replace_all!
// Example program
#include <iostream>
#include <string>
#include <algorithm>
#include <boost/algorithm/string/replace.hpp>
int main()
{
std::string msg("\"Date\"\":1481200838,\"\"Message\"\":\"");
boost::replace_all(msg, "\"\"", "\"");
std::cout << msg << std::endl;
}
The boost::replace_all(request_json_str, "\"\"", "\"") already in your answer is the correct way to handle this using boost::replace_all: http://coliru.stacked-crooked.com/a/af7cbc753e16cf4f
I wanted to post an additional answer to say that given auto request_json_str = "\"\"Date\"\":1481200838,\"\"Message\"\":\"\""s the repeated quotations could also be removed without Boost (though not quite so eloquently, using unique, distance, and string::resize):
request_json_str.resize(distance(begin(request_json_str), unique(begin(request_json_str), end(request_json_str), [](const auto& a, const auto& b){ return a == '"' && b == '"'; })));
Related
#include <iostream>
#include <iterator>
#include <regex>
#include <string>
std::string ty(std::string text){
if(text == "brown")
return "true";
else
return "qw";
}
int main()
{
std::string text = "Quick $brown fox";
std::cout << '\n' << std::regex_replace(text, std::regex(R"(\\$(.*))"), ty("$&")) << '\n';
}
i use c++11 . I try without if worked but with if don't work ? i don't know what to do
There's a lot of different things wrong with the original code.
Firstly here's some working code
#include <iostream>
#include <iterator>
#include <regex>
#include <string>
std::string ty(std::string text){
if(text == "brown")
return "true";
else
return "qw";
}
int main()
{
std::string text = "Quick $brown fox";
std::smatch m;
if (std::regex_search(text, m, std::regex(R"(\$([[:alpha:]][[:alnum:]]*))")))
{
std::cout << '\n' << ty(std::string(m[1].first, m[1].second)) << '\n';
}
else
{
std::cout << "\nno match\n";
}
}
Some things that were wrong with the original code
Firstly the function being called was wrong. Use std::regex_search to search for matches in a string. Capture the results in an std::smatch object and then use those results to call the ty function.
The regex was wrong in two different ways. Firstly \\ is wrong because you are using a raw string literal, so only a single backslash is required. Secondly (.*) is wrong because that will match the entire rest of the string. You only want to match the word following the dollar. I've used ([[:alpha:]][[:alnum:]]*) instead. That might not be exactly what you want but it works for this example. You can modify it if you want.
I have a string of the form:
http://stackoverflow.com/q""uestions/ask/%33854#/á
Now I want to delete all characters from this string except alphnumeric and ://.So that the output string becomes:
http://stackoverflow.com/questions/ask/33854/á
I know I can traverse this string character by character and remove unnecessary characters. But is there some function in some standard library which may help me remove unwanted characters. If i know the unwanted characters then I can use std::remove and std::replace to selectively remove or replace. But here I do not know the unknown characters, I only know the characters which I want to retain.
Is there some way by which I may retain only the necessary characters and remove the unwanted characters.
gcc version which I am using is:
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)
EDIT: I also want to include characters like á. I dont know what they are called. I know they are not alph-numeric. But I am not getting how to check for them
Since your compiler is ancient and regex support is relatively recent in gcc (from gcc 4.9 forward), regexes are not an option. We'll use the erase-remove idiom, with a named function because Gcc 4.4 does not yet support lambdas.
#include <algorithm>
#include <iostream>
#include <locale>
#include <string>
// true for characters that should be removed
bool is_special_character(char c) {
std::locale loc("your_locale_string_here");
return !std::isalnum(c, loc) && c != ':' && c != '/' && c != '.';
}
int main()
{
std::string s = "http://stackoverflow.com/q\"\"uestions/ask/%33854#";
// interesting part here
s.erase(std::remove_if(s.begin(), s.end(), is_special_character), s.end());
std::cout << s << '\n';
}
You will want to use std::remove_if and define a predicate to return false only if the characters are the ones you want to retain.
You'll also want to resize the string to the new length after you do this process. As an example:
#include <string>
#include <algorithm>
#include <iostream>
#include <locale>
bool is_special_char(char c)
{
return !( std::isalnum(c) || c == ':' || c == '/' || c == '.');
}
int main()
{
std::string s = "http://stackoverflow.com/q\"\"uestions/ask/\%33854#";
std::cout << s << std::endl;
std::string::iterator new_end = std::remove_if(s.begin(), s.end(), is_special_char);
s.resize(new_end - s.begin());
std::cout << s << std::endl;
}
will output
http://stackoverflow.com/q""uestions/ask/%33854#
http://stackoverflow.com/questions/ask/33854
If you want to incorporate unicode characters you need to use a wstring instead of a string, an example using this (and incorporating Wintermute's nice use of the erase/remove idiom) would be.
#include <string>
#include <algorithm>
#include <iostream>
#include <locale>
bool is_special_char(wchar_t c)
{
return !( std::iswalnum(c) || c == ':' || c == '/' || c == '.');
}
int main()
{
std::locale::global( std::locale("en_US.UTF-8") ); //Set the global locale to Unicode
std::wstring s = L"http://stáckoverflow.com/q\"\"uestions/ask/%33854#";
std::wcout << s << std::endl;
s.erase( std::remove_if(s.begin(), s.end(), is_special_char), s.end() );
std::wcout << s << std::endl;
}
which will output
http://stáckoverflow.com/q""uestions/ask/%33854#
http://stáckoverflow.com/questions/ask/33854
But here I do not know the unknown characters, I only know the characters which I want to retain.
Whitelist the characters you want to retain using a char array for example. Then run through each character in your string and remove it if it isn't in the whitelist.
You could try something like that :
std::string str ("This is an example sentence.");
std::cout << str << '\n';
// "This is an example sentence."
str.erase (10,8); // ^^^^^^^^
std::cout << str << '\n';
// "This is an sentence."
str.erase (str.begin()+9); // ^
std::cout << str << '\n';
// "This is a sentence."
str.erase (str.begin()+5, str.end()-9); // ^^^^^
std::cout << str << '\n';
// "This sentence."
The function template boost::algorithm::split_regex splits a single string into strings on the substring of the original string that matches the regex pattern we passed to split_regex. The question is: how can I split it only once on the first substring that matches? That is, is it possible to make split_regex stop after its first splitting? Please see the following codes.
#include <boost/algorithm/string/regex.hpp>
#include <boost/format.hpp>
#include <boost/regex.hpp>
#include <iostream>
#include <locale>
int main(int argc, char *argv[])
{
using namespace std;
using boost::regex;
locale::global(locale(""));
// Create a standard string for experiment.
string strRequestLine("Host: 192.168.0.1:12345");
regex pat(R"(:\s*)", regex::perl | boost::regex_constants::match_stop);
// Try to split the request line.
vector<string> coll;
boost::algorithm::split_regex(coll, strRequestLine, pat);
// Output what we got.
for (const auto& elt : coll)
cout << boost::format("{%s}\n") % elt;
// Exit the program.
return 0;
}
Where shall the codes be modified to have the output like
{Host}
{192.168.0.1:12345}
instead of the current output
{Host}
{192.168.0.1}
{12345}
Any suggestion/hint? Thanks.
Please note that I'm not asking how to do it with other functions or patterns. I'm asking if it's possible for split_regex to split only once and then stop. Because regex object seems to have the ability to stop at the first matched, I wonder that if offering it some proper flags it maybe stop at the first matched.
For your specific input it seems the simple fix is to change the pattern to become R"(:\s+)". Of course, this assumes that there is, at least, one space after Host: and no space between the IP address and the port.
Another alternative would be not to use split_regex() but rather std::regex_match():
#include <iostream>
#include <regex>
#include <string>
int main()
{
std::string strRequestLine("Host: 192.168.0.1:12345");
std::smatch results;
if (std::regex_match(strRequestLine, results, std::regex(R"(([^:]*):\s*(.*))"))) {
for (auto it(++results.begin()), end(results.end()); it != end; ++it) {
std::cout << "{" << *it << "}\n";
}
}
}
Expanding from my comment:
You might be interested in the first sample I listed here: small HTTP response headers parsing function. Summary: use phrase_parse(f, e, token >> ':' >> lexeme[*(char_ - eol)], space, key, value)
Here's a simple sample:
Live On Coliru
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
namespace {
typedef std::string::const_iterator It;
// 2.2 Basic Rules (rfc1945)
static const qi::rule<It, std::string()> rfc1945_token = +~qi::char_( " \t><#,;:\\\"/][?=}{:"); // FIXME? should filter CTLs
}
#include <iostream>
int main()
{
std::string const strRequestLine("Host: 192.168.0.1:12345");
std::string::const_iterator f(strRequestLine.begin()), l(strRequestLine.end());
std::string key, value;
if (qi::phrase_parse(f, l, rfc1945_token >> ':' >> qi::lexeme[*(qi::char_ - qi::eol)], qi::space, key, value))
std::cout << "'" << key << "' -> '" << value << "'\n";
}
Prints
'Host' -> '192.168.0.1:12345'
I have these variables:
boost::regex re //regular expression to use
std::string stringToChange //replace this string
std::string newValue //new value that is going to replace the stringToChange depending on the regex.
I only want to replace the first occurrence of it only.
Thanks fellas.
EDIT: I've found this:
boost::regex_replace(stringToChange, re, boost::format_first_only);
but it says the function does not exists, I'm guessing the parameters are incorrect at the moment.
Here is an example of basic usage:
#include <iostream>
#include <string>
#include <boost/regex.hpp>
int main(){
std::string str = "hellooooooooo";
std::string newtext = "o Bob";
boost::regex re("ooooooooo");
std::cout << str << std::endl;
std::string result = boost::regex_replace(str, re, newtext);
std::cout << result << std::endl;
}
Output
hellooooooooo
hello Bob
Make sure you are including <boost/regex.hpp> and have linked to the boost_regex library.
I have some difficulties in understanding if-then-else conditionals in regular expressions.
After reading If-Then-Else Conditionals in Regular Expressions I decided to write a simple test. I use C++, Boost 1.38 Regex and MS VC 8.0.
I have written this program:
#include <iostream>
#include <string>
#include <boost/regex.hpp>
int main()
{
std::string str_to_modify = "123";
//std::string str_to_modify = "ttt";
boost::regex regex_to_search ("(\\d\\d\\d)");
std::string regex_format ("(?($1)$1|000)");
std::string modified_str =
boost::regex_replace(
str_to_modify,
regex_to_search,
regex_format,
boost::match_default | boost::format_all | format_no_copy );
std::cout << modified_str << std::endl;
return 0;
}
I expected to get "123" if str_to_modify has "123" and to get "000" if I str_to_modify has "ttt". However I get ?123123|000 in the first case and nothing in second one.
Coluld you tell me, please, what is wrong with my test?
The second example that still doesn't work :
#include <iostream>
#include <string>
#include <boost/regex.hpp>
int main()
{
//std::string str_to_modify = "123";
std::string str_to_modify = "ttt";
boost::regex regex_to_search ("(\\d\\d\\d)");
std::string regex_format ("(?1foo:bar");
std::string modified_str =
boost::regex_replace(str_to_modify, regex_to_search, regex_format,
boost::match_default | boost::format_all | boost::format_no_copy );
std::cout << modified_str << std::endl;
return 0;
}
I think the format string should be (?1$1:000) as described in the Boost.Regex docs.
Edit: I don't think regex_replace can do what you want. Why don't you try the following instead? regex_match will tell you whether the match succeeded (or you can use match[i].matched to check whether the i-th tagged sub-expression matched). You can format the match using the match.format member function.
#include <iostream>
#include <string>
#include <boost/regex.hpp>
int main()
{
boost::regex regex_to_search ("(\\d\\d\\d)");
std::string str_to_modify;
while (std::getline(std::cin, str_to_modify))
{
boost::smatch match;
if (boost::regex_match(str_to_modify, match, regex_to_search))
std::cout << match.format("foo:$1") << std::endl;
else
std::cout << "error" << std::endl;
}
}