Refactored app_pcrecpp.h structure.

This commit is contained in:
Alexander Shaduri
2021-03-15 19:00:50 +04:00
parent bedd8f362b
commit cfc11bef6e
+281 -117
View File
@@ -12,8 +12,6 @@ Copyright:
#ifndef APP_PCRECPP_H
#define APP_PCRECPP_H
// A wrapper header for pcrecpp
#include <pcrecpp.h>
#include <string>
#include <string_view>
@@ -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<int>(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<int>(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<int>(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<int>(str.size())});
}
#endif
/// @}