Reputation: 441
I receive 2 regexes as an input. I am working in C and C++ (we were told that both options are OK, but I am mostly skilled in C). The received regexes have to be applied to a file on stdin, line by line. I use this code:
int res;
line = read_line(&res);
while (res) {
printf("%s\n",line);
std::string input_line = line;
std::string to_replace = argv[1];
std::string new_regex = argv[2];
std::regex_replace(input_line, to_replace, new_regex);
printf("%s\n", input_line);
free(line)
line = read_line(&res);
}
But I have problem with the function regex_replace - it seems to take in C++ objects, but I don't know how to convert my input arguments to std::regex. I tried converting it into std::string and then to std::regex, but it didn't work. I would appreciate any help.
Upvotes: 2
Views: 812
Reputation: 20141
Matthieu already mentioned the doc. of std::regex_replace() on cppreference.com
.
There are multiple flavors of std::regex_replace()
. Some of them use iterators as arguments. This is very common for std library algorithms because it makes them very flexible to use, i.e. applicable to the broadest variety of things which can be iterated including container templates, arrays, and strings (although there might be additional constraints reducing that).
In this specific case, I choose the (in my case) most convenient flavor:
template< class Traits, class CharT,
class STraits, class SAlloc >
std::basic_string<CharT,STraits,SAlloc>
regex_replace( const std::basic_string<CharT,STraits,SAlloc>& s,
const std::basic_regex<CharT,Traits>& re,
const CharT* fmt,
std::regex_constants::match_flag_type flags =
std::regex_constants::match_default );
which can be read for my concrete types as:
std::string std::regex_replace(
const std::string &s, // the input string to process
const std::regex &re, // the regular expression to apply
const char *fmt, // the replacement text
std::regex_constants::match_flag_type flags
= std::regex_constants::match_default);
The other “missing piece” of OP seems to be the fact that the 2nd argument of regex_replace()
is an instance of std::regex
.
So, OP's line
std::regex_replace(input_line, to_replace, new_regex);
has three issues:
std::regex
instance as 2nd argument.The fix would look like:
input_line
= std::regex_replace(input_line, std::regex(new_regex), to_replace);
The explicit call of std::regex::regex()
is necessary as the doc. of std::regex::regex() shows that:
explicit regex(
const char *text,
flag_type f = std::regex_constants::ECMAScript);
as well as
explicit regex(
const std::string &text,
flag_type f = std::regex_constants::ECMAScript);
are remarked as explicit
i.e. they won't apply automatically for conversion of a given const char*
or std::string
.
As the regular expression is given once (in command line argument) but might be applied to many lines, I recommend to construct it outside of loop. Regular expressions are not that cheap concerning performance. I often read the hint that pre-compiling is recommended.
Putting all this together, I got the following sample testRE.cc
:
#include <iostream>
#include <regex>
#include <string>
int main(int argc, char **argv)
{
// a minimal check of command line arguments
if (argc != 3) {
std::cerr << "ERROR! Wrong number of command line arguments.\n"
<< "Usage:\n"
<< " " << argv[0] << " REPLACE REGEX\n";
return 1;
}
// configure replace and regex
const char *const replace = argv[1];
const std::regex regexpr(argv[2]);
// process standard input
for (std::string line; std::getline(std::cin, line);) {
line = std::regex_replace(line, regexpr, replace);
std::cout << line << '\n';
}
// done
return 0;
}
Compiled and tested:
$ g++ -std=c++11 -O2 -Wall -pedantic testRE.cc -o testRE
$ (cat | ./testRE "cat" 'd(og|uck)') <<EOF
The quick brown fox jumps over the lazy dog.
My black cat looks to the white duck.
EOF
The quick brown fox jumps over the lazy cat.
My black cat looks to the white cat.
$
Con-cat-enation
Upvotes: 2