diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files
index a1650b7ee38443087671cf717dc2facb0d5b20c8..7b9f07486b3447b786999e68d3e1f9a80b8fe6b1 100644
--- a/src/OpenFOAM/Make/files
+++ b/src/OpenFOAM/Make/files
@@ -95,6 +95,7 @@ $(strings)/fileName/fileNameIO.C
 $(strings)/keyType/keyType.C
 $(strings)/wordRe/wordRe.C
 $(strings)/lists/hashedWordList.C
+$(strings)/lists/wordReListMatcher.C
 $(strings)/stringOps/stringOps.C
 
 ops = primitives/ops
diff --git a/src/OpenFOAM/primitives/strings/lists/wordReListMatcher.C b/src/OpenFOAM/primitives/strings/lists/wordReListMatcher.C
new file mode 100644
index 0000000000000000000000000000000000000000..1a24dcbbb1949e1f8902c97e90f0e6aa4d13b017
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/lists/wordReListMatcher.C
@@ -0,0 +1,56 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 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 "wordReListMatcher.H"
+#include "HashSet.H"
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+Foam::wordReList Foam::wordReListMatcher::uniq(const UList<wordRe>& input)
+{
+    wordReList retain(input.size());
+    wordHashSet uniqWord;
+
+    label nUniq = 0;
+    forAll(input, i)
+    {
+        const wordRe& select = input[i];
+
+        if
+        (
+            select.isPattern()
+         || uniqWord.insert(static_cast<const word&>(select))
+        )
+        {
+            retain[nUniq++] = select;
+        }
+    }
+
+    retain.setSize(nUniq);
+    return retain;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/lists/wordReListMatcher.H b/src/OpenFOAM/primitives/strings/lists/wordReListMatcher.H
index ebdd9481196a9433afa5737319880fb0addc0634..2bba686964cd2c74adbc30beb81a7ff8bf990445 100644
--- a/src/OpenFOAM/primitives/strings/lists/wordReListMatcher.H
+++ b/src/OpenFOAM/primitives/strings/lists/wordReListMatcher.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -77,13 +77,20 @@ public:
             inline const UList<wordRe>& operator()() const;
 
 
-    // Searching
+        // Searching
 
             //- Return true if string matches any of the regular expressions
             //  Smart match as regular expression or as a string.
             //  Optionally specify a literal match only.
             inline bool match(const string&, bool literalMatch=false) const;
 
+
+        // Helpers
+
+            //- Return a wordReList with duplicate words filtered out.
+            //  No filtering is done on regular expressions.
+            static wordReList uniq(const UList<wordRe>& input);
+
 };
 
 
diff --git a/src/functionObjects/field/ddt2/ddt2.C b/src/functionObjects/field/ddt2/ddt2.C
index 12d6d2b67ade02b633b23d9f22d4e75c509f4532..a3876716585aa57bcea8897ca5cf0e57e0ee2029 100644
--- a/src/functionObjects/field/ddt2/ddt2.C
+++ b/src/functionObjects/field/ddt2/ddt2.C
@@ -27,6 +27,7 @@ License
 
 #include "volFields.H"
 #include "dictionary.H"
+#include "wordReListMatcher.H"
 #include "steadyStateDdtScheme.H"
 #include "addToRunTimeSelectionTable.H"
 
@@ -77,25 +78,6 @@ bool Foam::functionObjects::ddt2::checkFormatName(const word& str)
 }
 
 
-void Foam::functionObjects::ddt2::uniqWords(wordReList& lst)
-{
-    boolList retain(lst.size());
-    wordHashSet uniq;
-    forAll(lst, i)
-    {
-        const wordRe& select = lst[i];
-
-        retain[i] =
-        (
-            select.isPattern()
-         || uniq.insert(static_cast<const word&>(select))
-        );
-    }
-
-    inplaceSubset(retain, lst);
-}
-
-
 bool Foam::functionObjects::ddt2::accept(const word& fieldName) const
 {
     // check input vs possible result names
@@ -160,10 +142,11 @@ bool Foam::functionObjects::ddt2::read(const dictionary& dict)
         return false;
     }
 
-    fvMeshFunctionObject::read(dict);
-
-    dict.lookup("fields") >> selectFields_;
-    uniqWords(selectFields_);
+    selectFields_ = wordReListMatcher::uniq
+    (
+        wordReList(dict.lookup("fields"))
+    );
+    Info<< type() << " fields: " << selectFields_ << nl;
 
     resultName_ = dict.lookupOrDefault<word>
     (
diff --git a/src/functionObjects/field/ddt2/ddt2.H b/src/functionObjects/field/ddt2/ddt2.H
index 4cf62c3addd367d3ddc7720724ddd474cc74db93..21607ce2a34c98f72c87742e8f94b84dd1340119 100644
--- a/src/functionObjects/field/ddt2/ddt2.H
+++ b/src/functionObjects/field/ddt2/ddt2.H
@@ -124,9 +124,6 @@ class ddt2
         //- Check that the word contains the appropriate substitution token(s).
         static bool checkFormatName(const word&);
 
-        //- Eliminate duplicate 'word' entries
-        static void uniqWords(wordReList&);
-
 
         //- Accept unless field name appears to have already been processed
         bool accept(const word& fieldName) const;
diff --git a/src/functionObjects/field/zeroGradient/zeroGradient.C b/src/functionObjects/field/zeroGradient/zeroGradient.C
index 9f7a2c257e7cedf3aafd93e7a1103e65fe426f8d..ff07607652bf19fa5f3dab52c6dc2d5841998d8b 100644
--- a/src/functionObjects/field/zeroGradient/zeroGradient.C
+++ b/src/functionObjects/field/zeroGradient/zeroGradient.C
@@ -27,6 +27,7 @@ License
 
 #include "volFields.H"
 #include "dictionary.H"
+#include "wordReListMatcher.H"
 #include "addToRunTimeSelectionTable.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -76,25 +77,6 @@ bool Foam::functionObjects::zeroGradient::checkFormatName(const word& str)
 }
 
 
-void Foam::functionObjects::zeroGradient::uniqWords(wordReList& lst)
-{
-    boolList retain(lst.size());
-    wordHashSet uniq;
-    forAll(lst, i)
-    {
-        const wordRe& select = lst[i];
-
-        retain[i] =
-        (
-            select.isPattern()
-         || uniq.insert(static_cast<const word&>(select))
-        );
-    }
-
-    inplaceSubset(retain, lst);
-}
-
-
 int Foam::functionObjects::zeroGradient::process(const word& fieldName)
 {
     int state = 0;
@@ -138,8 +120,11 @@ bool Foam::functionObjects::zeroGradient::read(const dictionary& dict)
 {
     fvMeshFunctionObject::read(dict);
 
-    dict.lookup("fields") >> selectFields_;
-    uniqWords(selectFields_);
+    selectFields_ = wordReListMatcher::uniq
+    (
+        wordReList(dict.lookup("fields"))
+    );
+    Info<< type() << " fields: " << selectFields_ << nl;
 
     resultName_ = dict.lookupOrDefault<word>("result", type() + "(@@)");
     return checkFormatName(resultName_);
diff --git a/src/functionObjects/field/zeroGradient/zeroGradient.H b/src/functionObjects/field/zeroGradient/zeroGradient.H
index 2651761a57e6b30c073a55ffed6afcfeada07a66..84243608243737ecb27b8735d2be2e19e84f1d43 100644
--- a/src/functionObjects/field/zeroGradient/zeroGradient.H
+++ b/src/functionObjects/field/zeroGradient/zeroGradient.H
@@ -110,9 +110,6 @@ class zeroGradient
         //- Check that the word contains the appropriate substitution token(s).
         static bool checkFormatName(const word&);
 
-        //- Eliminate duplicate 'word' entries
-        static void uniqWords(wordReList&);
-
 
         //- Accept unless field only has constraint patches
         //  (ie, empty/zero-gradient/processor).