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.
This commit is contained in:
Mark Olesen 2019-03-14 13:24:23 +01:00 committed by Andrew Heather
parent e0e0414726
commit 487877377d
17 changed files with 1170 additions and 330 deletions

View File

@ -1,3 +0,0 @@
Test-regex.C
EXE = $(FOAM_USER_APPBIN)/Test-regex

View File

@ -0,0 +1,3 @@
Test-regex1.C
EXE = $(FOAM_USER_APPBIN)/Test-regex1

View File

@ -2,10 +2,8 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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,22 +82,144 @@ 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;
for (std::smatch::size_type i = 1; i < sm.size(); ++i)
{
os << " " << sm.str(i);
}
regExp::results_type match;
return os;
}
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 (RegexType(nullptr).match(me))
{
Info<< "fail - matched: " << me << endl;
}
else
{
Info<< "pass - null pointer is no expression" << endl;
}
}
catch (const Foam::error& err)
{
Info<< "Caught FatalError " << err << nl << endl;
}
try
{
// Normal match
if (RegexType("[Mm]ar[ck]").match(me))
{
Info<< "pass - matched: " << me << endl;
}
else
{
Info<< "no match" << endl;
}
}
catch (const Foam::error& err)
{
Info<< "Caught FatalError " << err << nl << endl;
}
try
{
// Match ignore case
if (RegexType("mar[ck]", true).match(me))
{
Info<< "pass - matched: " << me << endl;
}
else
{
Info<< "no match" << endl;
}
}
catch (const Foam::error& err)
{
Info<< "Caught FatalError " << err << nl << endl;
}
try
{
// Embedded prefix for match ignore case
if (RegexType("(?i)mar[ck]").match(me))
{
Info<< "pass - matched: " << me << endl;
}
else
{
Info<< "no match" << endl;
}
}
catch (const Foam::error& err)
{
Info<< "Caught FatalError " << err << nl << endl;
}
try
{
// Handling of empty expression
if (RegexType("").match(me))
{
Info<< "fail - matched: " << me << endl;
}
else
{
Info<< "pass - no match on empty expression" << endl;
}
}
catch (const Foam::error& err)
{
Info<< "Caught FatalError " << err << nl << endl;
}
try
{
// Embedded prefix - but expression is empty
if (RegexType("(?i)").match(me))
{
Info<< "fail - matched: " << me << endl;
}
else
{
Info<< "pass - no match on empty expression" << endl;
}
}
catch (const Foam::error& err)
{
Info<< "Caught FatalError " << err << nl << endl;
}
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 : rawList)
for (const auto& testseq : tests)
{
const bool expected = testseq.expected;
const string& pat = testseq.pattern;
@ -105,7 +228,7 @@ int main(int argc, char *argv[])
Info<< "Test " << Switch(expected) << ": "
<< str << " =~ m/" << pat.c_str() << "/ == ";
regExp re;
RegexType re;
try
{
@ -137,7 +260,7 @@ int main(int argc, char *argv[])
if (false)
{
regExp re2(std::move(re));
RegexType re2(std::move(re));
Info<<"move construct: " << re.exists() << "/" << re2.exists()
<< endl;
@ -151,112 +274,76 @@ int main(int argc, char *argv[])
}
}
Info<< nl << "test regExp(const char*) ..." << endl;
string me("Mark");
try
{
// Handling of null strings
if (regExp(nullptr).match(me))
{
Info<< "fail - matched: " << me << endl;
}
else
{
Info<< "pass - null pointer is no expression" << endl;
}
}
catch (const Foam::error& err)
{
Info<< "Caught FatalError " << err << nl << endl;
}
try
{
// Normal match
if (regExp("[Mm]ar[ck]").match(me))
{
Info<< "pass - matched: " << me << endl;
}
else
{
Info<< "no match" << endl;
}
}
catch (const Foam::error& err)
{
Info<< "Caught FatalError " << err << nl << endl;
}
try
{
// Match ignore case
if (regExp("mar[ck]", true).match(me))
{
Info<< "pass - matched: " << me << endl;
}
else
{
Info<< "no match" << endl;
}
}
catch (const Foam::error& err)
{
Info<< "Caught FatalError " << err << nl << endl;
}
try
{
// Embedded prefix for match ignore case
if (regExp("(?i)mar[ck]").match(me))
{
Info<< "pass - matched: " << me << endl;
}
else
{
Info<< "no match" << endl;
}
}
catch (const Foam::error& err)
{
Info<< "Caught FatalError " << err << nl << endl;
}
try
{
// Handling of empty expression
if (regExp("").match(me))
{
Info<< "fail - matched: " << me << endl;
}
else
{
Info<< "pass - no match on empty expression" << endl;
}
}
catch (const Foam::error& err)
{
Info<< "Caught FatalError " << err << nl << endl;
}
try
{
// Embedded prefix - but expression is empty
if (regExp("(?i)").match(me))
{
Info<< "fail - matched: " << me << endl;
}
else
{
Info<< "pass - no match on empty expression" << endl;
}
}
catch (const Foam::error& err)
{
Info<< "Caught FatalError " << err << nl << 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;

View File

@ -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

View File

@ -2,10 +2,8 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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

View File

@ -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
// ************************************************************************* //

View File

@ -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

View File

@ -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
// ************************************************************************* //

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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;
}
// ************************************************************************* //

View File

@ -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
// ************************************************************************* //

View File

@ -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);
}
// ************************************************************************* //