diff --git a/include/wx/regex.h b/include/wx/regex.h index 0b1836e344..ac70ff3907 100644 --- a/include/wx/regex.h +++ b/include/wx/regex.h @@ -142,6 +142,8 @@ public: int ReplaceAll(wxString *text, const wxString& replacement) const { return Replace(text, replacement, 0); } + static wxString QuoteMeta(const wxString& str); + // dtor not virtual, don't derive from this class ~wxRegEx(); diff --git a/interface/wx/regex.h b/interface/wx/regex.h index 0b1debcabd..0a6f24558c 100644 --- a/interface/wx/regex.h +++ b/interface/wx/regex.h @@ -250,5 +250,31 @@ public: Replace the first occurrence. */ int ReplaceFirst(wxString* text, const wxString& replacement) const; + + /** + Escapes any of the characters having special meaning for wxRegEx. + + Currently the following characters are special: \\, ^, $, ., |, ?, *, + +, (, ), [, ], { and }. All occurrences of any of these characters in + the passed string are escaped, i.e. a backslash is inserted before + them, to remove their special meaning. + + For example: + @code + wxString quoted = wxRegEx::QuoteMeta("foo.*bar"); + assert( quoted == R"(foo\.\*bar)" ); + @endcode + + This function can be useful when using wxRegEx to search for a literal + string entered by user, for example. + + @param str + A string that may contain metacharacters to escape. + + @return A string with all metacharacters escaped. + + @since 3.1.3 + */ + static wxString QuoteMeta(const wxString& str); }; diff --git a/src/common/regex.cpp b/src/common/regex.cpp index d9151a67ed..2e48d2f592 100644 --- a/src/common/regex.cpp +++ b/src/common/regex.cpp @@ -690,4 +690,29 @@ int wxRegEx::Replace(wxString *pattern, return m_impl->Replace(pattern, replacement, maxMatches); } +wxString wxRegEx::QuoteMeta(const wxString& str) +{ + static const wxString s_strMetaChars = wxS("\\^$.|?*+()[]{}"); + + wxString strEscaped; + + // This is the maximal possible length of the resulting string, if every + // character were escaped. + strEscaped.reserve(str.length() * 2); + + for ( wxString::const_iterator it = str.begin(); it != str.end(); ++it ) + { + if ( s_strMetaChars.find(*it) != wxString::npos ) + { + strEscaped += wxS('\\'); + } + + strEscaped += *it; + } + + strEscaped.shrink_to_fit(); + + return strEscaped; +} + #endif // wxUSE_REGEX diff --git a/tests/regex/wxregextest.cpp b/tests/regex/wxregextest.cpp index c65dd71714..b731caa0fc 100644 --- a/tests/regex/wxregextest.cpp +++ b/tests/regex/wxregextest.cpp @@ -334,5 +334,14 @@ CPPUNIT_TEST_SUITE_REGISTRATION(wxRegExTestSuite); // also include in its own registry so that these tests can be run alone CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(wxRegExTestSuite, "wxRegExTestSuite"); +TEST_CASE("wxRegEx::QuoteMeta", "[regex][meta]") +{ + CHECK( wxRegEx::QuoteMeta("") == "" ); + CHECK( wxRegEx::QuoteMeta("a") == "a" ); + CHECK( wxRegEx::QuoteMeta("?") == "\\?" ); + CHECK( wxRegEx::QuoteMeta("\\") == "\\\\" ); + CHECK( wxRegEx::QuoteMeta("\\?!") == "\\\\\\?!" ); + CHECK( wxRegEx::QuoteMeta(":foo.*bar") == ":foo\\.\\*bar" ); +} #endif // wxUSE_REGEX