diff --git a/applications/test/regex/Test-regex.C b/applications/test/regex/Test-regex.C
index 6996d4445cee96fcea1dd060013df1a5750bbdb5..e79b7ba99828121e41bf305f0d44b03335b3adf1 100644
--- a/applications/test/regex/Test-regex.C
+++ b/applications/test/regex/Test-regex.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.
@@ -30,52 +30,108 @@ Description
 #include "IOobject.H"
 #include "IFstream.H"
 #include "regExp.H"
-#include "List.H"
-#include "Tuple2.H"
+#include "SubStrings.H"
+#include "Switch.H"
 
 using namespace Foam;
 
+
+//- Simple structure for holding regex tests
+struct regexTest
+{
+    bool expected;
+    string pattern;
+    string text;
+
+    friend Istream& operator>>(Istream& is, struct regexTest& obj)
+    {
+        is.readBegin("struct");
+        is >> obj.expected >> obj.pattern >> obj.text;
+        is.readEnd("struct");
+        is.check(FUNCTION_NAME);
+        return is;
+    }
+
+    friend Ostream& operator<<(Ostream& os, const struct regexTest& obj)
+    {
+        os  << "( "
+            << obj.expected << " " << obj.pattern << " " << obj.text
+            << " )";
+        return os;
+    }
+};
+
+// 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)
+{
+    for (std::smatch::size_type i = 1; i < sm.size(); ++i)
+    {
+        os << " " << sm.str(i);
+    }
+
+    return os;
+}
+
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // Main program:
 
 int main(int argc, char *argv[])
 {
-    List<Tuple2<string, string>> rawList(IFstream("testRegexps")());
+    List<regexTest> rawList(IFstream("testRegexps")());
     Info<< "Test expressions:" << rawList << endl;
     IOobject::writeDivider(Info) << endl;
 
-    List<std::string> groups;
+    regExp::results_type match;
+
+    // Expect some failures:
+    const bool throwingError = FatalError.throwExceptions();
 
     // Report matches:
-    forAll(rawList, elemI)
+    for (const auto& testseq : rawList)
     {
-        const string& pat = rawList[elemI].first();
-        const string& str = rawList[elemI].second();
-        regExp re(pat);
+        const bool expected = testseq.expected;
+        const string& pat = testseq.pattern;
+        const string& str = testseq.text;
+
+        Info<< "Test " << Switch(expected) << ": "
+            << str << " =~ m/" << pat.c_str() << "/ == ";
 
-        Info<< str << " =~ m/" << pat.c_str() << "/ == ";
+        regExp re;
 
-        if (re.match(str, groups))
+        try
         {
-            Info<< "true";
-            if (re.ngroups())
+            re = pat;
+
+            if (re.match(str, match))
             {
-                Info<< nl << "groups: " << groups;
+                Info<< "true";
+                if (re.ngroups())
+                {
+                    Info<< " (" << re.ngroups() << " groups):" << match;
+                }
             }
-        }
-        else
-        {
-            if (re.search(str))
+            else if (re.search(str))
             {
-                Info<< " partial match";
+                Info<< "partial match";
             }
             else
             {
                 Info<< "false";
             }
+            Info<< endl;
+        }
+        catch (Foam::error& err)
+        {
+            Info<< "Caught FatalError " << err << nl << endl;
+            continue;
         }
-
-        Info<< endl;
 
         if (false)
         {
@@ -96,68 +152,111 @@ int main(int argc, char *argv[])
     Info<< nl << "test regExp(const char*) ..." << endl;
     string me("Mark");
 
-    // Handling of null strings
-    if (regExp(nullptr).match(me))
+    try
     {
-        Info<< "fail - matched: " << me << endl;
+        // Handling of null strings
+        if (regExp(nullptr).match(me))
+        {
+            Info<< "fail - matched: " << me << endl;
+        }
+        else
+        {
+            Info<< "pass - null pointer is no expression" << endl;
+        }
     }
-    else
+    catch (Foam::error& err)
     {
-        Info<< "pass - null pointer is no expression" << endl;
+        Info<< "Caught FatalError " << err << nl << endl;
     }
 
-    // Normal match
-    if (regExp("[Mm]ar[ck]").match(me))
+    try
     {
-        Info<< "pass - matched: " << me << endl;
+        // Normal match
+        if (regExp("[Mm]ar[ck]").match(me))
+        {
+            Info<< "pass - matched: " << me << endl;
+        }
+        else
+        {
+            Info<< "no match" << endl;
+        }
     }
-    else
+    catch (Foam::error& err)
     {
-        Info<< "no match" << endl;
+        Info<< "Caught FatalError " << err << nl << endl;
     }
 
-    // Match ignore case
-    if (regExp("mar[ck]", true).match(me))
+    try
     {
-        Info<< "pass - matched: " << me << endl;
+        // Match ignore case
+        if (regExp("mar[ck]", true).match(me))
+        {
+            Info<< "pass - matched: " << me << endl;
+        }
+        else
+        {
+            Info<< "no match" << endl;
+        }
     }
-    else
+    catch (Foam::error& err)
     {
-        Info<< "no match" << endl;
+        Info<< "Caught FatalError " << err << nl << endl;
     }
 
-    // Embedded prefix for match ignore case
-    if (regExp("(?i)mar[ck]").match(me))
+    try
     {
-        Info<< "pass - matched: " << me << endl;
+        // Embedded prefix for match ignore case
+        if (regExp("(?i)mar[ck]").match(me))
+        {
+            Info<< "pass - matched: " << me << endl;
+        }
+        else
+        {
+            Info<< "no match" << endl;
+        }
     }
-    else
+    catch (Foam::error& err)
     {
-        Info<< "no match" << endl;
+        Info<< "Caught FatalError " << err << nl << endl;
     }
 
-    // Handling of empty expression
-    if (regExp("").match(me))
+    try
     {
-        Info<< "fail - matched: " << me << endl;
+        // Handling of empty expression
+        if (regExp("").match(me))
+        {
+            Info<< "fail - matched: " << me << endl;
+        }
+        else
+        {
+            Info<< "pass - no match on empty expression" << endl;
+        }
     }
-    else
+    catch (Foam::error& err)
     {
-        Info<< "pass - no match on empty expression" << endl;
+        Info<< "Caught FatalError " << err << nl << endl;
     }
 
-    // Embedded prefix - but expression is empty
-    if (regExp("(?i)").match(me))
+    try
     {
-        Info<< "fail - matched: " << me << endl;
+        // 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;
+        }
     }
-    else
+    catch (Foam::error& err)
     {
-        Info<< "pass - no match on empty expression" << endl;
+        Info<< "Caught FatalError " << err << nl << endl;
     }
 
+    FatalError.throwExceptions(throwingError);
 
-    Info<< endl;
+    Info<< "\nDone" << nl << endl;
 
     return 0;
 }
diff --git a/applications/test/regex/testRegexps b/applications/test/regex/testRegexps
index 6f2d0e2935762290002cb6ee56383ca3c8271624..523780120139ae3a79c98243576a735e77393b54 100644
--- a/applications/test/regex/testRegexps
+++ b/applications/test/regex/testRegexps
@@ -10,27 +10,29 @@
 
 // Pattern, String
 (
-    ( "a.*"  "abc" )        // true
-    ( "a.*"  "bac" )        // false - partial match only
-    ( "a.*"  "abcd" )       // true
-    ( "a.*"  "def" )        // false
-    ( ".*a.*"  "Abc" )      // false
-    ( "(?i).*a.*"  "Abc" )  // true
-    ( "d(.*)f"  "def" )     // true
-    (
+    ( true  "a.*"  "abc" )
+    ( true  "a.*"  "abc" )
+    ( false "a.*"  "bac" )        // partial match only
+    ( true  "a.*"  "abcd" )
+    ( false "a.*"  "def" )
+    ( false ".*a.*"  "Abc" )
+    ( true  "(?i).*a.*"  "Abc" )
+    ( true  "d(.*)([xy]*)([f-p])"  "def" )
+    ( false "d(.*)([xy]*)([f-p])"  "xxdef" )
+    ( true
         " *([A-Za-z]+) *= *([^ /]+) *(//.*)?"
         "   keyword  = value // comment"
-    )   // true
-
+    )
     (
+        false   // partial match only
         "[[:digit:]]"
         "contains 1 or more digits"
-    )   // false - partial match only
-
+    )
     (
+        true
         "[[:digit:]]+-[[:digit:]]+-[[:digit:]]+-[[:digit:]]+"
         "1-905-123-2234"
-    )   // true
+    )
 
 )
 
diff --git a/src/OSspecific/POSIX/regExp.C b/src/OSspecific/POSIX/regExp.C
index 0f9cd7cb21cc95cd68c10dfe2af111d61215a3ee..f53175571dae5d3bbbfe7753b2dc05c27b9929c3 100644
--- a/src/OSspecific/POSIX/regExp.C
+++ b/src/OSspecific/POSIX/regExp.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  |
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -24,61 +24,35 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "regExp.H"
-#include "List.H"
+#include "SubStrings.H"
+#include "error.H"
 
-// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
 
-bool Foam::regExp::matchGrouping
-(
-    const std::string& text,
-    List<std::string>& groups
-) const
+// Verify that the entire len was matched
+static inline bool fullMatch(const regmatch_t& m, const regoff_t len)
 {
-    if (preg_ && !text.empty())
-    {
-        size_t nmatch = ngroups() + 1;
-        regmatch_t pmatch[nmatch];
+    return (m.rm_so == 0 && m.rm_eo == len);
+}
 
-        // Also verify that the entire string was matched.
-        // pmatch[0] is the entire match
-        // pmatch[1..] are the (...) sub-groups
-        if
-        (
-            regexec(preg_, text.c_str(), nmatch, pmatch, 0) == 0
-         && (pmatch[0].rm_so == 0 && pmatch[0].rm_eo == label(text.size()))
-        )
-        {
-            groups.setSize(ngroups());
-            label groupI = 0;
 
-            for (size_t matchI = 1; matchI < nmatch; matchI++)
-            {
-                if (pmatch[matchI].rm_so != -1 && pmatch[matchI].rm_eo != -1)
-                {
-                    groups[groupI] = text.substr
-                    (
-                        pmatch[matchI].rm_so,
-                        pmatch[matchI].rm_eo - pmatch[matchI].rm_so
-                    );
-                }
-                else
-                {
-                    groups[groupI].clear();
-                }
-                groupI++;
-            }
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-            return true;
-        }
+bool Foam::regExp::clear()
+{
+    if (preg_)
+    {
+        regfree(preg_);
+        delete preg_;
+        preg_ = nullptr;
+
+        return true;
     }
 
-    groups.clear();
     return false;
 }
 
 
-// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
-
 bool Foam::regExp::set(const char* pattern, bool ignoreCase)
 {
     clear();
@@ -136,26 +110,11 @@ bool Foam::regExp::set(const std::string& pattern, bool ignoreCase)
 }
 
 
-bool Foam::regExp::clear()
-{
-    if (preg_)
-    {
-        regfree(preg_);
-        delete preg_;
-        preg_ = nullptr;
-
-        return true;
-    }
-
-    return false;
-}
-
-
 std::string::size_type Foam::regExp::find(const std::string& text) const
 {
     if (preg_ && !text.empty())
     {
-        size_t nmatch = 1;
+        const size_t nmatch = 1;
         regmatch_t pmatch[1];
 
         if (regexec(preg_, text.c_str(), nmatch, pmatch, 0) == 0)
@@ -170,21 +129,20 @@ std::string::size_type Foam::regExp::find(const std::string& text) const
 
 bool Foam::regExp::match(const std::string& text) const
 {
-    if (preg_ && !text.empty())
+    const auto len = text.size();
+
+    if (preg_ && len)
     {
-        size_t nmatch = 1;
+        const size_t nmatch = 1;
         regmatch_t pmatch[1];
 
-        // Also verify that the entire string was matched
-        // pmatch[0] is the entire match
-        if
+        // Verify that the entire string was matched
+        // - [0] is the entire match result
+        return
         (
             regexec(preg_, text.c_str(), nmatch, pmatch, 0) == 0
-         && (pmatch[0].rm_so == 0 && pmatch[0].rm_eo == regoff_t(text.size()))
-        )
-        {
-            return true;
-        }
+         && fullMatch(pmatch[0], len)
+        );
     }
 
     return false;
@@ -194,10 +152,54 @@ bool Foam::regExp::match(const std::string& text) const
 bool Foam::regExp::match
 (
     const std::string& text,
-    List<std::string>& groups
+    SubStrings<std::string>& matches
 ) const
 {
-    return matchGrouping(text, groups);
+    matches.clear();
+
+    const auto len = text.size();
+    if (preg_ && len)
+    {
+        const size_t nmatch = ngroups() + 1;
+        regmatch_t pmatch[nmatch];
+
+        // Verify that the entire string was matched
+        // - [0] is the entire match result
+        // - [1..] are the match groups (1..)
+        if
+        (
+            regexec(preg_, text.c_str(), nmatch, pmatch, 0) != 0
+         || !fullMatch(pmatch[0], len)
+        )
+        {
+            return false;
+        }
+
+        matches.reserve(nmatch);
+
+        for (size_t matchi = 0; matchi < nmatch; ++matchi)
+        {
+            const auto& mat = pmatch[matchi];
+
+            if (mat.rm_so != -1 && mat.rm_eo != -1)
+            {
+                matches.append
+                (
+                    text.cbegin() + mat.rm_so,
+                    text.cbegin() + mat.rm_eo
+                );
+            }
+            else
+            {
+                // This may be misleading...
+                matches.append(text.cbegin(), text.cbegin());
+            }
+        }
+
+        return true;
+    }
+
+    return false;
 }
 
 
diff --git a/src/OSspecific/POSIX/regExp.H b/src/OSspecific/POSIX/regExp.H
index c5c78929092cda94c6c3038b8677814c332ca2ad..59417ea7a4a576c3e23646f269101ef98784db2d 100644
--- a/src/OSspecific/POSIX/regExp.H
+++ b/src/OSspecific/POSIX/regExp.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2017-2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -35,6 +35,7 @@ See also
     These differ somewhat from \c Perl and \c sed regular expressions.
 
 SourceFiles
+    regExpI.H
     regExp.C
 
 \*---------------------------------------------------------------------------*/
@@ -50,8 +51,8 @@ SourceFiles
 namespace Foam
 {
 
-// Forward declaration of classes
-template<class T> class List;
+// Forward declarations
+template<class String> class SubStrings;
 
 
 /*---------------------------------------------------------------------------*\
@@ -65,34 +66,22 @@ class regExp
         //- Precompiled regular expression
         regex_t* preg_;
 
+public:
 
-    // Private Member Functions
-
-        //- Disallow default bitwise copy construct
-        regExp(const regExp&) = delete;
-
-        //- Disallow default bitwise assignment
-        void operator=(const regExp&) = delete;
-
-        //- Return true if it matches and sets the sub-groups matched.
-        bool matchGrouping
-        (
-            const std::string& text,
-            List<std::string>& groups
-        ) const;
-
+    //- Type for matches
+    typedef SubStrings<std::string> results_type;
 
-public:
 
     // Static Member Functions
 
-        //- Is character a regular expression meta-character?
-        //  any character: '.' \n
-        //  quantifiers: '*', '+', '?' \n
-        //  grouping: '(', '|', ')' \n
-        //  range: '[', ']' \n
+        //- 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
         //
-        //  Don't bother checking for '{digit}' bounds
+        // \note The presence of '{', '}' regex bounds is not considered
         inline static bool meta(const char c);
 
 
@@ -101,6 +90,12 @@ public:
         //- 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);
 
@@ -113,9 +108,6 @@ public:
         //- Construct from string, optionally ignore case
         inline regExp(const std::string& pattern, bool ignoreCase);
 
-        //- Move construct
-        inline regExp(regExp&& rgx);
-
 
     //- Destructor
     inline ~regExp();
@@ -123,27 +115,18 @@ public:
 
     // Member functions
 
-      // Access
+    // Access
 
         //- Return true if a precompiled expression does not exist
         inline bool empty() const;
 
-        //- Does a precompiled expression exist?
+        //- 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
-
-        //- 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);
+    // Editing
 
         //- Clear expression.
         //  \return True if expression had existed prior to the clear.
@@ -152,8 +135,15 @@ public:
         //- 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);
 
-      // Matching/Searching
+        //- 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
@@ -163,9 +153,10 @@ public:
         //  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 sub-groups matched.
+        //- 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, List<std::string>& groups) const;
+        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;
@@ -176,17 +167,20 @@ public:
         //- Perform match on text
         inline bool operator()(const std::string& text) const;
 
-        //- Assign and compile pattern from a character array
-        //  Always case sensitive
-        inline void operator=(const char* pattern);
-
-        //- Assign and compile pattern from string
-        //  Always case sensitive
-        inline void operator=(const std::string& pattern);
+        //- 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);
+
 };
 
 
diff --git a/src/OSspecific/POSIX/regExpI.H b/src/OSspecific/POSIX/regExpI.H
index 60c7da3053b2d30a4af82700ff277a8bc2b3a488..6586de160c408309ad0e9dcdbec02534f6cd88e1 100644
--- a/src/OSspecific/POSIX/regExpI.H
+++ b/src/OSspecific/POSIX/regExpI.H
@@ -136,22 +136,22 @@ inline bool Foam::regExp::operator()(const std::string& text) const
 }
 
 
-inline void Foam::regExp::operator=(const char* pattern)
+inline void Foam::regExp::operator=(regExp&& rgx)
 {
-    set(pattern);
+    clear();
+    swap(rgx);
 }
 
 
-inline void Foam::regExp::operator=(const std::string& pattern)
+inline void Foam::regExp::operator=(const char* pattern)
 {
     set(pattern);
 }
 
 
-inline void Foam::regExp::operator=(regExp&& rgx)
+inline void Foam::regExp::operator=(const std::string& pattern)
 {
-    clear();
-    swap(rgx);
+    set(pattern);
 }
 
 
diff --git a/src/OpenFOAM/primitives/strings/lists/SubStrings.H b/src/OpenFOAM/primitives/strings/lists/SubStrings.H
index 3e37fd7edd517ed6a5a743193fe559263be97ec1..0f2a690d6d1e154c4213af8f84af1cef00e5de6f 100644
--- a/src/OpenFOAM/primitives/strings/lists/SubStrings.H
+++ b/src/OpenFOAM/primitives/strings/lists/SubStrings.H
@@ -66,8 +66,7 @@ public:
     // Constructors
 
         //- Construct null
-        SubStrings()
-        {}
+        SubStrings() = default;
 
 
     // Member Functions
@@ -114,6 +113,13 @@ public:
             return this->back();
         }
 
+
+        //- Get element pos, converted to a string type.
+        String str(size_t pos) const
+        {
+            return (*this)[pos].str();
+        }
+
 };
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/surfMesh/surfaceFormats/starcd/STARCDsurfaceFormatCore.C b/src/surfMesh/surfaceFormats/starcd/STARCDsurfaceFormatCore.C
index b55e86ea1f4e65d42dab9da6fde1115f60ac124a..2462f7e569ab1eff9da0819de4624703ebe37f69 100644
--- a/src/surfMesh/surfaceFormats/starcd/STARCDsurfaceFormatCore.C
+++ b/src/surfMesh/surfaceFormats/starcd/STARCDsurfaceFormatCore.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -27,6 +27,7 @@ License
 #include "clock.H"
 #include "regExp.H"
 #include "IFstream.H"
+#include "SubStrings.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -35,10 +36,7 @@ License
 // don't bother with the older comma-delimited format
 
 Foam::Map<Foam::word>
-Foam::fileFormats::STARCDsurfaceFormatCore::readInpCellTable
-(
-    ISstream& is
-)
+Foam::fileFormats::STARCDsurfaceFormatCore::readInpCellTable(ISstream& is)
 {
     Map<word> lookup;
 
@@ -47,7 +45,7 @@ Foam::fileFormats::STARCDsurfaceFormatCore::readInpCellTable
         return lookup;
     }
 
-    const regExp ctnameRE
+    const regExp ctname
     (
         " *CTNA[^ ]*"        // keyword - min 4 chars
         "[[:space:]]+"       // space delimited
@@ -58,13 +56,14 @@ Foam::fileFormats::STARCDsurfaceFormatCore::readInpCellTable
     );
 
     string line;
-    List<std::string> groups;
+    regExp::results_type groups;
+
     while (is.good() && is.getLine(line).good())
     {
-        if (ctnameRE.match(line, groups))
+        if (ctname.match(line, groups))
         {
-            const label tableId = atoi(groups[0].c_str());
-            const word tableName = word::validate(groups[1], true);
+            const label tableId = readLabel(groups.str(1));
+            const word tableName = word::validate(groups.str(2), true);
 
             if (!tableName.empty())
             {