ENH: disentangle testing and quoting of regex characters

- originally had tests for regex meta characters strewn across
  regExp classes as well as wordRe, keyType, string.
  And had special-purpose quotemeta static function within string
  that relied on special naming convention for testing the meta
  characters.

  The regex meta character testing/handling now relegated entirely
  to the regExp class(es).
  Relocate quotemeta to stringOps, with a predicate.

- avoid code duplication. Reuse some regExpCxx methods in regExpPosix
This commit is contained in:
Mark Olesen 2021-04-09 10:49:13 +02:00 committed by Andrew Heather
parent cdbc3e2de6
commit 57c1fceabf
14 changed files with 273 additions and 254 deletions

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2013 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -140,8 +141,8 @@ int main(int argc, char *argv[])
bool changed = false;
for (label orig = 0; orig < names.size()-1; ++orig)
{
// skip patterns or entries that have already been done
if (names[orig].empty() || wordRe::isPattern(names[orig]))
// Skip patterns or entries that have already been done
if (names[orig].empty() || regExp::is_meta(names[orig]))
{
continue;
}
@ -150,15 +151,15 @@ int main(int argc, char *argv[])
for (label check = orig+1; check < names.size(); ++check)
{
// skip patterns or entries that have already been done
if (names[check].empty() || wordRe::isPattern(names[check]))
// Skip patterns or entries that have already been done
if (names[check].empty() || regExp::is_meta(names[check]))
{
continue;
}
const dictionary& dict2 = solverDict.subDict(names[check]);
// check for identical content
// Check for identical content
if (checkDictionaryContent(dict1, dict2))
{
names[orig] += "|" + names[check];

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2019 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -34,6 +34,7 @@ Description
#include "IFstream.H"
#include "Switch.H"
#include "stringOps.H"
#include "SubStrings.H"
#include "regExpCxx.H"
#ifndef _WIN32
@ -294,19 +295,16 @@ int main(int argc, char *argv[])
argList::noFunctionObjects();
argList::noParallel();
argList::addBoolOption
(
"cxx",
"Test C++11 regular expressions"
);
argList::addBoolOption("cxx", "Test C++11 regular expressions");
#ifndef _WIN32
argList::addBoolOption
(
"posix",
"Test POSIX regular expressions"
);
argList::addBoolOption("posix", "Test POSIX regular expressions");
#endif
argList::addOption
(
"regex",
"expression",
"regular expression to test"
);
argList::addArgument("file");
argList::addArgument("...");
@ -315,24 +313,50 @@ int main(int argc, char *argv[])
#include "setRootCase.H"
// Newer compilers support regex directly
#ifdef _GLIBCXX_RELEASE
Info<< "_GLIBCXX_RELEASE = " << (_GLIBCXX_RELEASE) << nl;
#endif
if (std::is_same<regExp, regExpCxx>::value)
{
Info<<"Foam::regExp uses C++11 regex" << nl << nl;
Info<< "Foam::regExp uses C++11 regex" << nl;
}
#ifndef _WIN32
if (std::is_same<regExp, regExpPosix>::value)
{
Info<<"Foam::regExp uses POSIX regex" << nl << nl;
Info<< "Foam::regExp uses POSIX regex" << nl;
}
#endif
if (!args.count({"cxx", "posix"}))
{
Info<< "Specified one or more of -cxx, -posix" << nl;
return 1;
args.setOption("cxx");
Info<< "Assuming -cxx as default" << nl;
}
Info<< nl;
if (args.size() < 2)
if (args.found("regex"))
{
std::string expr(args["regex"]);
Info<< "regex: " << expr << nl;
Info<< "(cxx)" << nl
<< "meta : " << Switch(regExpCxx::is_meta(expr)) << nl
<< "quotemeta: "
<< stringOps::quotemeta(expr, regExpCxx::meta()) << nl
<< nl;
#ifndef _WIN32
Info<< "(posix):" << nl
<< "meta : " << Switch(regExpPosix::is_meta(expr)) << nl
<< "quotemeta: "
<< stringOps::quotemeta(expr, regExpPosix::meta()) << nl
<< nl;
#endif
Info<< nl;
}
else if (args.size() < 2)
{
Info<< "No test files specified .. restrict to general tests" << nl;
@ -351,7 +375,8 @@ int main(int argc, char *argv[])
for (label argi = 1; argi < args.size(); ++argi)
{
List<regexTest> tests(IFstream(args[argi])());
IFstream is(args[argi]);
List<regexTest> tests(is);
Info<< "Test expressions:" << tests << endl;
IOobject::writeDivider(Info) << endl;

View File

@ -40,7 +40,7 @@ int Foam::regExpPosix::grammar(0);
namespace
{
// Verify that the entire len was matched
// Matched entire length
static inline bool fullMatch(const regmatch_t& m, const regoff_t len)
{
return (m.rm_so == 0 && m.rm_eo == len);

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2017-2019 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -57,8 +57,8 @@ SourceFiles
#ifndef regExpPosix_H
#define regExpPosix_H
#include "regExpCxx.H"
#include <regex.h>
#include <string>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -66,8 +66,7 @@ namespace Foam
{
// Forward Declarations
template<class String> class SubStrings;
template<class StringType> class SubStrings;
/*---------------------------------------------------------------------------*\
Class regExpPosix Declaration
@ -77,7 +76,7 @@ class regExpPosix
{
// Private Data
//- Precompiled regular expression
//- Compiled regular expression
regex_t* preg_;
public:
@ -96,39 +95,53 @@ public:
// 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);
//- Test if character is a regex meta-character
inline static bool is_meta(const char c) noexcept
{
return regExpCxx::is_meta(c);
}
//- Test if string contains any (unquoted) meta-characters
inline static bool is_meta
(
const std::string& str,
const char quote = '\\'
)
{
return regExpCxx::is_meta(str, quote);
}
// Public Classes
//- Functor wrapper for testing meta-characters
using meta = regExpCxx::meta;
// Constructors
//- Construct null
inline regExpPosix();
//- Default construct
inline regExpPosix() noexcept;
//- 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);
inline regExpPosix(regExpPosix&& rgx) noexcept;
//- Construct from character array, optionally ignore case
inline regExpPosix(const char* pattern, bool ignoreCase);
inline explicit regExpPosix
(
const char* pattern,
const bool ignoreCase = false
);
//- Construct from string, optionally ignore case
inline regExpPosix(const std::string& pattern, bool ignoreCase);
inline explicit regExpPosix
(
const std::string& pattern,
const bool ignoreCase = false
);
//- Destructor

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2019 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,61 +27,15 @@ License
#include <algorithm>
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
inline bool Foam::regExpPosix::meta(char c)
{
return
(
(c == '.') // any character
|| (c == '*' || c == '+' || c == '?') // quantifiers
|| (c == '(' || c == ')' || c == '|') // grouping/branching
|| (c == '[' || c == ']') // range
);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline Foam::regExpPosix::regExpPosix()
inline Foam::regExpPosix::regExpPosix() noexcept
:
preg_(nullptr)
{}
inline Foam::regExpPosix::regExpPosix(const char* pattern)
:
preg_(nullptr)
{
set(pattern, false);
}
inline Foam::regExpPosix::regExpPosix(const std::string& pattern)
:
preg_(nullptr)
{
set(pattern, false);
}
inline Foam::regExpPosix::regExpPosix(const char* pattern, bool ignoreCase)
:
preg_(nullptr)
{
set(pattern, ignoreCase);
}
inline Foam::regExpPosix::regExpPosix(const std::string& pattern, bool ignoreCase)
:
preg_(nullptr)
{
set(pattern, ignoreCase);
}
inline Foam::regExpPosix::regExpPosix(regExpPosix&& rgx)
inline Foam::regExpPosix::regExpPosix(regExpPosix&& rgx) noexcept
:
preg_(rgx.preg_)
{
@ -89,6 +43,30 @@ inline Foam::regExpPosix::regExpPosix(regExpPosix&& rgx)
}
inline Foam::regExpPosix::regExpPosix
(
const char* pattern,
const bool ignoreCase
)
:
preg_(nullptr)
{
set(pattern, ignoreCase);
}
inline Foam::regExpPosix::regExpPosix
(
const std::string& pattern,
const bool ignoreCase
)
:
preg_(nullptr)
{
set(pattern, ignoreCase);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
inline Foam::regExpPosix::~regExpPosix()
@ -143,8 +121,12 @@ inline bool Foam::regExpPosix::operator()(const std::string& text) const
inline void Foam::regExpPosix::operator=(regExpPosix&& rgx)
{
clear();
swap(rgx);
if (this != &rgx)
{
// Self-assignment is a no-op
clear();
swap(rgx);
}
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2019 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -80,6 +80,7 @@ class regExpCxx
//- Track if input pattern was OK - ie, has a length
bool ok_;
// Private Member Functions
//- Select grammar based on regExpCxx optimisationSwitch
@ -102,39 +103,67 @@ public:
// Static Member Functions
//- Test if character appears to be a regular expression meta-character
// \return true if character is one of the following:
//- Test if character is a regex 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);
// \note Regex bounds '{', '}' are not considered
inline static bool is_meta(const char c) noexcept;
//- Test if string contains any (unquoted) meta-characters
inline static bool is_meta
(
const std::string& str,
const char quote = '\\'
);
// Public Classes
//- Functor wrapper for testing meta-characters
struct meta
{
//- Test if character is a regex meta-character
bool operator()(const char c) const noexcept
{
return is_meta(c);
}
//- Test string for meta-characters
bool operator()(const std::string& s, const char q = '\\') const
{
return is_meta(s, q);
}
};
// Constructors
//- Construct null
//- Default construct
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);
inline regExpCxx(regExpCxx&& rgx) noexcept;
//- Construct from character array, optionally ignore case
inline regExpCxx(const char* pattern, bool ignoreCase);
inline explicit regExpCxx
(
const char* pattern,
const bool ignoreCase = false
);
//- Construct from string, optionally ignore case
inline regExpCxx(const std::string& pattern, bool ignoreCase);
inline explicit regExpCxx
(
const std::string& pattern,
const bool ignoreCase = false
);
//- Destructor

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2019 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -39,7 +39,7 @@ inline std::regex::flag_type Foam::regExpCxx::syntax()
}
inline bool Foam::regExpCxx::meta(const char c)
inline bool Foam::regExpCxx::is_meta(const char c) noexcept
{
return
(
@ -51,6 +51,32 @@ inline bool Foam::regExpCxx::meta(const char c)
}
inline bool Foam::regExpCxx::is_meta
(
const std::string& str,
const char quote
)
{
bool escaped = false;
for (const char c : str)
{
if (quote && c == quote)
{
escaped = !escaped; // toggle state
}
else if (escaped)
{
escaped = false;
}
else if (is_meta(c))
{
return true;
}
}
return false;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline Foam::regExpCxx::regExpCxx()
@ -67,7 +93,7 @@ inline Foam::regExpCxx::regExpCxx(const regExpCxx& rgx)
{}
inline Foam::regExpCxx::regExpCxx(regExpCxx&& rgx)
inline Foam::regExpCxx::regExpCxx(regExpCxx&& rgx) noexcept
:
re_(std::move(rgx.re_)),
ok_(rgx.ok_)
@ -76,25 +102,11 @@ inline Foam::regExpCxx::regExpCxx(regExpCxx&& rgx)
}
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)
inline Foam::regExpCxx::regExpCxx
(
const char* pattern,
const bool ignoreCase
)
:
re_(),
ok_(false)
@ -103,7 +115,11 @@ inline Foam::regExpCxx::regExpCxx(const char* pattern, bool ignoreCase)
}
inline Foam::regExpCxx::regExpCxx(const std::string& pattern, bool ignoreCase)
inline Foam::regExpCxx::regExpCxx
(
const std::string& pattern,
const bool ignoreCase
)
:
re_(),
ok_(false)
@ -208,15 +224,23 @@ inline bool Foam::regExpCxx::operator()(const std::string& text) const
inline void Foam::regExpCxx::operator=(const regExpCxx& rgx)
{
re_ = rgx.re_;
ok_ = rgx.ok_;
if (this != &rgx)
{
// Self-assignment is a no-op
re_ = rgx.re_;
ok_ = rgx.ok_;
}
}
inline void Foam::regExpCxx::operator=(regExpCxx&& rgx)
{
clear();
swap(rgx);
if (this != &rgx)
{
// Self-assignment is a no-op
clear();
swap(rgx);
}
}

View File

@ -192,11 +192,6 @@ public:
template<class String>
static inline bool valid(const std::string& str);
//- Does this string contain meta-characters?
// The meta characters can be optionally quoted.
template<class String>
static inline bool meta(const std::string& str, const char quote='\\');
//- Strip invalid characters from the given string
template<class String>
static inline bool stripInvalid(std::string& str);
@ -205,14 +200,6 @@ public:
template<class String>
static inline String validate(const std::string& str);
//- Return a String with quoted meta-characters from the given string
template<class String>
static inline string quotemeta
(
const std::string& str,
const char quote = '\\'
);
// Member Functions

View File

@ -172,68 +172,6 @@ inline bool Foam::string::stripInvalid(std::string& str)
}
template<class String>
inline bool Foam::string::meta(const std::string& str, const char quote)
{
int escaped = 0;
for (auto iter = str.cbegin(); iter != str.cend(); ++iter)
{
const char c = *iter;
if (quote && c == quote)
{
escaped ^= 1; // toggle state
}
else if (escaped)
{
escaped = 0;
}
else if (String::meta(c))
{
return true;
}
}
return false;
}
template<class String>
inline Foam::string
Foam::string::quotemeta(const std::string& str, const char quote)
{
if (!quote)
{
return str;
}
string sQuoted;
sQuoted.reserve(2*str.size());
int escaped = 0;
for (auto iter = str.cbegin(); iter != str.cend(); ++iter)
{
const char c = *iter;
if (c == quote)
{
escaped ^= 1; // toggle state
}
else if (escaped)
{
escaped = 0;
}
else if (String::meta(c))
{
sQuoted += quote;
}
sQuoted += c;
}
sQuoted.shrink_to_fit();
return sQuoted;
}
template<class String>
inline String Foam::string::validate(const std::string& str)
{

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -77,6 +77,15 @@ namespace stringOps
return wordRes::matcher(patterns)(text);
}
//- Quote any meta-characters in given string
template<class StringType, class UnaryPredicate>
StringType quotemeta
(
const StringType& str,
const UnaryPredicate& meta,
const char quote = '\\'
);
//- Expand occurrences of variables according to the mapping
//- and return the expanded string.
//

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2018 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,6 +27,45 @@ License
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class StringType, class UnaryPredicate>
StringType Foam::stringOps::quotemeta
(
const StringType& str,
const UnaryPredicate& meta,
const char quote
)
{
if (str.empty() || !quote)
{
return str;
}
StringType result;
result.reserve(1.5*str.size()); // Moderately pessimistic
bool escaped = false;
for (const char c : str)
{
if (c == quote)
{
escaped = !escaped; // toggle state
}
else if (escaped)
{
escaped = false;
}
else if (meta(c))
{
result += quote;
}
result += c;
}
result.shrink_to_fit();
return result;
}
template<class StringType>
Foam::SubStrings<StringType> Foam::stringOps::split
(

View File

@ -153,17 +153,11 @@ public:
// Member Functions
//- Is this a meta character?
inline static bool meta(char c);
//- Is this character valid for a wordRe?
// This is largely identical with what word accepts, but also
// permit brace-brackets, which are valid for some regexs.
inline static bool valid(char c);
//- Test string for regular expression meta characters
inline static bool isPattern(const std::string& str);
// Access
@ -211,9 +205,6 @@ public:
// Miscellaneous
//- Return a string with quoted meta-characters
inline string quotemeta() const;
//- Output some basic info
Ostream& info(Ostream& os) const;

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2019 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -28,24 +28,12 @@ License
// * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * * //
inline bool Foam::wordRe::meta(char c)
{
return regExp::meta(c);
}
inline bool Foam::wordRe::valid(char c)
{
return keyType::valid(c);
}
inline bool Foam::wordRe::isPattern(const std::string& str)
{
return string::meta<regExp>(str);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline Foam::wordRe::wordRe()
@ -184,7 +172,7 @@ inline bool Foam::wordRe::compile(const compOption opt)
}
else if (opt & wordRe::DETECT)
{
comp = string::meta<regExp>(*this) || !string::valid<word>(*this);
comp = regExp::is_meta(*this) || !string::valid<word>(*this);
}
else if (opt & wordRe::ICASE)
{
@ -237,12 +225,6 @@ inline bool Foam::wordRe::match(const std::string& text, bool literal) const
}
inline Foam::string Foam::wordRe::quotemeta() const
{
return string::quotemeta<regExp>(*this);
}
inline void Foam::wordRe::set(const std::string& str, const compOption opt)
{
assign(str);

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,6 +26,7 @@ License
\*---------------------------------------------------------------------------*/
#include "ddt2.H"
#include "stringOps.H"
#include "stringListOps.H"
#include "volFields.H"
#include "dictionary.H"
@ -107,7 +108,7 @@ Foam::functionObjects::ddt2::ddt2
:
fvMeshFunctionObject(name, runTime, dict),
selectFields_(),
resultName_(word::null),
resultName_(),
denyField_(),
results_(),
mag_(dict.getOrDefault("mag", false))
@ -150,10 +151,8 @@ bool Foam::functionObjects::ddt2::read(const dictionary& dict)
{
denyField_.set
(
string::quotemeta<regExp>
(
resultName_
).replace("@@", "(.+)")
stringOps::quotemeta(resultName_, regExp::meta())
.replace("@@", "(.+)")
);
return true;