From 638a1efd86f1b49822e66e02cb006fc63693098e Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Thu, 14 Mar 2019 13:24:23 +0100 Subject: [PATCH] ENH: reorganize regular expressions and add C++11 regex support - new regExpCxx wrapper for C++11 regex support with drop-in compatibility with existing code. - regExpPosix (was regExp), for future phase out in favour of regExpCxx. - The regExp header will continue to be used for defining an appropriate typedef corresponding to the preferred implementation. --- applications/test/regex/Make/files | 3 - applications/test/regex1/Make/files | 3 + .../test/{regex => regex1}/Make/options | 0 .../Test-regex.C => regex1/Test-regex1.C} | 243 ++++++++++++------ .../test/{regex => regex1}/testRegexps | 0 src/OSspecific/POSIX/Make/files | 2 +- src/OSspecific/POSIX/regExp.H | 169 +----------- src/OSspecific/POSIX/regExpFwd.H | 49 ++++ .../POSIX/{regExp.C => regExpPosix.C} | 24 +- src/OSspecific/POSIX/regExpPosix.H | 204 +++++++++++++++ .../POSIX/{regExpI.H => regExpPosixI.H} | 34 +-- src/OpenFOAM/Make/files | 1 + src/OpenFOAM/db/dictionary/dictionary.H | 12 +- src/OpenFOAM/db/dictionary/dictionarySearch.C | 12 +- .../primitives/strings/regex/regExpCxx.C | 207 +++++++++++++++ .../primitives/strings/regex/regExpCxx.H | 219 ++++++++++++++++ .../primitives/strings/regex/regExpCxxI.H | 228 ++++++++++++++++ 17 files changed, 1125 insertions(+), 285 deletions(-) delete mode 100644 applications/test/regex/Make/files create mode 100644 applications/test/regex1/Make/files rename applications/test/{regex => regex1}/Make/options (100%) rename applications/test/{regex/Test-regex.C => regex1/Test-regex1.C} (70%) rename applications/test/{regex => regex1}/testRegexps (100%) create mode 100644 src/OSspecific/POSIX/regExpFwd.H rename src/OSspecific/POSIX/{regExp.C => regExpPosix.C} (90%) create mode 100644 src/OSspecific/POSIX/regExpPosix.H rename src/OSspecific/POSIX/{regExpI.H => regExpPosixI.H} (72%) create mode 100644 src/OpenFOAM/primitives/strings/regex/regExpCxx.C create mode 100644 src/OpenFOAM/primitives/strings/regex/regExpCxx.H create mode 100644 src/OpenFOAM/primitives/strings/regex/regExpCxxI.H diff --git a/applications/test/regex/Make/files b/applications/test/regex/Make/files deleted file mode 100644 index 28fa008d1f..0000000000 --- a/applications/test/regex/Make/files +++ /dev/null @@ -1,3 +0,0 @@ -Test-regex.C - -EXE = $(FOAM_USER_APPBIN)/Test-regex diff --git a/applications/test/regex1/Make/files b/applications/test/regex1/Make/files new file mode 100644 index 0000000000..8484667641 --- /dev/null +++ b/applications/test/regex1/Make/files @@ -0,0 +1,3 @@ +Test-regex1.C + +EXE = $(FOAM_USER_APPBIN)/Test-regex1 diff --git a/applications/test/regex/Make/options b/applications/test/regex1/Make/options similarity index 100% rename from applications/test/regex/Make/options rename to applications/test/regex1/Make/options diff --git a/applications/test/regex/Test-regex.C b/applications/test/regex1/Test-regex1.C similarity index 70% rename from applications/test/regex/Test-regex.C rename to applications/test/regex1/Test-regex1.C index 29ed6766b2..ca5bfb60cd 100644 --- a/applications/test/regex/Test-regex.C +++ b/applications/test/regex1/Test-regex1.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2004-2010, 2017-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2017-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2011-2016 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -28,13 +26,14 @@ Description \*---------------------------------------------------------------------------*/ +#include "argList.H" #include "IOstreams.H" -#include "IOobject.H" #include "IFstream.H" -#include "regExp.H" -#include "SubStrings.H" #include "Switch.H" +#include "regExpCxx.H" +#include "regExpPosix.H" + using namespace Foam; @@ -63,14 +62,16 @@ struct regexTest } }; + // Needed for list output. Just treat everything as unequal. bool operator!=(const struct regexTest&, const struct regexTest&) { return true; } + // Simple output of match groups -static Ostream& operator<<(Ostream& os, const regExp::results_type& sm) +static Ostream& operator<<(Ostream& os, const regExpCxx::results_type& sm) { for (std::smatch::size_type i = 1; i < sm.size(); ++i) { @@ -81,83 +82,31 @@ static Ostream& operator<<(Ostream& os, const regExp::results_type& sm) } -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Main program: - -int main(int argc, char *argv[]) +// Simple output of match groups +static Ostream& operator<<(Ostream& os, const regExpPosix::results_type& sm) { - List<regexTest> rawList(IFstream("testRegexps")()); - Info<< "Test expressions:" << rawList << endl; - IOobject::writeDivider(Info) << endl; - - regExp::results_type match; - - // Expect some failures: - const bool throwingError = FatalError.throwExceptions(); - - // Report matches: - for (const auto& testseq : rawList) + for (std::smatch::size_type i = 1; i < sm.size(); ++i) { - const bool expected = testseq.expected; - const string& pat = testseq.pattern; - const string& str = testseq.text; - - Info<< "Test " << Switch(expected) << ": " - << str << " =~ m/" << pat.c_str() << "/ == "; - - regExp re; - - try - { - re = pat; - - if (re.match(str, match)) - { - Info<< "true"; - if (re.ngroups()) - { - Info<< " (" << re.ngroups() << " groups):" << match; - } - } - else if (re.search(str)) - { - Info<< "partial match"; - } - else - { - Info<< "false"; - } - Info<< endl; - } - catch (const Foam::error& err) - { - Info<< "Caught FatalError " << err << nl << endl; - continue; - } - - if (false) - { - regExp re2(std::move(re)); - Info<<"move construct: " << re.exists() << "/" << re2.exists() - << endl; + os << " " << sm.str(i); + } - re = std::move(re2); - Info<<"move assign: " << re.exists() << "/" << re2.exists() - << endl; + return os; +} - re.swap(re2); - Info<<"swap: " << re.exists() << "/" << re2.exists() - << endl; - } - } +template<class RegexType> +void generalTests() +{ Info<< nl << "test regExp(const char*) ..." << endl; string me("Mark"); + // Expect some failures: + const bool throwingError = FatalError.throwExceptions(); + try { // Handling of null strings - if (regExp(nullptr).match(me)) + if (RegexType(nullptr).match(me)) { Info<< "fail - matched: " << me << endl; } @@ -174,7 +123,7 @@ int main(int argc, char *argv[]) try { // Normal match - if (regExp("[Mm]ar[ck]").match(me)) + if (RegexType("[Mm]ar[ck]").match(me)) { Info<< "pass - matched: " << me << endl; } @@ -191,7 +140,7 @@ int main(int argc, char *argv[]) try { // Match ignore case - if (regExp("mar[ck]", true).match(me)) + if (RegexType("mar[ck]", true).match(me)) { Info<< "pass - matched: " << me << endl; } @@ -208,7 +157,7 @@ int main(int argc, char *argv[]) try { // Embedded prefix for match ignore case - if (regExp("(?i)mar[ck]").match(me)) + if (RegexType("(?i)mar[ck]").match(me)) { Info<< "pass - matched: " << me << endl; } @@ -225,7 +174,7 @@ int main(int argc, char *argv[]) try { // Handling of empty expression - if (regExp("").match(me)) + if (RegexType("").match(me)) { Info<< "fail - matched: " << me << endl; } @@ -242,7 +191,7 @@ int main(int argc, char *argv[]) try { // Embedded prefix - but expression is empty - if (regExp("(?i)").match(me)) + if (RegexType("(?i)").match(me)) { Info<< "fail - matched: " << me << endl; } @@ -257,6 +206,144 @@ int main(int argc, char *argv[]) } FatalError.throwExceptions(throwingError); +} + + + +template<class RegexType> +void testExpressions(const UList<regexTest>& tests) +{ + typename RegexType::results_type match; + + // Expect some failures: + const bool throwingError = FatalError.throwExceptions(); + + // Report matches: + for (const auto& testseq : tests) + { + const bool expected = testseq.expected; + const string& pat = testseq.pattern; + const string& str = testseq.text; + + Info<< "Test " << Switch(expected) << ": " + << str << " =~ m/" << pat.c_str() << "/ == "; + + RegexType re; + + try + { + re = pat; + + if (re.match(str, match)) + { + Info<< "true"; + if (re.ngroups()) + { + Info<< " (" << re.ngroups() << " groups):" << match; + } + } + else if (re.search(str)) + { + Info<< "partial match"; + } + else + { + Info<< "false"; + } + Info<< endl; + } + catch (const Foam::error& err) + { + Info<< "Caught FatalError " << err << nl << endl; + continue; + } + + if (false) + { + RegexType re2(std::move(re)); + Info<<"move construct: " << re.exists() << "/" << re2.exists() + << endl; + + re = std::move(re2); + Info<<"move assign: " << re.exists() << "/" << re2.exists() + << endl; + + re.swap(re2); + Info<<"swap: " << re.exists() << "/" << re2.exists() + << endl; + } + } + + FatalError.throwExceptions(throwingError); +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// Main program: + +int main(int argc, char *argv[]) +{ + argList::noBanner(); + argList::noFunctionObjects(); + argList::noParallel(); + + argList::addBoolOption + ( + "cxx", + "Test C++11 regular expressions" + ); + + argList::addBoolOption + ( + "posix", + "Test POSIX regular expressions" + ); + + argList::addArgument("file"); + argList::addArgument("..."); + argList::addArgument("fileN"); + argList::noMandatoryArgs(); + + #include "setRootCase.H" + + if (!args.count({"cxx", "posix"})) + { + Info<< "Specified one or more of -cxx, -posix" << nl; + return 1; + } + + if (args.size() < 2) + { + Info<< "No test files specified .. restrict to general tests" << nl; + + if (args.found("cxx")) + { + generalTests<regExpCxx>(); + } + + if (args.found("posix")) + { + generalTests<regExpPosix>(); + } + } + + for (label argi = 1; argi < args.size(); ++argi) + { + List<regexTest> tests(IFstream(args[argi])()); + + Info<< "Test expressions:" << tests << endl; + IOobject::writeDivider(Info) << endl; + + if (args.found("cxx")) + { + testExpressions<regExpCxx>(tests); + } + + if (args.found("posix")) + { + testExpressions<regExpPosix>(tests); + } + } Info<< "\nDone" << nl << endl; diff --git a/applications/test/regex/testRegexps b/applications/test/regex1/testRegexps similarity index 100% rename from applications/test/regex/testRegexps rename to applications/test/regex1/testRegexps diff --git a/src/OSspecific/POSIX/Make/files b/src/OSspecific/POSIX/Make/files index 6263ba8481..26e735cb88 100644 --- a/src/OSspecific/POSIX/Make/files +++ b/src/OSspecific/POSIX/Make/files @@ -4,7 +4,7 @@ signals/sigInt.C signals/sigQuit.C signals/sigStopAtWriteNow.C signals/sigWriteNow.C -regExp.C +regExpPosix.C timer.C fileStat.C POSIX.C diff --git a/src/OSspecific/POSIX/regExp.H b/src/OSspecific/POSIX/regExp.H index dabd3d9a40..eee48c78d8 100644 --- a/src/OSspecific/POSIX/regExp.H +++ b/src/OSspecific/POSIX/regExp.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2004-2011, 2017-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2011-2017 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -23,176 +21,19 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. -Class +Typedef Foam::regExp Description - Wrapper around POSIX extended regular expressions. - - The PCRE '(?i)' extension is provided to compile the regular expression - as being case-insensitive. - -See also - The manpage regex(7) for more information about POSIX regular expressions. - These differ somewhat from \c Perl and \c sed regular expressions. - -SourceFiles - regExpI.H - regExp.C + Selection of preferred regular expression implementation \*---------------------------------------------------------------------------*/ #ifndef regExp_H #define regExp_H -#include <regex.h> -#include <string> - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -// Forward declarations -template<class String> class SubStrings; - - -/*---------------------------------------------------------------------------*\ - Class regExp Declaration -\*---------------------------------------------------------------------------*/ - -class regExp -{ - // Private data - - //- Precompiled regular expression - regex_t* preg_; - -public: - - //- Type for matches - typedef SubStrings<std::string> results_type; - - - // Static Member Functions - - //- Test if character appears to be a regular expression meta-character - // \return true if character is one of the following: - // - any character: '.' \n - // - quantifiers: '*', '+', '?' \n - // - grouping: '(', '|', ')' \n - // - range: '[', ']' \n - // - // \note The presence of '{', '}' regex bounds is not considered - inline static bool meta(char c); - - - // Constructors - - //- Construct null - inline regExp(); - - //- Copy construct - disallowed - regExp(const regExp&) = delete; - - //- Move construct - inline regExp(regExp&& rgx); - - //- Construct from character array - inline explicit regExp(const char* pattern); - - //- Construct from string - inline explicit regExp(const std::string& pattern); - - //- Construct from character array, optionally ignore case - inline regExp(const char* pattern, bool ignoreCase); - - //- Construct from string, optionally ignore case - inline regExp(const std::string& pattern, bool ignoreCase); - - - //- Destructor - inline ~regExp(); - - - // Member functions - - // Access - - //- Return true if a precompiled expression does not exist - inline bool empty() const; - - //- Return true if a precompiled expression exists - inline bool exists() const; - - //- The number of capture groups for a non-empty expression - inline unsigned ngroups() const; - - // Editing - - //- Clear expression. - // \return True if expression had existed prior to the clear. - bool clear(); - - //- Swap contents - inline void swap(regExp& rgx); - - //- Compile pattern into a regular expression, optionally ignore case. - // \return True if the pattern was compiled - bool set(const char* pattern, bool ignoreCase=false); - - //- Compile pattern into a regular expression, optionally ignore case. - // \return True if the pattern was compiled - bool set(const std::string& pattern, bool ignoreCase=false); - - // Matching/Searching - - //- Find position within the text. - // \return The index where it begins or string::npos if not found - std::string::size_type find(const std::string& text) const; - - //- True if the regex matches the entire text. - // The begin-of-line (^) and end-of-line ($) anchors are implicit - bool match(const std::string& text) const; - - //- True if the regex matches the text, set the matches. - // The first group starts at index 1 (0 is the entire match). - // The begin-of-line (^) and end-of-line ($) anchors are implicit - bool match(const std::string& text, results_type& matches) const; - - //- Return true if the regex was found within the text - inline bool search(const std::string& text) const; - - - // Member Operators - - //- Perform match on text - inline bool operator()(const std::string& text) const; - - //- Copy assignment - disallowed - void operator=(const regExp&) = delete; - - //- Move assignment - inline void operator=(regExp&& rgx); - - //- Assign and compile pattern from a character array. - // Matching is case sensitive. - inline void operator=(const char* pattern); - - //- Assign and compile pattern from string. - // Matching is case sensitive. - inline void operator=(const std::string& pattern); - -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#include "regExpI.H" +#include "regExpPosix.H" +#include "regExpFwd.H" #endif diff --git a/src/OSspecific/POSIX/regExpFwd.H b/src/OSspecific/POSIX/regExpFwd.H new file mode 100644 index 0000000000..47e8c268cf --- /dev/null +++ b/src/OSspecific/POSIX/regExpFwd.H @@ -0,0 +1,49 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2019 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Typedef + Foam::regExp + +Description + Selection of preferred regular expression implementation + +\*---------------------------------------------------------------------------*/ + +#ifndef regExpFwd_H +#define regExpFwd_H + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + class regExpCxx; + class regExpPosix; + + typedef regExpPosix regExp; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/OSspecific/POSIX/regExp.C b/src/OSspecific/POSIX/regExpPosix.C similarity index 90% rename from src/OSspecific/POSIX/regExp.C rename to src/OSspecific/POSIX/regExpPosix.C index df661e2615..c6c1b40a92 100644 --- a/src/OSspecific/POSIX/regExp.C +++ b/src/OSspecific/POSIX/regExpPosix.C @@ -25,22 +25,32 @@ License \*---------------------------------------------------------------------------*/ -#include "regExp.H" +#include "regExpPosix.H" #include "SubStrings.H" #include "error.H" +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +int Foam::regExpPosix::grammar(0); + + // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // +namespace +{ + // Verify that the entire len was matched static inline bool fullMatch(const regmatch_t& m, const regoff_t len) { return (m.rm_so == 0 && m.rm_eo == len); } +} // End anonymous namespace + // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // -bool Foam::regExp::clear() +bool Foam::regExpPosix::clear() { if (preg_) { @@ -55,7 +65,7 @@ bool Foam::regExp::clear() } -bool Foam::regExp::set(const char* pattern, bool ignoreCase) +bool Foam::regExpPosix::set(const char* pattern, bool ignoreCase) { clear(); @@ -106,13 +116,13 @@ bool Foam::regExp::set(const char* pattern, bool ignoreCase) } -bool Foam::regExp::set(const std::string& pattern, bool ignoreCase) +bool Foam::regExpPosix::set(const std::string& pattern, bool ignoreCase) { return set(pattern.c_str(), ignoreCase); } -std::string::size_type Foam::regExp::find(const std::string& text) const +std::string::size_type Foam::regExpPosix::find(const std::string& text) const { if (preg_ && !text.empty()) { @@ -129,7 +139,7 @@ std::string::size_type Foam::regExp::find(const std::string& text) const } -bool Foam::regExp::match(const std::string& text) const +bool Foam::regExpPosix::match(const std::string& text) const { const auto len = text.size(); @@ -151,7 +161,7 @@ bool Foam::regExp::match(const std::string& text) const } -bool Foam::regExp::match +bool Foam::regExpPosix::match ( const std::string& text, SubStrings<std::string>& matches diff --git a/src/OSspecific/POSIX/regExpPosix.H b/src/OSspecific/POSIX/regExpPosix.H new file mode 100644 index 0000000000..dbed07a4dc --- /dev/null +++ b/src/OSspecific/POSIX/regExpPosix.H @@ -0,0 +1,204 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2004-2011, 2017-2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- + | Copyright (C) 2011-2017 OpenFOAM Foundation +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::regExpPosix + +Description + Wrapper around POSIX extended regular expressions. + + The PCRE '(?i)' extension is provided to compile the regular expression + as being case-insensitive. + +See also + The manpage regex(7) for more information about POSIX regular expressions. + These differ somewhat from \c Perl and \c sed regular expressions. + +SourceFiles + regExpPosixI.H + regExpPosix.C + +\*---------------------------------------------------------------------------*/ + +#ifndef regExpPosix_H +#define regExpPosix_H + +#include <regex.h> +#include <string> + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward Declarations +template<class String> class SubStrings; + + +/*---------------------------------------------------------------------------*\ + Class regExpPosix Declaration +\*---------------------------------------------------------------------------*/ + +class regExpPosix +{ + // Private Data + + //- Precompiled regular expression + regex_t* preg_; + +public: + + //- Type for matches + typedef SubStrings<std::string> results_type; + + // Static Member Data + + //- The default grammar (unused) - for future-compatibility + static int grammar; + + + // Static Member Functions + + //- Test if character appears to be a regular expression meta-character + // \return true if character is one of the following: + // - any character: '.' \n + // - quantifiers: '*', '+', '?' \n + // - grouping: '(', '|', ')' \n + // - range: '[', ']' \n + // + // \note The presence of '{', '}' regex bounds is not considered + inline static bool meta(char c); + + + // Constructors + + //- Construct null + inline regExpPosix(); + + //- Copy construct - disallowed + regExpPosix(const regExpPosix&) = delete; + + //- Move construct + inline regExpPosix(regExpPosix&& rgx); + + //- Construct from character array + inline explicit regExpPosix(const char* pattern); + + //- Construct from string + inline explicit regExpPosix(const std::string& pattern); + + //- Construct from character array, optionally ignore case + inline regExpPosix(const char* pattern, bool ignoreCase); + + //- Construct from string, optionally ignore case + inline regExpPosix(const std::string& pattern, bool ignoreCase); + + + //- Destructor + inline ~regExpPosix(); + + + // Member functions + + // Access + + //- Return true if a precompiled expression does not exist + inline bool empty() const; + + //- Return true if a precompiled expression exists + inline bool exists() const; + + //- The number of capture groups for a non-empty expression + inline unsigned ngroups() const; + + // Editing + + //- Clear expression. + // \return True if expression had existed prior to the clear. + bool clear(); + + //- Swap contents + inline void swap(regExpPosix& rgx); + + //- Compile pattern into a regular expression, optionally ignore case. + // \return True if the pattern was compiled + bool set(const char* pattern, bool ignoreCase=false); + + //- Compile pattern into a regular expression, optionally ignore case. + // \return True if the pattern was compiled + bool set(const std::string& pattern, bool ignoreCase=false); + + // Matching/Searching + + //- Find position within the text. + // \return The index where it begins or string::npos if not found + std::string::size_type find(const std::string& text) const; + + //- True if the regex matches the entire text. + // The begin-of-line (^) and end-of-line ($) anchors are implicit + bool match(const std::string& text) const; + + //- True if the regex matches the text, set the matches. + // The first group starts at index 1 (0 is the entire match). + // The begin-of-line (^) and end-of-line ($) anchors are implicit + bool match(const std::string& text, results_type& matches) const; + + //- Return true if the regex was found within the text + inline bool search(const std::string& text) const; + + + // Member Operators + + //- Perform match on text + inline bool operator()(const std::string& text) const; + + //- Copy assignment - disallowed + void operator=(const regExpPosix&) = delete; + + //- Move assignment + inline void operator=(regExpPosix&& rgx); + + //- Assign and compile pattern from a character array. + // Matching is case sensitive. + inline void operator=(const char* pattern); + + //- Assign and compile pattern from string. + // Matching is case sensitive. + inline void operator=(const std::string& pattern); + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "regExpPosixI.H" + +#endif + +// ************************************************************************* // diff --git a/src/OSspecific/POSIX/regExpI.H b/src/OSspecific/POSIX/regExpPosixI.H similarity index 72% rename from src/OSspecific/POSIX/regExpI.H rename to src/OSspecific/POSIX/regExpPosixI.H index 48d3beb36c..75f8482506 100644 --- a/src/OSspecific/POSIX/regExpI.H +++ b/src/OSspecific/POSIX/regExpPosixI.H @@ -28,7 +28,7 @@ License // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // -inline bool Foam::regExp::meta(char c) +inline bool Foam::regExpPosix::meta(char c) { return ( @@ -42,13 +42,13 @@ inline bool Foam::regExp::meta(char c) // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -inline Foam::regExp::regExp() +inline Foam::regExpPosix::regExpPosix() : preg_(nullptr) {} -inline Foam::regExp::regExp(const char* pattern) +inline Foam::regExpPosix::regExpPosix(const char* pattern) : preg_(nullptr) { @@ -56,7 +56,7 @@ inline Foam::regExp::regExp(const char* pattern) } -inline Foam::regExp::regExp(const std::string& pattern) +inline Foam::regExpPosix::regExpPosix(const std::string& pattern) : preg_(nullptr) { @@ -64,7 +64,7 @@ inline Foam::regExp::regExp(const std::string& pattern) } -inline Foam::regExp::regExp(const char* pattern, bool ignoreCase) +inline Foam::regExpPosix::regExpPosix(const char* pattern, bool ignoreCase) : preg_(nullptr) { @@ -72,7 +72,7 @@ inline Foam::regExp::regExp(const char* pattern, bool ignoreCase) } -inline Foam::regExp::regExp(const std::string& pattern, bool ignoreCase) +inline Foam::regExpPosix::regExpPosix(const std::string& pattern, bool ignoreCase) : preg_(nullptr) { @@ -80,7 +80,7 @@ inline Foam::regExp::regExp(const std::string& pattern, bool ignoreCase) } -inline Foam::regExp::regExp(regExp&& rgx) +inline Foam::regExpPosix::regExpPosix(regExpPosix&& rgx) : preg_(rgx.preg_) { @@ -90,7 +90,7 @@ inline Foam::regExp::regExp(regExp&& rgx) // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // -inline Foam::regExp::~regExp() +inline Foam::regExpPosix::~regExpPosix() { clear(); } @@ -98,31 +98,31 @@ inline Foam::regExp::~regExp() // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // -inline bool Foam::regExp::empty() const +inline bool Foam::regExpPosix::empty() const { return !preg_; } -inline bool Foam::regExp::exists() const +inline bool Foam::regExpPosix::exists() const { return preg_ ? true : false; } -inline unsigned Foam::regExp::ngroups() const +inline unsigned Foam::regExpPosix::ngroups() const { return preg_ ? preg_->re_nsub : 0; } -inline bool Foam::regExp::search(const std::string& text) const +inline bool Foam::regExpPosix::search(const std::string& text) const { return std::string::npos != find(text); } -inline void Foam::regExp::swap(regExp& rgx) +inline void Foam::regExpPosix::swap(regExpPosix& rgx) { std::swap(preg_, rgx.preg_); } @@ -130,26 +130,26 @@ inline void Foam::regExp::swap(regExp& rgx) // * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * // -inline bool Foam::regExp::operator()(const std::string& text) const +inline bool Foam::regExpPosix::operator()(const std::string& text) const { return match(text); } -inline void Foam::regExp::operator=(regExp&& rgx) +inline void Foam::regExpPosix::operator=(regExpPosix&& rgx) { clear(); swap(rgx); } -inline void Foam::regExp::operator=(const char* pattern) +inline void Foam::regExpPosix::operator=(const char* pattern) { set(pattern); } -inline void Foam::regExp::operator=(const std::string& pattern) +inline void Foam::regExpPosix::operator=(const std::string& pattern) { set(pattern); } diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files index 978beb40fb..54c3b2a19a 100644 --- a/src/OpenFOAM/Make/files +++ b/src/OpenFOAM/Make/files @@ -120,6 +120,7 @@ $(strings)/word/wordIOList.C $(strings)/fileName/fileName.C $(strings)/fileName/fileNameIO.C $(strings)/keyType/keyType.C +$(strings)/regex/regExpCxx.C $(strings)/wordRe/wordRe.C $(strings)/wordRes/wordRes.C $(strings)/lists/CStringList.C diff --git a/src/OpenFOAM/db/dictionary/dictionary.H b/src/OpenFOAM/db/dictionary/dictionary.H index 3a4d2c9be0..b86be7adc8 100644 --- a/src/OpenFOAM/db/dictionary/dictionary.H +++ b/src/OpenFOAM/db/dictionary/dictionary.H @@ -100,14 +100,14 @@ SeeAlso // Some common data types #include "label.H" #include "scalar.H" +#include "regExpFwd.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { -// Forward declarations -class regExp; +// Forward Declarations class dictionary; class SHA1Digest; @@ -282,7 +282,7 @@ public: private: - // Private data + // Private Data //- Report optional keywords and values if not present in dictionary // Set/unset via an InfoSwitch @@ -309,12 +309,6 @@ private: //- The storage container typedef IDLList<entry> parent_type; - typedef DLList<entry*>::iterator pattern_iterator; - typedef DLList<entry*>::const_iterator pattern_const_iterator; - - typedef DLList<autoPtr<regExp>>::iterator regexp_iterator; - typedef DLList<autoPtr<regExp>>::const_iterator regexp_const_iterator; - // Private Member Functions diff --git a/src/OpenFOAM/db/dictionary/dictionarySearch.C b/src/OpenFOAM/db/dictionary/dictionarySearch.C index 56460f28dd..d3fcee91c4 100644 --- a/src/OpenFOAM/db/dictionary/dictionarySearch.C +++ b/src/OpenFOAM/db/dictionary/dictionarySearch.C @@ -277,8 +277,8 @@ Foam::dictionary::const_searcher Foam::dictionary::csearch if ((matchOpt & keyType::REGEX) && patterns_.size()) { - pattern_const_iterator wcLink = patterns_.begin(); - regexp_const_iterator reLink = regexps_.begin(); + auto wcLink = patterns_.cbegin(); + auto reLink = regexps_.cbegin(); // Find in patterns using regular expressions only if (findInPatterns(true, keyword, wcLink, reLink)) @@ -584,8 +584,8 @@ bool Foam::dictionary::remove(const word& keyword) if (iter.found()) { // Delete from patterns - pattern_iterator wcLink = patterns_.begin(); - regexp_iterator reLink = regexps_.begin(); + auto wcLink = patterns_.begin(); + auto reLink = regexps_.begin(); // Find in pattern using exact match only if (findInPatterns(false, keyword, wcLink, reLink)) @@ -645,8 +645,8 @@ bool Foam::dictionary::changeKeyword if (iter2()->keyword().isPattern()) { // Delete from patterns - pattern_iterator wcLink = patterns_.begin(); - regexp_iterator reLink = regexps_.begin(); + auto wcLink = patterns_.begin(); + auto reLink = regexps_.begin(); // Find in patterns using exact match only if (findInPatterns(false, iter2()->keyword(), wcLink, reLink)) diff --git a/src/OpenFOAM/primitives/strings/regex/regExpCxx.C b/src/OpenFOAM/primitives/strings/regex/regExpCxx.C new file mode 100644 index 0000000000..0f99c82dc1 --- /dev/null +++ b/src/OpenFOAM/primitives/strings/regex/regExpCxx.C @@ -0,0 +1,207 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2017-2019 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "regExpCxx.H" +#include "debug.H" +#include "error.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +int Foam::regExpCxx::grammar(Foam::debug::optimisationSwitch("regExpCxx", 0)); + + +// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // + +namespace +{ + +static std::string error_string(const std::regex_error& err) +{ + switch (err.code()) + { + case std::regex_constants::error_collate : + return "invalid collating element name"; + break; + + case std::regex_constants::error_ctype : + return "invalid character class name"; + break; + + case std::regex_constants::error_escape : + return "invalid escaped character or a trailing escape"; + break; + + case std::regex_constants::error_backref : + return "invalid back reference"; + break; + + case std::regex_constants::error_brack : + return "mismatched [ and ]"; + break; + + case std::regex_constants::error_paren : + return "mismatched ( and )"; + break; + + case std::regex_constants::error_brace : + return "mismatched { and }"; + break; + + case std::regex_constants::error_badbrace : + return "invalid range in a {..}"; + break; + + case std::regex_constants::error_range : + return "invalid [..] character range"; + break; + + case std::regex_constants::error_space : + return "memory error"; + break; + + case std::regex_constants::error_badrepeat : + return "bad '*?+{' repeat"; + break; + + case std::regex_constants::error_complexity : + return "expression too complex"; + break; + + case std::regex_constants::error_stack : + return "memory stack error"; + break; + + default: + break; + + } + + return ""; +} + +} // End anonymous namespace + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +bool Foam::regExpCxx::set(const char* pattern, bool ignoreCase) +{ + clear(); + + size_t len = (pattern ? strlen(pattern) : 0); + + // Avoid nullptr and zero-length patterns + if (!len) + { + return false; + } + + std::regex::flag_type flags = syntax(); + if (ignoreCase) + { + flags |= std::regex::icase; + } + + const char* pat = pattern; + + // Has embedded ignore-case prefix? + if (len >= 4 && !strncmp(pattern, "(?i)", 4)) + { + flags |= std::regex::icase; + pat += 4; + len -= 4; + } + + if (len) + { + try + { + re_.assign(pat, flags); + return true; + } + catch (const std::regex_error& err) + { + FatalErrorInFunction + << "Failed to compile regular expression '" + << pattern << "'" << nl + << err.what() << ": " << error_string(err).c_str() << nl + << exit(FatalError); + } + } + + return false; +} + + +bool Foam::regExpCxx::set(const std::string& pattern, bool ignoreCase) +{ + clear(); + + auto len = pattern.size(); + + // Avoid zero-length patterns + if (!len) + { + return false; + } + + std::regex::flag_type flags = syntax(); + if (ignoreCase) + { + flags |= std::regex::icase; + } + + auto pat = pattern.begin(); + + // Has embedded ignore-case prefix? + if (len >= 4 && !pattern.compare(0, 4, "(?i)")) + { + flags |= std::regex::icase; + pat += 4; + len -= 4; + } + + if (len) + { + try + { + re_.assign(pat, pattern.end(), flags); + return true; + } + catch (const std::regex_error& err) + { + FatalErrorInFunction + << "Failed to compile regular expression '" + << pattern.c_str() << "'" << nl + << err.what() << ": " << error_string(err).c_str() << nl + << exit(FatalError); + } + } + + return false; +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/primitives/strings/regex/regExpCxx.H b/src/OpenFOAM/primitives/strings/regex/regExpCxx.H new file mode 100644 index 0000000000..a96ad8e84a --- /dev/null +++ b/src/OpenFOAM/primitives/strings/regex/regExpCxx.H @@ -0,0 +1,219 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2017-2019 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::regExpCxx + +Description + Wrapper around C++11 regular expressions. + + Using either POSIX extended regular expressions or + <a href= + "http://www.cplusplus.com/reference/regex/ECMAScript" + >modified ECMAScript regular expression grammar</a> + + Since ECMAScript grammar may not work correctly on all installations, + the current default is to use extended regular expressions. + + The JAVA/PCRE '(?i)' extension is supported as a prefix to compile the + regular expression as being case-insensitive. + +Note + The C++11 regular expressions may be broken on some compilers. + For example, gcc 4.8 is known to fail. + For these systems the POSIX implementation should be used. + +SourceFiles + regExpCxxI.H + regExpCxx.C + +\*---------------------------------------------------------------------------*/ + +#ifndef regExpCxx_H +#define regExpCxx_H + +#include <regex> +#include <string> + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class regExpCxx Declaration +\*---------------------------------------------------------------------------*/ + +class regExpCxx +{ + // Private data + + //- Regular expression (using char type) + std::regex re_; + + //- Track if input pattern was OK - ie, has a length + bool ok_; + + // Private Member Functions + + //- Select grammar based on regExpCxx optimisationSwitch + // 0 = extended, 1 = ECMAScript + static inline std::regex::flag_type syntax(); + +public: + + //- Type for matches + typedef std::smatch results_type; + + // Static Member Data + + //- The default grammar (extended | ECMAScript). + static int grammar; + + + // Static Member Functions + + //- Test if character appears to be a regular expression meta-character + // \return true if character is one of the following: + // - any character: '.' \n + // - quantifiers: '*', '+', '?' \n + // - grouping: '(', '|', ')' \n + // - range: '[', ']' \n + // + // \note The presence of '{', '}' regex bounds is not considered + inline static bool meta(const char c); + + + // Constructors + + //- Construct null + inline regExpCxx(); + + //- Copy construct + inline regExpCxx(const regExpCxx& rgx); + + //- Move construct + inline regExpCxx(regExpCxx&& rgx); + + //- Construct from character array + inline explicit regExpCxx(const char* pattern); + + //- Construct from string + inline explicit regExpCxx(const std::string& pattern); + + //- Construct from character array, optionally ignore case + inline regExpCxx(const char* pattern, bool ignoreCase); + + //- Construct from string, optionally ignore case + inline regExpCxx(const std::string& pattern, bool ignoreCase); + + + //- Destructor + ~regExpCxx() = default; + + + // Member functions + + // Access + + //- Return true if expression is empty + inline bool empty() const; + + //- Return true if expression is non-empty + inline bool exists() const; + + //- The number of capture groups for a non-empty expression + inline unsigned ngroups() const; + + // \return True if the pattern was set with ignore-case. + inline bool nocase() const; + + // Editing + + //- Clear expression. + // \return True if expression had existed prior to the clear. + inline bool clear(); + + //- Swap contents + inline void swap(regExpCxx& rgx); + + //- Compile pattern into a regular expression, optionally ignore case. + // \return True if the pattern was compiled + bool set(const char* pattern, bool ignoreCase=false); + + //- Compile pattern into a regular expression, optionally ignore case. + // \return True if the pattern was compiled + bool set(const std::string& pattern, bool ignoreCase=false); + + // Matching/Searching + + //- Find position within the text. + // \return The index where it begins or string::npos if not found + inline std::string::size_type find(const std::string& text) const; + + //- True if the regex matches the entire text. + // The begin-of-line (^) and end-of-line ($) anchors are implicit + inline bool match(const std::string& text) const; + + //- True if the regex matches the text, set the matches. + // The first group starts at index 1 (0 is the entire match). + // The begin-of-line (^) and end-of-line ($) anchors are implicit + inline bool match(const std::string& text, results_type& matches) const; + + //- Return true if the regex was found within the text + inline bool search(const std::string& text) const; + + + // Member Operators + + //- Perform match on text + inline bool operator()(const std::string& text) const; + + //- Copy assignment + inline void operator=(const regExpCxx& rgx); + + //- Move assignment + inline void operator=(regExpCxx&& rgx); + + //- Assign and compile pattern from a character array. + // Matching is case sensitive. + inline void operator=(const char* pattern); + + //- Assign and compile pattern from string. + // Matching is case sensitive. + inline void operator=(const std::string& pattern); + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "regExpCxxI.H" + +#endif + +// ************************************************************************* // diff --git a/src/OpenFOAM/primitives/strings/regex/regExpCxxI.H b/src/OpenFOAM/primitives/strings/regex/regExpCxxI.H new file mode 100644 index 0000000000..92d84a0037 --- /dev/null +++ b/src/OpenFOAM/primitives/strings/regex/regExpCxxI.H @@ -0,0 +1,228 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2017-2019 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // + +inline std::regex::flag_type Foam::regExpCxx::syntax() +{ + // 0 = extended, 1 = ECMAScript + return + ( + regExpCxx::grammar + ? std::regex::ECMAScript + : std::regex::extended + ); +} + + +inline bool Foam::regExpCxx::meta(const char c) +{ + return + ( + (c == '.') // any character + || (c == '*' || c == '+' || c == '?') // quantifiers + || (c == '(' || c == ')' || c == '|') // grouping/branching + || (c == '[' || c == ']') // range + ); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +inline Foam::regExpCxx::regExpCxx() +: + re_(), + ok_(false) +{} + + +inline Foam::regExpCxx::regExpCxx(const regExpCxx& rgx) +: + re_(rgx.re_), + ok_(rgx.ok_) +{} + + +inline Foam::regExpCxx::regExpCxx(regExpCxx&& rgx) +: + re_(std::move(rgx.re_)), + ok_(rgx.ok_) +{ + rgx.ok_ = false; +} + + +inline Foam::regExpCxx::regExpCxx(const char* pattern) +: + re_(), + ok_(false) +{ + set(pattern, false); +} + + +inline Foam::regExpCxx::regExpCxx(const std::string& pattern) +: + re_(), + ok_(false) +{ + set(pattern, false); +} + + +inline Foam::regExpCxx::regExpCxx(const char* pattern, bool ignoreCase) +: + re_(), + ok_(false) +{ + set(pattern, ignoreCase); +} + + +inline Foam::regExpCxx::regExpCxx(const std::string& pattern, bool ignoreCase) +: + re_(), + ok_(false) +{ + set(pattern, ignoreCase); +} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +inline bool Foam::regExpCxx::empty() const +{ + return !ok_; +} + + +inline bool Foam::regExpCxx::exists() const +{ + return ok_; +} + + +inline unsigned Foam::regExpCxx::ngroups() const +{ + return ok_ ? re_.mark_count() : 0; +} + + +inline bool Foam::regExpCxx::nocase() const +{ + return ok_ && ((re_.flags() & std::regex::icase) == std::regex::icase); +} + + +inline bool Foam::regExpCxx::clear() +{ + if (ok_) + { + re_.assign(""); + ok_ = false; + + return true; + } + + return false; +} + + +inline void Foam::regExpCxx::swap(regExpCxx& rgx) +{ + re_.swap(rgx.re_); + std::swap(ok_, rgx.ok_); +} + + +inline std::string::size_type Foam::regExpCxx::find(const std::string& text) const +{ + std::smatch mat; + if (!text.empty() && std::regex_search(text, mat, re_)) + { + return mat.position(0); + } + + return std::string::npos; +} + + +inline bool Foam::regExpCxx::search(const std::string& text) const +{ + return (ok_ && !text.empty() && std::regex_search(text, re_)); +} + + +inline bool Foam::regExpCxx::match(const std::string& text) const +{ + return (ok_ && !text.empty() && std::regex_match(text, re_)); +} + + +inline bool Foam::regExpCxx::match +( + const std::string& text, + std::smatch& matches +) const +{ + return std::regex_match(text, matches, re_); +} + + +// * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * // + +inline bool Foam::regExpCxx::operator()(const std::string& text) const +{ + return match(text); +} + + +inline void Foam::regExpCxx::operator=(const regExpCxx& rgx) +{ + re_ = rgx.re_; + ok_ = rgx.ok_; +} + + +inline void Foam::regExpCxx::operator=(regExpCxx&& rgx) +{ + clear(); + swap(rgx); +} + + +inline void Foam::regExpCxx::operator=(const char* pattern) +{ + set(pattern); +} + + +inline void Foam::regExpCxx::operator=(const std::string& pattern) +{ + set(pattern); +} + + +// ************************************************************************* // -- GitLab