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,85 @@ 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+ PCRE2_UCHAR errorMessageBuf[120 ];
311+ const int res = pcre2_get_error_message (pcreExecRet, errorMessageBuf, sizeof (errorMessageBuf));
312+ if (res < 0 )
313+ return std::string (" failed to get error message " ) + std::to_string (res) + " (pos: " + std::to_string (pos) + " )" ;
314+ return std::string (reinterpret_cast <char *>(errorMessageBuf)) + " (pos: " + std::to_string (pos) + " )" ;
315+ }
316+ PCRE2_SIZE* ovector = pcre2_get_ovector_pointer (match_data);
317+ const uint32_t ovcount = pcre2_get_ovector_count (match_data);
318+ if (ovcount != 1 )
319+ return " invalid ovector count" ;
320+ const auto pos1 = static_cast <unsigned int >(ovector[0 ]);
321+ const auto pos2 = static_cast <unsigned int >(ovector[1 ]);
322+
323+ match (pos1, pos2);
324+
325+ // jump to the end of the match for the next pcre_exec
326+ pos = static_cast <int >(pos2);
327+ }
328+
329+ return " " ;
330+ }
331+ }
332+
251333template <typename T>
252334static T* createAndCompileRegex (std::string pattern, std::string& err)
253335{
@@ -261,6 +343,8 @@ std::shared_ptr<Regex> Regex::create(std::string pattern, Engine engine, std::st
261343 Regex* regex = nullptr ;
262344 if (engine == Engine::Pcre)
263345 regex = createAndCompileRegex<PcreRegex>(std::move (pattern), err);
346+ else if (engine == Engine::Pcre2)
347+ regex = createAndCompileRegex<Pcre2Regex>(std::move (pattern), err);
264348 else {
265349 err = " unknown regular expression engine" ;
266350 }
0 commit comments