2727#endif
2828#include < pcre.h>
2929
30+ #define PCRE2_CODE_UNIT_WIDTH 8
31+ #include < pcre2.h>
32+
3033namespace {
3134 class PcreRegex : public Regex
3235 {
@@ -248,6 +251,79 @@ namespace {
248251 }
249252}
250253
254+ namespace {
255+ class Pcre2Regex : public Regex
256+ {
257+ public:
258+ explicit Pcre2Regex (std::string pattern)
259+ : mPattern(std::move(pattern))
260+ {}
261+
262+ ~Pcre2Regex () override
263+ {
264+ if (mRe ) {
265+ pcre_free (mRe );
266+ mRe = nullptr ;
267+ }
268+ }
269+
270+ std::string compile ();
271+ std::string match (const std::string& str, const MatchFn& match) const override ;
272+
273+ private:
274+ std::string mPattern ;
275+ pcre2_code* mRe {};
276+ };
277+
278+ std::string Pcre2Regex::compile ()
279+ {
280+ if (mRe )
281+ return " regular expression has already been compiled" ;
282+
283+ int errnumber = 0 ;
284+ size_t erroffset = 0 ;
285+ pcre2_code * const re = pcre2_compile (reinterpret_cast <PCRE2_SPTR8>(mPattern .c_str ()), PCRE2_ZERO_TERMINATED, 0 , &errnumber, &erroffset, nullptr );
286+ if (!re) {
287+ PCRE2_UCHAR buffer[256 ];
288+ pcre2_get_error_message (errnumber, buffer, sizeof (buffer));
289+ return reinterpret_cast <char *>(buffer);
290+ }
291+
292+ mRe = re;
293+
294+ return " " ;
295+ }
296+
297+ std::string Pcre2Regex::match (const std::string& str, const MatchFn& match) const
298+ {
299+ if (!mRe )
300+ return " regular expression has not been compiled yet" ;
301+
302+ pcre2_match_data* match_data = pcre2_match_data_create_from_pattern (mRe , NULL );
303+
304+ int pos = 0 ;
305+ while (pos < static_cast <int >(str.size ())) {
306+ const int pcreExecRet = pcre2_match (mRe , reinterpret_cast <PCRE2_SPTR8>(str.c_str ()), static_cast <int >(str.size ()), pos, 0 , match_data, nullptr );
307+ if (pcreExecRet == PCRE2_ERROR_NOMATCH)
308+ return " " ;
309+ if (pcreExecRet < 0 ) {
310+ // TODO: get message
311+ return std::to_string (pcreExecRet) + " (pos: " + std::to_string (pos) + " )" ;
312+ }
313+ PCRE2_SIZE* ovector = pcre2_get_ovector_pointer (match_data);
314+ const auto pos1 = static_cast <unsigned int >(ovector[0 ]);
315+ const auto pos2 = static_cast <unsigned int >(ovector[1 ]);
316+
317+ match (pos1, pos2);
318+
319+ // jump to the end of the match for the next pcre_exec
320+ pos = static_cast <int >(pos2);
321+ }
322+
323+ return " " ;
324+ }
325+ }
326+
251327template <typename T>
252328static T* createAndCompileRegex (std::string pattern, std::string& err)
253329{
@@ -261,6 +337,8 @@ std::shared_ptr<Regex> Regex::create(std::string pattern, Engine engine, std::st
261337 Regex* regex = nullptr ;
262338 if (engine == Engine::Pcre)
263339 regex = createAndCompileRegex<PcreRegex>(std::move (pattern), err);
340+ else if (engine == Engine::Pcre2)
341+ regex = createAndCompileRegex<Pcre2Regex>(std::move (pattern), err);
264342 else {
265343 err = " unknown regular expression engine" ;
266344 }
0 commit comments