From cfc11bef6e77e6b2559777e513258a20f54205b4 Mon Sep 17 00:00:00 2001 From: Alexander Shaduri Date: Mon, 15 Mar 2021 19:00:50 +0400 Subject: [PATCH] Refactored app_pcrecpp.h structure. --- src/applib/app_pcrecpp.h | 398 +++++++++++++++++++++++++++------------ 1 file changed, 281 insertions(+), 117 deletions(-) diff --git a/src/applib/app_pcrecpp.h b/src/applib/app_pcrecpp.h index c47a821..97afc4c 100644 --- a/src/applib/app_pcrecpp.h +++ b/src/applib/app_pcrecpp.h @@ -12,8 +12,6 @@ Copyright: #ifndef APP_PCRECPP_H #define APP_PCRECPP_H -// A wrapper header for pcrecpp - #include #include #include @@ -21,6 +19,12 @@ Copyright: #include "hz/debug.h" +/** + * \file + * Convenience wrappers for pcrecpp + */ + + /// Take a string of characters where each character represents a modifier /// and return the appropriate pcre options. @@ -33,33 +37,167 @@ Copyright: /// - 8 - handles UTF8 characters in pattern (u in php, not available in perl). /// - U - ungreedy, reverses * and *? (not available in perl). /// - N - disables matching parentheses (not available in perl or php). -inline pcrecpp::RE_Options app_pcre_get_options(const char* modifiers) +inline pcrecpp::RE_Options app_pcre_get_options(std::string_view modifiers); + + + +/// Create a regular expression. +/// Pattern is in form of "/pattern/modifiers". +/// Note: Slashes should be escaped with backslashes within the pattern. +/// If the string doesn't start with a slash, it is treated as an ordinary pattern +/// without modifiers. +/// This function will make a RE object with ANYCRLF option set for portability +/// across various pcre builds. +inline pcrecpp::RE app_pcre_re(const std::string& perl_pattern); + + + +/// Partially match a string against a regular expression. +/// matched_ptr arguments take pointers to std::string and arithmetical types, +/// and are filled with matched parts of `str. +/// \return true if a match was found. +inline bool app_pcre_match(const pcrecpp::RE& re, const std::string_view& str, + const pcrecpp::Arg& matched_ptr1 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr2 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr3 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr4 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr5 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr6 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr7 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr8 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr9 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr10 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr11 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr12 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr13 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr14 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr15 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr16 = pcrecpp::RE::no_arg); + + + +/// Partially match a string against a pattern in "/pattern/modifiers" format. +/// matched_ptr arguments take pointers to std::string and arithmetical types, +/// and are filled with matched parts of `str. +/// \return true if a match was found. +inline bool app_pcre_match(const std::string& perl_pattern, const std::string_view& str, + const pcrecpp::Arg& matched_ptr1 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr2 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr3 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr4 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr5 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr6 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr7 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr8 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr9 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr10 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr11 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr12 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr13 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr14 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr15 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr16 = pcrecpp::RE::no_arg); + + + +/// Match a string against a pattern in "/pattern/modifiers" format. +/// matched_ptr arguments take pointers to std::string and arithmetical types, +/// and are filled with matched parts of `str. +/// This overload is needed to avoid ambiguity with pcrecpp::RE overload. +/// \return true if a match was found. +inline bool app_pcre_match(const char* perl_pattern, const std::string_view& str, + const pcrecpp::Arg& matched_ptr1 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr2 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr3 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr4 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr5 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr6 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr7 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr8 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr9 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr10 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr11 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr12 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr13 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr14 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr15 = pcrecpp::RE::no_arg, + const pcrecpp::Arg& matched_ptr16 = pcrecpp::RE::no_arg); + + + +/// Replace every occurrence of pattern with replacement string in \c subject. +/// \return number of replacements made. +inline int app_pcre_replace(const pcrecpp::RE& re, const std::string_view& replacement, std::string& subject); + + +/// Replace every occurrence of pattern with replacement string in \c subject. +/// The pattern is in "/pattern/modifiers" format. +/// \return number of replacements made. +inline int app_pcre_replace(const std::string& perl_pattern, const std::string_view& replacement, std::string& subject); + + +/// Replace every occurrence of pattern with replacement string in \c subject. +/// The pattern is in "/pattern/modifiers" format. +/// \return number of replacements made. +inline int app_pcre_replace(const char* perl_pattern, const std::string_view& replacement, std::string& subject); + + + +/// Replace first occurrence of pattern with replacement string in \c subject. +/// \return true if a replacement was made +inline bool app_pcre_replace_once(const pcrecpp::RE& re, const std::string_view& replacement, std::string& subject); + + +/// Replace the first occurrence of pattern with replacement string in \c subject. +/// The pattern is in "/pattern/modifiers" format. +/// \return true if a replacement was made +inline bool app_pcre_replace_once(const std::string& perl_pattern, const std::string_view& replacement, std::string& subject); + + +/// Replace the first occurrence of pattern with replacement string in \c subject. +/// The pattern is in "/pattern/modifiers" format. +/// \return true if a replacement was made +inline bool app_pcre_replace_once(const char* perl_pattern, const std::string_view& replacement, std::string& subject); + + + +/// Escape a string to be used inside a regular expression. The result +/// won't contain any special expression characters. +/// Note that this function escapes any non-alphanumeric character (including slash), +/// as this is allowed by PCRE. +inline std::string app_pcre_escape(const std::string_view& str); + + + + +// ------------------------------------------- Implementation + + + +pcrecpp::RE_Options app_pcre_get_options(std::string_view modifiers) { // ANYCRLF means any of crlf, cr, lf. Used in ^ and $. // This overrides the build-time newline setting of pcre. -#ifdef PCRE_NEWLINE_ANYCRLF +#ifdef PCRE_NEWLINE_ANYCRLF // not available in older versions of pcre1, not wrapped in pcrecpp pcrecpp::RE_Options options(PCRE_NEWLINE_ANYCRLF); #else pcrecpp::RE_Options options; #endif - if (modifiers) { - char c = 0; - while ((c = *modifiers++) != '\0') { - switch (c) { - // Note: Most of these are from pcretest man page. - // Perl lacks some of them. - case 'i': options.set_caseless(true); break; // case insensitive match. - case 'm': options.set_multiline(true); break; // read past the first line too. - case 's': options.set_dotall(true); break; // dot matches newlines. - case 'E': options.set_dollar_endonly(true); break; // not in perl. php has D. $ matches only at end. - case 'X': options.set_extra(true); break; // not in perl. strict escape parsing - case 'x': options.set_extended(true); break; // ignore whitespaces - case '8': options.set_utf8(true); break; // not in perl. php has u. handles UTF8 chars in pattern. - case 'U': options.set_ungreedy(true); break; // not in perl. reverses * and *? - case 'N': options.set_no_auto_capture(true); break; // not in perl or php. disables matching parentheses. - default: debug_out_error("app", DBG_FUNC_MSG << "Unknown modifier \'" << c << "\'\n"); break; - } + for (char c : modifiers) { + switch (c) { + // Note: Most of these are from pcretest man page. + // Perl lacks some of them. + case 'i': options.set_caseless(true); break; // case insensitive match. + case 'm': options.set_multiline(true); break; // read past the first line too. + case 's': options.set_dotall(true); break; // dot matches newlines. + case 'E': options.set_dollar_endonly(true); break; // not in perl. php has D. $ matches only at end. + case 'X': options.set_extra(true); break; // not in perl. strict escape parsing + case 'x': options.set_extended(true); break; // ignore whitespaces + case '8': options.set_utf8(true); break; // not in perl. php has u. handles UTF8 chars in pattern. + case 'U': options.set_ungreedy(true); break; // not in perl. reverses * and *? + case 'N': options.set_no_auto_capture(true); break; // not in perl or php. disables matching parentheses. + default: debug_out_error("app", DBG_FUNC_MSG << "Unknown modifier \'" << c << "\'\n"); break; } } @@ -68,13 +206,7 @@ inline pcrecpp::RE_Options app_pcre_get_options(const char* modifiers) -/// Accept pattern in form of "/pattern/modifiers". -/// Note: Slashes should be escaped within the pattern. -/// If the string doesn't start with a slash, it is treated as an ordinary pattern -/// without modifiers. -/// This function will make a RE object with ANYCRLF option set for portability -/// across various pcre builds. -inline pcrecpp::RE app_pcre_re(const std::string& perl_pattern) +pcrecpp::RE app_pcre_re(const std::string& perl_pattern) { if (perl_pattern.size() >= 2 && perl_pattern[0] == '/') { @@ -84,149 +216,181 @@ inline pcrecpp::RE app_pcre_re(const std::string& perl_pattern) // no need to unescape slashes in pattern - pcre seems to not mind. return pcrecpp::RE(perl_pattern.substr(1, endpos - 1), - app_pcre_get_options(perl_pattern.substr(endpos + 1).c_str())); + app_pcre_get_options(perl_pattern.substr(endpos + 1))); } - return pcrecpp::RE(perl_pattern, app_pcre_get_options(nullptr)); + return pcrecpp::RE(perl_pattern, app_pcre_get_options({})); } -/// Match a string against a pattern in "/pattern/modifiers" format. -inline bool app_pcre_match(const pcrecpp::RE& re, const std::string_view& str, - const pcrecpp::Arg& ptr1 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr2 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr3 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr4 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr5 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr6 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr7 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr8 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr9 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr10 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr11 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr12 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr13 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr14 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr15 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr16 = pcrecpp::RE::no_arg) +bool app_pcre_match(const pcrecpp::RE& re, const std::string_view& str, + const pcrecpp::Arg& matched_ptr1, + const pcrecpp::Arg& matched_ptr2, + const pcrecpp::Arg& matched_ptr3, + const pcrecpp::Arg& matched_ptr4, + const pcrecpp::Arg& matched_ptr5, + const pcrecpp::Arg& matched_ptr6, + const pcrecpp::Arg& matched_ptr7, + const pcrecpp::Arg& matched_ptr8, + const pcrecpp::Arg& matched_ptr9, + const pcrecpp::Arg& matched_ptr10, + const pcrecpp::Arg& matched_ptr11, + const pcrecpp::Arg& matched_ptr12, + const pcrecpp::Arg& matched_ptr13, + const pcrecpp::Arg& matched_ptr14, + const pcrecpp::Arg& matched_ptr15, + const pcrecpp::Arg& matched_ptr16) { return re.PartialMatch({str.data(), static_cast(str.size())}, - ptr1, ptr2, ptr3, ptr4, ptr5, ptr6, ptr7, ptr8, ptr9, ptr10, ptr11, ptr12, ptr13, ptr14, ptr15, ptr16); + matched_ptr1, + matched_ptr2, + matched_ptr3, + matched_ptr4, + matched_ptr5, + matched_ptr6, + matched_ptr7, + matched_ptr8, + matched_ptr9, + matched_ptr10, + matched_ptr11, + matched_ptr12, + matched_ptr13, + matched_ptr14, + matched_ptr15, + matched_ptr16); } -/// Match a string against a pattern in "/pattern/modifiers" format. -inline bool app_pcre_match(const std::string& perl_pattern, const std::string_view& str, - const pcrecpp::Arg& ptr1 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr2 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr3 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr4 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr5 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr6 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr7 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr8 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr9 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr10 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr11 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr12 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr13 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr14 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr15 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr16 = pcrecpp::RE::no_arg) +bool app_pcre_match(const std::string& perl_pattern, const std::string_view& str, + const pcrecpp::Arg& matched_ptr1, + const pcrecpp::Arg& matched_ptr2, + const pcrecpp::Arg& matched_ptr3, + const pcrecpp::Arg& matched_ptr4, + const pcrecpp::Arg& matched_ptr5, + const pcrecpp::Arg& matched_ptr6, + const pcrecpp::Arg& matched_ptr7, + const pcrecpp::Arg& matched_ptr8, + const pcrecpp::Arg& matched_ptr9, + const pcrecpp::Arg& matched_ptr10, + const pcrecpp::Arg& matched_ptr11, + const pcrecpp::Arg& matched_ptr12, + const pcrecpp::Arg& matched_ptr13, + const pcrecpp::Arg& matched_ptr14, + const pcrecpp::Arg& matched_ptr15, + const pcrecpp::Arg& matched_ptr16) { return app_pcre_match(app_pcre_re(perl_pattern), str, - ptr1, ptr2, ptr3, ptr4, ptr5, ptr6, ptr7, ptr8, ptr9, ptr10, ptr11, ptr12, ptr13, ptr14, ptr15, ptr16); + matched_ptr1, + matched_ptr2, + matched_ptr3, + matched_ptr4, + matched_ptr5, + matched_ptr6, + matched_ptr7, + matched_ptr8, + matched_ptr9, + matched_ptr10, + matched_ptr11, + matched_ptr12, + matched_ptr13, + matched_ptr14, + matched_ptr15, + matched_ptr16); } -/// Match a string against a pattern in "/pattern/modifiers" format. -/// This overload is needed to avoid confusion with RE. -inline bool app_pcre_match(const char* perl_pattern, const std::string_view& str, - const pcrecpp::Arg& ptr1 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr2 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr3 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr4 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr5 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr6 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr7 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr8 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr9 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr10 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr11 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr12 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr13 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr14 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr15 = pcrecpp::RE::no_arg, - const pcrecpp::Arg& ptr16 = pcrecpp::RE::no_arg) +bool app_pcre_match(const char* perl_pattern, const std::string_view& str, + const pcrecpp::Arg& matched_ptr1, + const pcrecpp::Arg& matched_ptr2, + const pcrecpp::Arg& matched_ptr3, + const pcrecpp::Arg& matched_ptr4, + const pcrecpp::Arg& matched_ptr5, + const pcrecpp::Arg& matched_ptr6, + const pcrecpp::Arg& matched_ptr7, + const pcrecpp::Arg& matched_ptr8, + const pcrecpp::Arg& matched_ptr9, + const pcrecpp::Arg& matched_ptr10, + const pcrecpp::Arg& matched_ptr11, + const pcrecpp::Arg& matched_ptr12, + const pcrecpp::Arg& matched_ptr13, + const pcrecpp::Arg& matched_ptr14, + const pcrecpp::Arg& matched_ptr15, + const pcrecpp::Arg& matched_ptr16) { return app_pcre_match(app_pcre_re(perl_pattern), str, - ptr1, ptr2, ptr3, ptr4, ptr5, ptr6, ptr7, ptr8, ptr9, ptr10, ptr11, ptr12, ptr13, ptr14, ptr15, ptr16); + matched_ptr1, + matched_ptr2, + matched_ptr3, + matched_ptr4, + matched_ptr5, + matched_ptr6, + matched_ptr7, + matched_ptr8, + matched_ptr9, + matched_ptr10, + matched_ptr11, + matched_ptr12, + matched_ptr13, + matched_ptr14, + matched_ptr15, + matched_ptr16); } -/// Replace every occurence of pattern with replacement string in \c subject. -inline int app_pcre_replace(const pcrecpp::RE& re, const std::string_view& replacement, std::string& subject) +int app_pcre_replace(const pcrecpp::RE& re, const std::string_view& replacement, std::string& subject) { return re.GlobalReplace({replacement.data(), static_cast(replacement.size())}, &subject); } -/// Replace every occurence of pattern with replacement string in \c subject. -/// The pattern is in "/pattern/modifiers" format. -inline int app_pcre_replace(const std::string& perl_pattern, const std::string_view& replacement, std::string& subject) -{ - return app_pcre_replace(app_pcre_re(perl_pattern), replacement, subject); -} - -/// Replace every occurence of pattern with replacement string in \c subject. -/// The pattern is in "/pattern/modifiers" format. -inline int app_pcre_replace(const char* perl_pattern, const std::string_view& replacement, std::string& subject) +int app_pcre_replace(const std::string& perl_pattern, const std::string_view& replacement, std::string& subject) { return app_pcre_replace(app_pcre_re(perl_pattern), replacement, subject); } -/// Replace first occurence of pattern with replacement string in \c subject. -inline bool app_pcre_replace_once(const pcrecpp::RE& re, const std::string_view& replacement, std::string& subject) +int app_pcre_replace(const char* perl_pattern, const std::string_view& replacement, std::string& subject) +{ + return app_pcre_replace(app_pcre_re(perl_pattern), replacement, subject); +} + + + +bool app_pcre_replace_once(const pcrecpp::RE& re, const std::string_view& replacement, std::string& subject) { return re.Replace({replacement.data(), static_cast(replacement.size())}, &subject); } -/// Replace the first occurence of pattern with replacement string in \c subject. -/// The pattern is in "/pattern/modifiers" format. -inline bool app_pcre_replace_once(const std::string& perl_pattern, const std::string_view& replacement, std::string& subject) -{ - return app_pcre_replace_once(app_pcre_re(perl_pattern), replacement, subject); -} - -/// Replace the first occurence of pattern with replacement string in \c subject. -/// The pattern is in "/pattern/modifiers" format. -inline bool app_pcre_replace_once(const char* perl_pattern, const std::string_view& replacement, std::string& subject) +bool app_pcre_replace_once(const std::string& perl_pattern, const std::string_view& replacement, std::string& subject) { return app_pcre_replace_once(app_pcre_re(perl_pattern), replacement, subject); } -/// Escape a string to be used inside a regular expression. The result -/// won't contain any special expression characters. -inline std::string app_pcre_escape(const std::string_view& str) +bool app_pcre_replace_once(const char* perl_pattern, const std::string_view& replacement, std::string& subject) { + return app_pcre_replace_once(app_pcre_re(perl_pattern), replacement, subject); +} + + + +std::string app_pcre_escape(const std::string_view& str) +{ + // This escapes practically any non-alphanumeric character return pcrecpp::RE::QuoteMeta({str.data(), static_cast(str.size())}); } - - #endif /// @}