diff --git a/applications/test/sort/Test-sortList.C b/applications/test/sort/Test-sortList.C
index 1fbfcfcf39cd6b14e0f3b8e805bc0ce734e002ce..8b208f4f50fce9f0dfd38470b89e4229e535974b 100644
--- a/applications/test/sort/Test-sortList.C
+++ b/applications/test/sort/Test-sortList.C
@@ -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) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -27,6 +27,8 @@ Description
 
 #include "SortableList.H"
 #include "ListOps.H"
+#include "HashSet.H"
+#include "stringOps.H"
 
 using namespace Foam;
 
@@ -175,6 +177,142 @@ int main(int argc, char *argv[])
         Info<< "flat = " << values << endl;
     }
 
+    // Sort strings
+    {
+        HashSet<string> hashed
+        {
+            "2.txt",
+            "05.txt",
+            "15.txt",
+            "other.bak04",
+            "other.bak1",
+            "file1.txt",
+            "file10.txt",
+            "file2.txt",
+            "file100.txt",
+            "file.txt",
+            "file011.txt",
+            "file15.txt",
+            "file0009.txt",
+            "abcd.txt",
+
+         // Some regular processor directories
+            "processor0",
+            "processor1",
+            "processor9",
+            "processor10",
+            "processor11",
+            "processor20",
+            "processor21",
+            "processor35",
+            "processors",
+
+         // Aggregate processor directories
+            "processor0-31",
+            "processor32-63",
+            "processor64-95",
+            "processor96-127",
+            "processor128-159",
+            "processor160-191",
+            "processor192-223",
+            "processor224-255",
+        };
+
+        Info<< nl << "Test string sorting" << nl << endl;
+
+        // Using hash toc
+        if (true)
+        {
+            Info<< "Unsorted" << hashed.toc() << endl;
+            Info<< "sortedToc" << hashed.sortedToc() << endl;
+            Info<< "natural"
+                << hashed.sortedToc(stringOps::natural_sort()) << endl;
+
+            Info<< "reverse natural"
+                << hashed.sortedToc(stringOps::natural_sort::reverse())
+                << endl;
+        }
+
+        // Normal list
+        if (true)
+        {
+            labelList order;
+
+            List<string> strings(hashed.toc());
+            Info<< nl << "stringList:" << strings << endl;
+
+            sort(strings);
+            Info<< "normal sort:" << strings << endl;
+
+            shuffle(strings);
+            sort(strings, stringOps::natural_sort());
+            Info<< "natural sort:" << strings << endl;
+
+            shuffle(strings);
+            sort(strings, stringOps::natural_sort::reverse());
+            Info<< "reverse natural:" << strings << endl;
+
+            strings = hashed.toc();
+
+            Info<< nl << "test sorted order" << endl;
+            Info<< nl << "list:" << strings << endl;
+
+            sortedOrder(strings, order);
+            Info<< "sortedOrder:" << flatOutput(order) << endl;
+
+            shuffle(strings);
+            sort(strings, stringOps::natural_sort());
+            Info<< "reverse natural:" << strings << endl;
+
+            shuffle(strings);
+            sort(strings, stringOps::natural_sort::reverse());
+            Info<< "reverse natural:" << strings << endl;
+
+            sortedOrder
+            (
+                strings,
+                order,
+                stringOps::natural_sort::less<string>(strings)
+            );
+            Info<< "natural sortedOrder: " << flatOutput(order) << endl;
+        }
+
+        // SortableList
+        if (false)
+        {
+            SortableList<string> sortable;
+            Info<< nl << "Testing sortable list";
+
+            // Assign to ensure list is initially unsorted
+            sortable = hashed.toc();
+            Info<< nl << "input:" << sortable << endl;
+
+            sortable.sort();
+            Info<< nl << "normal:" << sortable << endl;
+
+            // This is still a bother (looks fairly ugly)
+            // so not implemented for now
+
+            ///  // Assign to ensure list is initially unsorted
+            ///  sortable = hashed.toc();
+            ///  sortable.sort
+            ///  (
+            ///      stringOps::natural_sort::less<string>(sortable)
+            ///  );
+            ///  Info<< nl << "natural:" << sortable << endl;
+
+            ///  // Assign to ensure list is initially unsorted
+            ///  sortable = hashed.toc();
+            ///  sortable.sort
+            ///  (
+            ///      stringOps::natural_sort::greater<string>(sortable)
+            ///  );
+            ///  Info<< nl << "natural:" << sortable << endl;
+        }
+
+    }
+
+
     Info<< "\nEnd\n" << endl;
 
     return 0;
diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files
index acf60a63d05b16b7feb2f6c9bb93b92d988b53d4..4a6adb98a168b649b741bef57c8856c2fc0b3c4e 100644
--- a/src/OpenFOAM/Make/files
+++ b/src/OpenFOAM/Make/files
@@ -114,6 +114,7 @@ $(strings)/wordRe/wordRe.C
 $(strings)/wordRes/wordRes.C
 $(strings)/lists/hashedWordList.C
 $(strings)/stringOps/stringOps.C
+$(strings)/stringOps/stringOpsSort.C
 $(strings)/parsing/parsing.C
 
 ops = primitives/ops
diff --git a/src/OpenFOAM/containers/Dictionaries/DictionaryBase/DictionaryBase.C b/src/OpenFOAM/containers/Dictionaries/DictionaryBase/DictionaryBase.C
index 60b390223c2651a0d3e4d126582939ea16d382a5..2f95d40f713993a5b5ba4888845696ab0b68e738 100644
--- a/src/OpenFOAM/containers/Dictionaries/DictionaryBase/DictionaryBase.C
+++ b/src/OpenFOAM/containers/Dictionaries/DictionaryBase/DictionaryBase.C
@@ -189,6 +189,17 @@ Foam::wordList Foam::DictionaryBase<IDLListType, T>::sortedToc() const
 }
 
 
+template<class IDLListType, class T>
+template<class Compare>
+Foam::wordList Foam::DictionaryBase<IDLListType, T>::sortedToc
+(
+    const Compare& comp
+) const
+{
+    return hashedTs_.sortedToc(comp);
+}
+
+
 template<class IDLListType, class T>
 void Foam::DictionaryBase<IDLListType, T>::insert(const word& keyword, T* tPtr)
 {
diff --git a/src/OpenFOAM/containers/Dictionaries/DictionaryBase/DictionaryBase.H b/src/OpenFOAM/containers/Dictionaries/DictionaryBase/DictionaryBase.H
index f4d864d82c746d51807a8ed2f82e7027f8940890..8c48737427298aadfd2339622de74f2f1d790ef3 100644
--- a/src/OpenFOAM/containers/Dictionaries/DictionaryBase/DictionaryBase.H
+++ b/src/OpenFOAM/containers/Dictionaries/DictionaryBase/DictionaryBase.H
@@ -131,6 +131,10 @@ public:
             //- Return the table of contents as a sorted list
             wordList sortedToc() const;
 
+            //- Return table of contents sorted using the specified comparator
+            template<class Compare>
+            wordList sortedToc(const Compare& comp) const;
+
 
         // Editing
 
diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C
index 1f209ef350ec3c075ed0ed2ae7dc7a36dab472ab..1c1d7b43606376853bf77e96d9c5ec3da072e15d 100644
--- a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C
+++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C
@@ -268,13 +268,27 @@ Foam::List<Key> Foam::HashTable<T, Key, Hash>::toc() const
 template<class T, class Key, class Hash>
 Foam::List<Key> Foam::HashTable<T, Key, Hash>::sortedToc() const
 {
-    List<Key> keyLst = this->toc();
+    List<Key> keyLst(this->toc());
     Foam::sort(keyLst);
 
     return keyLst;
 }
 
 
+template<class T, class Key, class Hash>
+template<class Compare>
+Foam::List<Key> Foam::HashTable<T, Key, Hash>::sortedToc
+(
+    const Compare& comp
+) const
+{
+    List<Key> keyLst(this->toc());
+    Foam::sort(keyLst, comp);
+
+    return keyLst;
+}
+
+
 template<class T, class Key, class Hash>
 template<class UnaryPredicate>
 Foam::List<Key> Foam::HashTable<T, Key, Hash>::tocKeys
diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H
index aa848e475c4dc7d2dbc7fc942065bf066345edad..f9dda76f9c81515f10ae7727702fecfde9e2fef8 100644
--- a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H
+++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H
@@ -347,6 +347,10 @@ public:
         //- Return the table of contents as a sorted list
         List<Key> sortedToc() const;
 
+        //- Return table of contents sorted using the specified comparator
+        template<class Compare>
+        List<Key> sortedToc(const Compare& comp) const;
+
         //- Return the sorted table of contents with keys that satisfy
         //  the unary predicate, optionally with inverted logic.
         template<class UnaryPredicate>
diff --git a/src/OpenFOAM/containers/Lists/ListOps/ListOps.H b/src/OpenFOAM/containers/Lists/ListOps/ListOps.H
index d7c93bef0235e0cb1198e65bdb689f908617e015..c3a6406da9e6f17cd9f0fc7c2a33f301727177e8 100644
--- a/src/OpenFOAM/containers/Lists/ListOps/ListOps.H
+++ b/src/OpenFOAM/containers/Lists/ListOps/ListOps.H
@@ -110,24 +110,44 @@ void inplaceMapKey(const labelUList& oldToNew, Container& lst);
 template<class T>
 void sortedOrder(const UList<T>& lst, labelList& order);
 
-template<class T, class Cmp>
-void sortedOrder(const UList<T>& lst, labelList& order, const Cmp& cmp);
+//- Sort using specified list compare predicate
+template<class T, class ListComparePredicate>
+void sortedOrder
+(
+    const UList<T>& lst,
+    labelList& order,
+    const ListComparePredicate& comp
+);
 
 
 //- Generate (sorted) indices corresponding to duplicate list values
 template<class T>
 void duplicateOrder(const UList<T>& lst, labelList& order);
 
-template<class T, class Cmp>
-void duplicateOrder(const UList<T>& lst, labelList& order, const Cmp& cmp);
+//- Generate (sorted) indices corresponding to duplicate list values
+//  sort using specified list compare predicate
+template<class T, class ListComparePredicate>
+void duplicateOrder
+(
+    const UList<T>& lst,
+    labelList& order,
+    const ListComparePredicate& comp
+);
 
 
 //- Generate (sorted) indices corresponding to unique list values
 template<class T>
 void uniqueOrder(const UList<T>& lst, labelList& order);
 
-template<class T, class Cmp>
-void uniqueOrder(const UList<T>& lst, labelList& order, const Cmp& cmp);
+//- Generate (sorted) indices corresponding to unique list values
+//  sort using specified list compare predicate
+template<class T, class ListComparePredicate>
+void uniqueOrder
+(
+    const UList<T>& lst,
+    labelList& order,
+    const ListComparePredicate& comp
+);
 
 
 //- Inplace sorting and removal of duplicates.
@@ -137,8 +157,12 @@ void inplaceUniqueSort(ListType& lst);
 
 //- Inplace sorting and removal of duplicates.
 //  Do not use FixedList for the input list, since it doesn't resize.
-template<class ListType, class Cmp>
-void inplaceUniqueSort(ListType& lst, const Cmp& cmp);
+template<class ListType, class ListComparePredicate>
+void inplaceUniqueSort
+(
+    ListType& lst,
+    const ListComparePredicate& comp
+);
 
 
 //- Extract elements of List when select is a certain value.
diff --git a/src/OpenFOAM/containers/Lists/ListOps/ListOpsTemplates.C b/src/OpenFOAM/containers/Lists/ListOps/ListOpsTemplates.C
index 641aa4ade0eeb4d8e811bfcaeb5b0d604452ce10..a55b8c714cdd46d1c944cba14f20c6e08054ce29 100644
--- a/src/OpenFOAM/containers/Lists/ListOps/ListOpsTemplates.C
+++ b/src/OpenFOAM/containers/Lists/ListOps/ListOpsTemplates.C
@@ -211,27 +211,30 @@ void Foam::sortedOrder
 }
 
 
-template<class T, class Cmp>
+template<class T, class ListComparePredicate>
 void Foam::sortedOrder
 (
     const UList<T>& lst,
     labelList& order,
-    const Cmp& cmp
+    const ListComparePredicate& comp
 )
 {
+    const label len = lst.size();
+
     // list lengths must be identical
-    if (order.size() != lst.size())
+    if (order.size() != len)
     {
-        // avoid copying any elements, they are overwritten anyhow
+        // Avoid copying any elements, they are overwritten anyhow
         order.clear();
-        order.setSize(lst.size());
+        order.setSize(len);
     }
 
-    forAll(order, elemI)
+    for (label i=0; i<len; ++i)
     {
-        order[elemI] = elemI;
+        order[i] = i; // identity
     }
-    Foam::stableSort(order, cmp);
+
+    Foam::stableSort(order, comp);
 }
 
 
@@ -246,12 +249,12 @@ void Foam::duplicateOrder
 }
 
 
-template<class T, class Cmp>
+template<class T, class ListComparePredicate>
 void Foam::duplicateOrder
 (
     const UList<T>& lst,
     labelList& order,
-    const Cmp& cmp
+    const ListComparePredicate& comp
 )
 {
     if (lst.size() < 2)
@@ -260,7 +263,7 @@ void Foam::duplicateOrder
         return;
     }
 
-    sortedOrder(lst, order, cmp);
+    sortedOrder(lst, order, comp);
 
     const label last = (order.size()-1);
     label n = 0;
@@ -286,15 +289,15 @@ void Foam::uniqueOrder
 }
 
 
-template<class T, class Cmp>
+template<class T, class ListComparePredicate>
 void Foam::uniqueOrder
 (
     const UList<T>& lst,
     labelList& order,
-    const Cmp& cmp
+    const ListComparePredicate& comp
 )
 {
-    sortedOrder(lst, order, cmp);
+    sortedOrder(lst, order, comp);
 
     if (order.size() > 1)
     {
@@ -324,18 +327,24 @@ void Foam::inplaceUniqueSort(ListType& lst)
 }
 
 
-template<class ListType, class Cmp>
-void Foam::inplaceUniqueSort(ListType& lst, const Cmp& cmp)
+template<class ListType, class ListComparePredicate>
+void Foam::inplaceUniqueSort
+(
+    ListType& lst,
+    const ListComparePredicate& comp
+)
 {
     labelList order;
-    uniqueOrder(lst, order, cmp);
+    uniqueOrder(lst, order, comp);
+
+    const label len = order.size();
 
-    ListType newLst(order.size());
-    newLst.setSize(order.size()); // Consistent sizing (eg, DynamicList)
+    ListType newLst(len);
+    newLst.setSize(len);  // Consistent sizing (eg, DynamicList)
 
-    forAll(order, elemI)
+    for (label i=0; i<len; ++i)
     {
-        newLst[elemI] = lst[order[elemI]];
+        newLst[i] = lst[order[i]];
     }
 
     lst.transfer(newLst);
diff --git a/src/OpenFOAM/containers/Lists/SortableList/SortableList.C b/src/OpenFOAM/containers/Lists/SortableList/SortableList.C
index fac433d7d75795cf82415fabfd5d43a780b8b017..6d2d2698dca17ff64e380e4915f472deec870808 100644
--- a/src/OpenFOAM/containers/Lists/SortableList/SortableList.C
+++ b/src/OpenFOAM/containers/Lists/SortableList/SortableList.C
@@ -133,7 +133,7 @@ Foam::List<T>& Foam::SortableList<T>::shrink()
 template<class T>
 void Foam::SortableList<T>::sort()
 {
-    sortedOrder(*this, indices_);
+    Foam::sortedOrder(*this, indices_);
 
     List<T> lst(*this, indices_); // Copy with indices for mapping
     List<T>::transfer(lst);
@@ -143,7 +143,7 @@ void Foam::SortableList<T>::sort()
 template<class T>
 void Foam::SortableList<T>::reverseSort()
 {
-    sortedOrder(*this, indices_, typename UList<T>::greater(*this));
+    Foam::sortedOrder(*this, indices_, typename UList<T>::greater(*this));
 
     List<T> lst(*this, indices_); // Copy with indices for mapping
     List<T>::transfer(lst);
@@ -157,6 +157,7 @@ void Foam::SortableList<T>::swap(SortableList<T>& lst)
     indices_.swap(lst.indices_);
 }
 
+
 template<class T>
 Foam::Xfer<Foam::List<T>> Foam::SortableList<T>::xfer()
 {
diff --git a/src/OpenFOAM/containers/Lists/SortableList/SortableList.H b/src/OpenFOAM/containers/Lists/SortableList/SortableList.H
index 8ef6aefa19796ec98a2eb0c1da0ba3eefa565345..083e69386f01603229095378eaf777f65426d589 100644
--- a/src/OpenFOAM/containers/Lists/SortableList/SortableList.H
+++ b/src/OpenFOAM/containers/Lists/SortableList/SortableList.H
@@ -119,8 +119,8 @@ public:
         //- Clear the indices and return a reference to the underlying List
         List<T>& shrink();
 
-        //- (stable) sort the list (if changed after construction time)
-        //  also resizes the indices as required
+        //- (stable) sort the list (if changed after construction time).
+        //  Resizes the indices as required
         void sort();
 
         //- Reverse (stable) sort the list
diff --git a/src/OpenFOAM/containers/Lists/UList/UList.C b/src/OpenFOAM/containers/Lists/UList/UList.C
index b87e524b5938e22181bf980178b744f9b13a17fe..9258fbf637a8d60ecb25a22757b41640bf79208c 100644
--- a/src/OpenFOAM/containers/Lists/UList/UList.C
+++ b/src/OpenFOAM/containers/Lists/UList/UList.C
@@ -293,10 +293,10 @@ void Foam::sort(UList<T>& a)
 }
 
 
-template<class T, class Cmp>
-void Foam::sort(UList<T>& a, const Cmp& cmp)
+template<class T, class Compare>
+void Foam::sort(UList<T>& a, const Compare& comp)
 {
-    std::sort(a.begin(), a.end(), cmp);
+    std::sort(a.begin(), a.end(), comp);
 }
 
 
@@ -307,10 +307,10 @@ void Foam::stableSort(UList<T>& a)
 }
 
 
-template<class T, class Cmp>
-void Foam::stableSort(UList<T>& a, const Cmp& cmp)
+template<class T, class Compare>
+void Foam::stableSort(UList<T>& a, const Compare& comp)
 {
-    std::stable_sort(a.begin(), a.end(), cmp);
+    std::stable_sort(a.begin(), a.end(), comp);
 }
 
 
diff --git a/src/OpenFOAM/containers/Lists/UList/UList.H b/src/OpenFOAM/containers/Lists/UList/UList.H
index 5c7999e2294ab6131eb8f6af73bbe47c81cdec35..fcdbd7c0da0c9a15b3896a481db3b99dbe2e8d75 100644
--- a/src/OpenFOAM/containers/Lists/UList/UList.H
+++ b/src/OpenFOAM/containers/Lists/UList/UList.H
@@ -139,39 +139,35 @@ public:
 
     // Public classes
 
-        //- Less function class that can be used for sorting
-        class less
+        //- A list compare binary predicate for normal sort
+        struct less
         {
-            const UList<T>& values_;
+            const UList<T>& values;
 
-        public:
-
-            less(const UList<T>& values)
+            less(const UList<T>& list)
             :
-                values_(values)
+                values(list)
             {}
 
-            bool operator()(const label a, const label b)
+            bool operator()(const label a, const label b) const
             {
-                return values_[a] < values_[b];
+                return values[a] < values[b];
             }
         };
 
-        //- Greater function class that can be used for sorting
-        class greater
+        //- A list compare binary predicate for reverse sort
+        struct greater
         {
-            const UList<T>& values_;
-
-        public:
+            const UList<T>& values;
 
-            greater(const UList<T>& values)
+            greater(const UList<T>& list)
             :
-                values_(values)
+                values(list)
             {}
 
-            bool operator()(const label a, const label b)
+            bool operator()(const label a, const label b) const
             {
-                return values_[a] > values_[b];
+                return values[a] > values[b];
             }
         };
 
@@ -487,14 +483,14 @@ public:
 template<class T>
 void sort(UList<T>& a);
 
-template<class T, class Cmp>
-void sort(UList<T>& a, const Cmp& cmp);
+template<class T, class Compare>
+void sort(UList<T>& a, const Compare& comp);
 
 template<class T>
 void stableSort(UList<T>& a);
 
-template<class T, class Cmp>
-void stableSort(UList<T>& a, const Cmp& cmp);
+template<class T, class Compare>
+void stableSort(UList<T>& a, const Compare& comp);
 
 template<class T>
 void shuffle(UList<T>& a);
diff --git a/src/OpenFOAM/db/dictionary/dictionary.H b/src/OpenFOAM/db/dictionary/dictionary.H
index fc34a32d991c09df2f8dfa6696761b61c9676172..f0c66b97a856272fdf046408ba576cc83b87f2fb 100644
--- a/src/OpenFOAM/db/dictionary/dictionary.H
+++ b/src/OpenFOAM/db/dictionary/dictionary.H
@@ -452,6 +452,10 @@ public:
             //- Return the sorted table of contents
             wordList sortedToc() const;
 
+            //- Return table of contents sorted using the specified comparator
+            template<class Compare>
+            wordList sortedToc(const Compare& comp) const;
+
             //- Return the list of available keys or patterns
             List<keyType> keys(bool patterns = false) const;
 
diff --git a/src/OpenFOAM/db/dictionary/dictionaryTemplates.C b/src/OpenFOAM/db/dictionary/dictionaryTemplates.C
index b247dfe8122647d5ea367c06b24a51d99628705e..1e46e5da33bbcd9f195951425ddb5eede5f54e6a 100644
--- a/src/OpenFOAM/db/dictionary/dictionaryTemplates.C
+++ b/src/OpenFOAM/db/dictionary/dictionaryTemplates.C
@@ -28,6 +28,13 @@ License
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
+template<class Compare>
+Foam::wordList Foam::dictionary::sortedToc(const Compare& comp) const
+{
+    return hashedEntries_.sortedToc(comp);
+}
+
+
 template<class T>
 T Foam::dictionary::lookupType
 (
diff --git a/src/OpenFOAM/primitives/predicates/predicates.H b/src/OpenFOAM/primitives/predicates/predicates.H
index 0d7d8539fa24394ddb2e743888df4ace222ad59c..a44b4eec7e2749ab83e1b396e0489aa967977b5c 100644
--- a/src/OpenFOAM/primitives/predicates/predicates.H
+++ b/src/OpenFOAM/primitives/predicates/predicates.H
@@ -49,37 +49,40 @@ namespace predicates
                            Class always Declaration
 \*---------------------------------------------------------------------------*/
 
-//- Unary and binary predicates returning true, useful for templating.
-class always
+//- Unary and binary predicates that always return true, useful for templating.
+struct always
 {
-public:
     typedef always value_type;
 
-    //- Construct null
+    //- Null constructible
     inline always()
     {}
 
-    //- Evaluated as a bool - return true
+    //- Evaluated as a bool
+    //  \return true
     inline operator bool() const
     {
         return true;
     }
 
-    //- Unary predicate returning true
+    //- Unary predicate
+    //  \return true
     template<class T>
     inline bool operator()(const T&) const
     {
         return true;
     }
 
-    //- Binary predicate returning true
+    //- Binary predicate
+    //  \return true
     template<class T1, class T2>
     inline bool operator()(const T1&, const T2&) const
     {
         return true;
     }
 
-    //- String match returning true
+    //- String match
+    //  \return true
     inline bool match(const std::string&, bool literal=false) const
     {
         return true;
@@ -91,37 +94,40 @@ public:
                             Class never Declaration
 \*---------------------------------------------------------------------------*/
 
-//- Unary and binary predicates returning false, useful for templating.
-class never
+//- Unary and binary predicates that never return true, useful for templating.
+struct never
 {
-public:
     typedef never value_type;
 
-    //- Construct null
+    //- Null constructible
     inline never()
     {}
 
-    //- Evaluated as a bool - return false
+    //- Evaluated as a bool
+    //  \return false
     inline operator bool() const
     {
         return false;
     }
 
-    //- Unary predicate returning false
+    //- Unary predicate
+    //  \return false
     template<class T>
     inline bool operator()(const T&) const
     {
         return false;
     }
 
-    //- Binary predicate returning false
+    //- Binary predicate
+    //  \return false
     template<class T1, class T2>
     inline bool operator()(const T1&, const T2&) const
     {
         return false;
     }
 
-    //- String match returning false
+    //- String match
+    //  \return false
     inline bool match(const std::string&, bool literal=false) const
     {
         return false;
diff --git a/src/OpenFOAM/primitives/strings/stringOps/stringOps.H b/src/OpenFOAM/primitives/strings/stringOps/stringOps.H
index 92092f9d5207ddf0370d1b499bb1600892248b6c..0d84856f52db85ee9df5e972ee6b0e760a763c58 100644
--- a/src/OpenFOAM/primitives/strings/stringOps/stringOps.H
+++ b/src/OpenFOAM/primitives/strings/stringOps/stringOps.H
@@ -41,6 +41,7 @@ SourceFiles
 #include "word.H"
 #include "dictionary.H"
 #include "HashTable.H"
+#include "stringOpsSort.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
diff --git a/src/OpenFOAM/primitives/strings/stringOps/stringOpsSort.C b/src/OpenFOAM/primitives/strings/stringOps/stringOpsSort.C
new file mode 100644
index 0000000000000000000000000000000000000000..aeeb29fa14b247400a24a8b566d5f01adae3746d
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/stringOps/stringOpsSort.C
@@ -0,0 +1,325 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+Changes for OpenFOAM
+
+   Code cleanup, reduction, elimination of redundant code.
+\*---------------------------------------------------------------------------*/
+
+//========================================================================
+// Copyright (c) 1998-2010,2011 Free Software Foundation, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, distribute with modifications, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+// THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the above copyright
+// holders shall not be used in advertising or otherwise to promote the
+// sale, use or other dealings in this Software without prior written
+// authorization.
+//========================================================================
+
+//========================================================================
+//  Original Author: Jan-Marten Spit <jmspit@euronet.nl>
+//========================================================================
+
+#include "stringOpsSort.H"
+#include <cctype>
+#include <cstring>
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Local tweaks/preferences:
+//
+// [DIGITS_ALWAYS_FIRST] : as per original code
+// This results in "file123.txt" sorting before "file.txt", which is
+// inconsistent with what 'ls -v' produces
+// - normally do not want this (Mark Olesen: Oct-2017)
+#undef DIGITS_ALWAYS_FIRST
+
+// [IGNORE_LEADING_ZEROS] : as per original code
+// This results in "file0005.txt" sorting before "file06.txt"
+// -> normally want this (Mark Olesen: Oct-2017)
+#define IGNORE_LEADING_ZEROS
+
+// [MANUAL_NUMCOMPARE] : handwritten code instead of strncmp
+// The orignal code has a mix of strncmp for equality but handwritten code
+// for greater-than/less-than.
+//
+// -> this does to be unneeded, rely on strncmp() return values
+//    (Mark Olesen: Oct-2017)
+#undef MANUAL_NUMCOMPARE
+
+// [DEBUG_NATSTRCMP] : debug info to std::cerr (for development purposes only)
+#undef DEBUG_NATSTRCMP
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef DEBUG_NATSTRCMP
+#include <iostream>
+
+template<class T>
+static inline void debugPrint(const char* text, T item1, T item2)
+{
+    std::cerr << text << ": <" << item1 << "> <" << item2 << ">\n";
+}
+
+// Character sequences, end pointer is _inclusive_.
+static inline void debugPrint
+(
+    const char* b1, const char* e1,
+    const char* b2, const char* e2
+)
+{
+    std::cerr << "<";
+    while (b1 < e1) { std::cerr << *b1++; }
+    std::cerr << *e1 << "> ";
+
+    std::cerr << "<";
+    while (b2 < e2) { std::cerr << *b2++; }
+    std::cerr << *e2 << ">\n";
+}
+#endif
+
+#ifdef MANUAL_NUMCOMPARE
+// Manual comparison of identical length (digit) sequences
+static inline int manual_numcompare(const char* s1, const char* s2)
+{
+    while (*s1 && *s2)
+    {
+        const int cmp = (*s1 - *s2);
+        if (!cmp) return cmp;
+
+        ++s1; ++s2;
+    }
+    return 0;  // Length check done before in caller.
+}
+#endif
+
+
+// ------------------------------------------------------------------------- //
+
+int Foam::stringOps::natstrcmp(const char* s1, const char* s2)
+{
+    #ifdef DEBUG_NATSTRCMP
+    debugPrint("natstrcmp", s1, s2);
+    #endif
+
+    // States for state engine
+    enum stateType { SCAN, ALPHA, NUMERIC };
+
+    // Number of leading zeroes
+    unsigned zeros1 = 0;
+    unsigned zeros2 = 0;
+
+    // Pointers to begin/end of integer sequences (without leading zeros)
+    const char* numbeg1 = nullptr;
+    const char* numbeg2 = nullptr;
+    const char* numend1 = nullptr;
+    const char* numend2 = nullptr;
+
+    stateType state = SCAN;
+
+    const char* p1 = s1;
+    const char* p2 = s2;
+
+    while (*p1 && *p2)
+    {
+        // Bitmask for digits vs alpha
+        // - 0: neither are digits
+        // - 1: p1 is the only digit
+        // - 2: p2 is the only digit
+        // - 3: both p1 and p2 are digits
+
+        const unsigned digitMask =
+            ((isdigit(*p2) ? 2:0) | (isdigit(*p1) ? 1:0));
+
+        switch (state)
+        {
+            case SCAN:
+            {
+                #ifdef DEBUG_NATSTRCMP
+                debugPrint("SCAN", *p1, *p2);
+                #endif
+
+                switch (digitMask)
+                {
+                    case 0:         // (alpha,alpha)
+                    {
+                        state = ALPHA;
+
+                        if (*p1 == *p2)
+                        {
+                            ++p1; ++p2;
+                        }
+                        else
+                        {
+                            // Lexical compare
+                            return (*p1 - *p2);
+                        }
+                        break;
+                    }
+
+                    #ifdef DIGITS_ALWAYS_FIRST
+                    case 0x1:        // (digit,alpha) : digit < alpha
+                    {
+                        return -1;
+                        break;
+                    }
+                    case 0x2:        // (alpha,digit) : alpha > digit
+                    {
+                        return 1;
+                        break;
+                    }
+                    #else /* DIGITS_ALWAYS_FIRST */
+                    case 0x1:        // (digit,alpha)
+                    case 0x2:        // (alpha,digit)
+                    {
+                        // Lexical compare for digits/alpha
+                        return (*p1 - *p2);
+                        break;
+                    }
+                    #endif /* DIGITS_ALWAYS_FIRST */
+
+                    default:        // (digit,digit)
+                    {
+                        state = NUMERIC;
+
+                        #ifdef IGNORE_LEADING_ZEROS
+                        if (!zeros1)    // Start skip of leading zeros
+                        {
+                            while (*p1 == '0') { ++p1; ++zeros1; }
+                        }
+                        else
+                        #endif
+                        {
+                            while (*p1 == '0') { ++p1; }
+                        }
+                        #ifdef IGNORE_LEADING_ZEROS
+                        if (!zeros2)     // Start skip of leading zeros
+                        {
+                            while (*p2 == '0') { ++p2; ++zeros2; }
+                        }
+                        else
+                        #endif
+                        {
+                            while (*p2 == '0') { ++p2; }
+                        }
+
+                        if (zeros1 == zeros2)
+                        {
+                            // Same number of zeros - so irrelevant
+                            zeros1 = zeros2 = 0;
+                        }
+
+                        if (!isdigit(*p1)) --p1;
+                        if (!isdigit(*p2)) --p2;
+
+                        numbeg1 = numend1 = p1;
+                        numbeg2 = numend2 = p2;
+
+                        break;
+                    }
+                }
+                break;
+            }
+
+            case ALPHA:
+            {
+                #ifdef DEBUG_NATSTRCMP
+                debugPrint("ALPHA", *p1, *p2);
+                #endif
+
+                if (digitMask)
+                {
+                    state = SCAN;
+                }
+                else                // (alpha,alpha)
+                {
+                    if (*p1 == *p2)
+                    {
+                        ++p1; ++p2;
+                    }
+                    else
+                    {
+                        // Lexical compare
+                        return (*p1 - *p2);
+                    }
+                }
+                break;
+            }
+
+            case NUMERIC:
+            {
+                while (isdigit(*p1)) numend1 = p1++;
+                while (isdigit(*p2)) numend2 = p2++;
+
+                #ifdef DEBUG_NATSTRCMP
+                debugPrint("NUMERIC", *p1, *p2);
+                debugPrint(numbeg1,numend1, numbeg2,numend2);
+                #endif
+
+                // Length (minus 1) of each sequence
+                const size_t len1 = (numend1 - numbeg1);
+                const size_t len2 = (numend2 - numbeg2);
+
+                if (len1 < len2)
+                {
+                    return -1;
+                }
+                else if (len1 > len2)
+                {
+                    return 1;
+                }
+
+                // Same number of digits, leading zeros have been skipped.
+                // - so lexical and numerical compares are equivalent.
+
+                const int cmp = strncmp(numbeg1, numbeg2, len1+1);
+                if (!cmp)
+                {
+                    // Identical (digit) sequence - continue
+                    state = SCAN;
+                }
+                else
+                {
+                    #ifdef MANUAL_STRNCMP
+                    return manual_numcompare(numbeg1, numbeg2);
+                    #else
+                    return cmp;
+                    #endif
+                }
+                break;
+            }
+        }
+    }
+
+    if (zeros1 < zeros2) return -1;
+    if (zeros1 > zeros2) return 1;
+    if (!*p1 && *p2) return -1;  // s1 shorter than s2
+    if (*p1 && !*p2) return 1;   // s1 longer  than s2
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/stringOps/stringOpsSort.H b/src/OpenFOAM/primitives/strings/stringOps/stringOpsSort.H
new file mode 100644
index 0000000000000000000000000000000000000000..8e6344f27a81bfeb6f9662953204d677af75b384
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/stringOps/stringOpsSort.H
@@ -0,0 +1,133 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 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/>.
+
+InNamespace
+    Foam::stringOps
+
+Description
+    Specialized string sorting.
+
+SourceFiles
+    stringOpsSort.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef stringOpsSort_H
+#define stringOpsSort_H
+
+#include "stringOps.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace stringOps
+{
+
+    //- 'Natural' compare for C-strings
+    //  Uses algorithm and code from Jan-Marten Spit <jmspit@euronet.nl>
+    //
+    //  In the 'natural' comparison, strings are compared alphabetically
+    //  and numerically. Thus 'file010.txt' sorts after 'file2.txt'
+    //
+    //  \param s1 left string
+    //  \param s2 right string
+    //  \return -1 when s1 < s2, 0 when s1 == s2, 1 when s1 > s2
+    int natstrcmp(const char* s1, const char* s2);
+
+
+    //- Encapsulation of natural order sorting for algorithms
+    struct natural_sort
+    {
+        //- Natural compare for std::string
+        //  \return -1 when s1 < s2, 0 when s1 == s2, 1 when s1 > s2
+        static inline int compare
+        (
+            const std::string& s1,
+            const std::string& s2
+        )
+        {
+            return natstrcmp(s1.data(), s2.data());
+        }
+
+        //- Default (forward) natural sorting
+        bool operator()(const std::string& s1, const std::string& s2) const
+        {
+            return natural_sort::compare(s1, s2) < 0;
+        }
+
+        //- Reverse natural sorting
+        struct reverse
+        {
+            //- Reverse natural sorting
+            bool operator()(const std::string& s1, const std::string& s2) const
+            {
+                return natural_sort::compare(s1, s2) > 0;
+            }
+        };
+
+
+        //- A list compare binary predicate for natural sort
+        template<class T>
+        struct less
+        {
+            const UList<T>& values;
+
+            less(const UList<T>& list)
+            :
+                values(list)
+            {}
+
+            bool operator()(const label a, const label b) const
+            {
+                return natural_sort::compare(values[a], values[b]) < 0;
+            }
+        };
+
+
+        //- A list compare binary predicate for reverse natural sort
+        template<class T>
+        struct greater
+        {
+            const UList<T>& values;
+
+            greater(const UList<T>& list)
+            :
+                values(list)
+            {}
+
+            bool operator()(const label a, const label b) const
+            {
+                return natural_sort::compare(values[a], values[b]) > 0;
+            }
+        };
+    };
+
+} // End namespace stringOps
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //