From 3b77493abcdc6d954faab4ab3311a936d5105b20 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Sun, 7 Oct 2018 18:30:33 +0200
Subject: [PATCH] ENH: wordRes matcher method that distinguishes literal vs.
 regex

- useful for customizing the behaviour of white/black lists depending
  on the type of the match.
---
 applications/test/wordRe/Test-wordRe.C        | 113 ++++++++++--------
 .../primitives/strings/wordRes/wordRes.H      |  34 ++++--
 .../primitives/strings/wordRes/wordResI.H     |  37 ++++++
 3 files changed, 129 insertions(+), 55 deletions(-)

diff --git a/applications/test/wordRe/Test-wordRe.C b/applications/test/wordRe/Test-wordRe.C
index 98c4b6ebc63..e420d4bd034 100644
--- a/applications/test/wordRe/Test-wordRe.C
+++ b/applications/test/wordRe/Test-wordRe.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2017-2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -22,6 +22,7 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Description
+    Test word/regex
 
 \*---------------------------------------------------------------------------*/
 
@@ -36,6 +37,16 @@ Description
 
 using namespace Foam;
 
+
+word typeOf(wordRe::compOption retval)
+{
+    if (wordRe::LITERAL == retval) return "(literal)";
+    if (wordRe::UNKNOWN == retval) return "(unknown)";
+    if (wordRe::REGEX == retval)   return "(regex)";
+    return "";
+}
+
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // Main program:
 
@@ -53,28 +64,30 @@ int main(int argc, char *argv[])
         {"this", wordRe::LITERAL},
         {"x.*", wordRe::REGEX},
         {"file[a-b]", wordRe::REGEX},
+        {"xvalues", wordRe::LITERAL},
+        {"xv.*", wordRe::REGEX},
     };
 
-    if (true)
+    if (false)
     {
-        Info<<"keyType: " << keyre << endl;
+        Info<<"keyType: " << keyre << nl;
 
         keyType key2(std::move(keyre));
 
-        Info<<"move construct: <" << keyre << "> <" << key2 << ">" << endl;
+        Info<<"move construct: <" << keyre << "> <" << key2 << ">" << nl;
 
         keyre = std::move(key2);
 
-        Info<<"move assign: <" << keyre << "> <" << key2 << ">" << endl;
+        Info<<"move assign: <" << keyre << "> <" << key2 << ">" << nl;
 
         keyType key3;
 
         keyre.swap(key3);
 
-        Info<<"swap: <" << keyre << "> <" << key3 << ">" << endl;
+        Info<<"swap: <" << keyre << "> <" << key3 << ">" << nl;
 
         keyre = std::move(key3);
-        Info<<"move assign: <" << keyre << "> <" << key3 << ">" << endl;
+        Info<<"move assign: <" << keyre << "> <" << key3 << ">" << nl;
 
         return 0;
     }
@@ -83,86 +96,92 @@ int main(int argc, char *argv[])
     {
         wordRe keyre("y.*", wordRe::REGEX);
 
-        Info<<"wordRe: " << keyre << endl;
+        Info<<"wordRe: " << keyre << nl;
 
         wordRe key2(std::move(keyre));
 
-        Info<<"keyTypes: " << keyre << " " << key2 << endl;
+        Info<<"keyTypes: " << keyre << " " << key2 << nl;
 
         keyre = std::move(key2);
 
-        Info<<"keyTypes: " << keyre << " " << key2 << endl;
+        Info<<"keyTypes: " << keyre << " " << key2 << nl;
 
         wordRe key3;
 
         keyre.swap(key3);
 
-        Info<<"keyTypes: <" << keyre << "> <" << key3 << ">" << endl;
+        Info<<"keyTypes: <" << keyre << "> <" << key3 << ">" << nl;
 
         keyre = std::move(key3);
-        Info<<"keyTypes: <" << keyre << "> <" << key3 << ">" << endl;
+        Info<<"keyTypes: <" << keyre << "> <" << key3 << ">" << nl;
 
         return 0;
     }
 
-    wordRes wrelist(wordrelist);
+    wordRes wres1(wordrelist);
+
+    Info<< "re-list:" << wres1 << nl;
+    Info<< "match this: " << wres1("this") << nl;
+    Info<< "match xyz: "  << wres1("xyz") << nl;
+    Info<< "match zyx: "  << wres1("zyx") << nl;
+    Info<< "match xyz: "  << wres1.match("xyz") << nl;
+    Info<< "match any: "  << predicates::always()("any junk") << nl;
+
+    Info<< "match xvalues: "  << wres1.match("xvalues") << nl;
+    Info<< "matched xvalues = "  << typeOf(wres1.matched("xvalues")) << nl;
+    Info<< "matched xval = "  << typeOf(wres1.matched("xval")) << nl;
+    Info<< "matched zyx = "  << typeOf(wres1.matched("zyx")) << nl;
 
-    Info<< "re-list:" << wrelist << endl;
-    Info<< "match this: " << wrelist("this") << endl;
-    Info<< "match xyz: "  << wrelist("xyz") << endl;
-    Info<< "match zyx: "  << wrelist("zyx") << endl;
-    Info<< "match xyz: "  << wrelist.match("xyz") << endl;
-    Info<< "match any: "  << predicates::always()("any junk") << endl;
-    Info<< "keyre match: "  << keyre("xyz") << endl;
-    Info<< "string match: "  << string("this").match("xyz") << endl;
-    Info<< "string match: "  << string("x.*")("xyz") << endl;
-    Info<< "string match: "  << string("x.*")(keyre) << endl;
+    Info<< "keyre match: "  << keyre("xyz") << nl;
+    Info<< "string match: "  << string("this").match("xyz") << nl;
+    Info<< "string match: "  << string("x.*")("xyz") << nl;
+    Info<< "string match: "  << string("x.*")(keyre) << nl;
 
-    wordRe(s1, wordRe::DETECT).info(Info) << endl;
-    wordRe(s2).info(Info) << endl;
-    wordRe(s2, wordRe::DETECT).info(Info) << endl;
-    wordRe(s3, wordRe::REGEX).info(Info) << endl;
+    wordRe(s1, wordRe::DETECT).info(Info) << nl;
+    wordRe(s2).info(Info) << nl;
+    wordRe(s2, wordRe::DETECT).info(Info) << nl;
+    wordRe(s3, wordRe::REGEX).info(Info) << nl;
 
     wre = "this .* file";
 
-    Info<<"substring: " << wre.substr(4) << endl;
+    Info<<"substring: " << wre.substr(4) << nl;
 
-    wre.info(Info) << endl;
+    wre.info(Info) << nl;
     wre = s1;
-    wre.info(Info) << endl;
+    wre.info(Info) << nl;
     wre.uncompile();
-    wre.info(Info) << endl;
+    wre.info(Info) << nl;
 
     wre = "something";
-    wre.info(Info) << " before" << endl;
+    wre.info(Info) << " before" << nl;
     wre.uncompile();
-    wre.info(Info) << " uncompiled" << endl;
+    wre.info(Info) << " uncompiled" << nl;
     wre.compile(wordRe::DETECT);
-    wre.info(Info) << " after DETECT" << endl;
+    wre.info(Info) << " after DETECT" << nl;
     wre.compile(wordRe::ICASE);
-    wre.info(Info) << " after ICASE" << endl;
+    wre.info(Info) << " after ICASE" << nl;
     wre.compile(wordRe::DETECT_ICASE);
-    wre.info(Info) << " after DETECT_ICASE" << endl;
+    wre.info(Info) << " after DETECT_ICASE" << nl;
 
     wre = "something .* value";
-    wre.info(Info) << " before" << endl;
+    wre.info(Info) << " before" << nl;
     wre.uncompile();
-    wre.info(Info) << " uncompiled" << endl;
+    wre.info(Info) << " uncompiled" << nl;
     wre.compile(wordRe::DETECT);
-    wre.info(Info) << " after DETECT" << endl;
+    wre.info(Info) << " after DETECT" << nl;
     wre.uncompile();
-    wre.info(Info) << " uncompiled" << endl;
+    wre.info(Info) << " uncompiled" << nl;
     wre.compile();
-    wre.info(Info) << " re-compiled" << endl;
+    wre.info(Info) << " re-compiled" << nl;
 
     wre.set("something .* value", wordRe::LITERAL);
-    wre.info(Info) << " set as LITERAL" << endl;
+    wre.info(Info) << " set as LITERAL" << nl;
 
     IOobject::writeDivider(Info);
 
     List<Tuple2<wordRe, string>> rawList(IFstream("testRegexps")());
-    Info<< "input list:" << rawList << endl;
-    IOobject::writeDivider(Info) << endl;
+    Info<< "input list:" << rawList << nl;
+    IOobject::writeDivider(Info) << nl;
 
     forAll(rawList, elemI)
     {
@@ -174,7 +193,7 @@ int main(int argc, char *argv[])
             << "(" << wre.match(str, true) << ")"
             << " match:" << wre.match(str)
             << "  str=" << str
-            << endl;
+            << nl;
 
         wordRe wre2;
         wre2.set(wre, wordRe::ICASE);
@@ -182,11 +201,11 @@ int main(int argc, char *argv[])
         wre2.info(Info)
             << " match:" << wre2.match(str)
             << "  str=" << str
-            << endl;
+            << nl;
 
     }
 
-    Info<< endl;
+    Info<< "\nEnd\n" << endl;
 
     return 0;
 }
diff --git a/src/OpenFOAM/primitives/strings/wordRes/wordRes.H b/src/OpenFOAM/primitives/strings/wordRes/wordRes.H
index 28cf35b9727..197823682c7 100644
--- a/src/OpenFOAM/primitives/strings/wordRes/wordRes.H
+++ b/src/OpenFOAM/primitives/strings/wordRes/wordRes.H
@@ -53,7 +53,7 @@ class wordRes
 {
     // Private Methods
 
-        //- Check for any match of text in list of matchers
+        //- Smart match as literal or regex, stopping on the first match.
         inline static bool found_match
         (
             const UList<wordRe>& patterns,
@@ -61,6 +61,17 @@ class wordRes
             bool literal=false
         );
 
+        //- Smart match across entire list, returning the match type.
+        //  Stops on the first literal match, or continues to examine
+        //  if a regex match occurs.
+        //  \return wordRe::LITERAL, wordRe::REGEX on match and
+        //      wordRe::UNKNOWN otherwise.
+        inline static wordRe::compOption found_matched
+        (
+            const UList<wordRe>& patterns,
+            const std::string& text
+        );
+
 
 public:
 
@@ -111,16 +122,23 @@ public:
         //  No filtering attempted on regular expressions.
         void uniq();
 
-        //- Return true if string matches ANY of the regular expressions
-        //  Smart match as regular expression or as a string.
-        //  Optionally force a literal match only
-        inline bool match(const std::string& text, bool literal=false) const;
+        //- Smart match as literal or regex, stopping on the first match.
+        //
+        //  \param literal Force literal match only.
+        //  \return True if text matches ANY of the entries.
+        inline bool match(const std::string& text, bool literal = false) const;
+
+        //- Smart match in the list of matchers, returning the match type.
+        //  It stops if there is a literal match, or continues to examine
+        //  other regexs.
+        //  \return LITERAL if a lteral match was found, REGEX if a regex
+        //      match was found and UNKNOWN otherwise.
+        inline wordRe::compOption matched(const std::string& text) const;
 
 
-    // Member operators
+    // Member Operators
 
-        //- Perform smart match on text, as per match()
-        //  Allows use as a predicate.
+        //- Identical to match(), for use as a predicate.
         inline bool operator()(const std::string& text) const;
 };
 
diff --git a/src/OpenFOAM/primitives/strings/wordRes/wordResI.H b/src/OpenFOAM/primitives/strings/wordRes/wordResI.H
index ab602ee1f8e..65cbe2fe465 100644
--- a/src/OpenFOAM/primitives/strings/wordRes/wordResI.H
+++ b/src/OpenFOAM/primitives/strings/wordRes/wordResI.H
@@ -50,6 +50,36 @@ inline bool Foam::wordRes::found_match
 }
 
 
+inline Foam::wordRe::compOption Foam::wordRes::found_matched
+(
+    const UList<wordRe>& patterns,
+    const std::string& text
+)
+{
+    auto retval(wordRe::compOption::UNKNOWN);
+
+    for (const wordRe& select : patterns)
+    {
+        if (select.isLiteral())
+        {
+            if (select.match(text, true))
+            {
+                return wordRe::compOption::LITERAL;
+            }
+        }
+        else if (wordRe::compOption::UNKNOWN == retval)
+        {
+            if (select.match(text, false))
+            {
+                retval = wordRe::compOption::REGEX;
+            }
+        }
+    }
+
+    return retval;
+}
+
+
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 inline bool Foam::wordRes::match(const std::string& text, bool literal) const
@@ -58,6 +88,13 @@ inline bool Foam::wordRes::match(const std::string& text, bool literal) const
 }
 
 
+inline Foam::wordRe::compOption
+Foam::wordRes::matched(const std::string& text) const
+{
+    return found_matched(*this, text);
+}
+
+
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
 inline bool Foam::wordRes::operator()(const std::string& text) const
-- 
GitLab