diff --git a/applications/test/DirLister/Test-DirLister.C b/applications/test/DirLister/Test-DirLister.C
index c2e07b6c2e07e65044c3c6b28efcc6dd3b0de8b5..af0e76bc9da0a3a5b60322b4ce9c091c61995411 100644
--- a/applications/test/DirLister/Test-DirLister.C
+++ b/applications/test/DirLister/Test-DirLister.C
@@ -83,7 +83,7 @@ int main(int argc, char *argv[])
             const word& item
           : DirLister::files(".").where
             (
-                [](const word& val){ return val.startsWith("T"); }
+                [](const word& val){ return val.starts_with('T'); }
             )
         )
         {
@@ -135,7 +135,7 @@ int main(int argc, char *argv[])
             << "~~~~~~~~~~" << nl
             <<  DirLister(".").list<fileName>
                 (
-                    [](const word& val){ return val.startsWith("D"); },
+                    [](const word& val){ return val.starts_with('D'); },
                     false
                 )
             << nl;
diff --git a/applications/test/string/Test-string.C b/applications/test/string/Test-string.C
index 9b8e1688eb036a99ef8450917c65f1406059d934..8982cda8933b435b9756fe58d479bce6749a1d98 100644
--- a/applications/test/string/Test-string.C
+++ b/applications/test/string/Test-string.C
@@ -353,7 +353,7 @@ int main(int argc, char *argv[])
             << word::printf("formatted '%08d'", val) << "\n";
     }
 
-    // test startsWith, endsWith methods
+    // test starts_with, ends_with methods
     {
         string empty; //;
         string input1 = "shorter input";
@@ -362,64 +362,64 @@ int main(int argc, char *argv[])
         stringList checks{"match", "long", "", "short", "text", "s", "l", "t"};
 
         Info<< nl;
-        Info<< "check startsWith:" << nl
+        Info<< "check starts_with:" << nl
             << "~~~~~~~~~~~~~~~~~" << nl;
 
         Info<<"input: " << empty << nl;
         for (const string& test : checks)
         {
-            Info<< "    startsWith(" << test << ") = "
-                << Switch(empty.startsWith(test)) << nl;
+            Info<< "    starts_with(" << test << ") = "
+                << Switch(empty.starts_with(test)) << nl;
         }
         Info<<"input: " << input1 << nl;
         for (const string& test : checks)
         {
-            Info<< "    startsWith(" << test << ") = "
-                << Switch(input1.startsWith(test)) << nl;
+            Info<< "    starts_with(" << test << ") = "
+                << Switch(input1.starts_with(test)) << nl;
         }
         Info<<"input: " << input2 << nl;
         for (const string& test : checks)
         {
-            Info<< "    startsWith(" << test << ") = "
-                << Switch(input2.startsWith(test)) << nl;
+            Info<< "    starts_with(" << test << ") = "
+                << Switch(input2.starts_with(test)) << nl;
         }
 
 
         Info<< nl;
-        Info<< "check endsWith:" << nl
+        Info<< "check ends_with:" << nl
             << "~~~~~~~~~~~~~~~~~" << nl;
 
         Info<<"input: " << empty << nl;
         for (const string& test : checks)
         {
-            Info<< "    endsWith(" << test << ") = "
-                << Switch(empty.endsWith(test)) << nl;
+            Info<< "    ends_with(" << test << ") = "
+                << Switch(empty.ends_with(test)) << nl;
         }
         Info<<"input: " << input1 << nl;
         for (const string& test : checks)
         {
-            Info<< "    endsWith(" << test << ") = "
-                << Switch(input1.endsWith(test)) << nl;
+            Info<< "    ends_with(" << test << ") = "
+                << Switch(input1.ends_with(test)) << nl;
         }
         Info<<"input: " << input2 << nl;
         for (const string& test : checks)
         {
-            Info<< "    endsWith(" << test << ") = "
-                << Switch(input2.endsWith(test)) << nl;
+            Info<< "    ends_with(" << test << ") = "
+                << Switch(input2.ends_with(test)) << nl;
         }
 
         Info<< nl;
-        Info<< "check endsWith as applied to field names:" << nl
+        Info<< "check ends_with as applied to field names:" << nl
             << "~~~~~~~~~~~~~~~~~" << nl;
 
         string input3 = "field_0";
         string input4 = "_0";
 
-        Info<<input3 << " endsWith(\"_0\") = "
-            << Switch(input3.endsWith("_0")) << nl;
+        Info<<input3 << " ends_with(\"_0\") = "
+            << Switch(input3.ends_with("_0")) << nl;
 
-        Info<<input4 << " endsWith(\"_0\") = "
-            << Switch(input4.endsWith("_0")) << nl;
+        Info<<input4 << " ends_with(\"_0\") = "
+            << Switch(input4.ends_with("_0")) << nl;
     }
 
 
diff --git a/applications/utilities/mesh/conversion/tetgenToFoam/tetgenToFoam.C b/applications/utilities/mesh/conversion/tetgenToFoam/tetgenToFoam.C
index 167efd5e8062f89f47259b2856ecd57c897fa08c..d70a2d4a7412d23b977cb44203c475983bfd7cf2 100644
--- a/applications/utilities/mesh/conversion/tetgenToFoam/tetgenToFoam.C
+++ b/applications/utilities/mesh/conversion/tetgenToFoam/tetgenToFoam.C
@@ -175,7 +175,7 @@ int main(int argc, char *argv[])
     {
         nodeStream.getLine(line);
     }
-    while (line.size() && line[0] == '#');
+    while (line.starts_with('#'));
 
     IStringStream nodeLine(line);
 
@@ -252,7 +252,7 @@ int main(int argc, char *argv[])
     {
         eleStream.getLine(line);
     }
-    while (line.size() && line[0] == '#');
+    while (line.starts_with('#'));
 
     IStringStream eleLine(line);
 
@@ -368,7 +368,7 @@ int main(int argc, char *argv[])
         {
             faceStream.getLine(line);
         }
-        while (line.size() && line[0] == '#');
+        while (line.starts_with('#'));
 
         IStringStream faceLine(line);
 
diff --git a/applications/utilities/mesh/manipulation/objToVTK/objToVTK.C b/applications/utilities/mesh/manipulation/objToVTK/objToVTK.C
index a20da340755c624f8d822fdc22b7f390030a5180..ccc9da33dc169c64951510fb6371818dbc9216de 100644
--- a/applications/utilities/mesh/manipulation/objToVTK/objToVTK.C
+++ b/applications/utilities/mesh/manipulation/objToVTK/objToVTK.C
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2015 OpenFOAM Foundation
+    Copyright (C) 2019 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -51,7 +52,7 @@ string getLine(std::ifstream& is)
     {
         std::getline(is, line);
     }
-    while (line.size() && line[0] == '#');
+    while (line.starts_with('#'));
 
     return line;
 }
diff --git a/applications/utilities/miscellaneous/foamHelp/helpTypes/helpType/helpTypeNew.C b/applications/utilities/miscellaneous/foamHelp/helpTypes/helpType/helpTypeNew.C
index 851a43fe197a4af966956df4c9eb2f7db99154fd..c6c65b47b41d6b8b64c6dd010d9075698d2cc45f 100644
--- a/applications/utilities/miscellaneous/foamHelp/helpTypes/helpType/helpTypeNew.C
+++ b/applications/utilities/miscellaneous/foamHelp/helpTypes/helpType/helpTypeNew.C
@@ -40,7 +40,7 @@ Foam::autoPtr<Foam::helpType> Foam::helpType::New
     {
         // special treatment for -help
         // exit without stack trace
-        if (helpTypeName.startsWith("-help"))
+        if (helpTypeName.starts_with("-help"))
         {
             FatalErrorInFunction
                 << "Valid helpType selections:" << nl
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/foamReader/library/vtkPVFoam.C b/applications/utilities/postProcessing/graphics/PVReaders/foamReader/library/vtkPVFoam.C
index c5c648c386a0073aed4e4e445f89733f5598c969..8db72b8bf1334abf448085f314565e630c429f0f 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/foamReader/library/vtkPVFoam.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/foamReader/library/vtkPVFoam.C
@@ -678,7 +678,7 @@ void Foam::vtkPVFoam::Update
         // Suppress caching of Lagrangian since it normally always changes.
         cachedVtp_.filterKeys
         (
-            [](const word& k){ return k.startsWith("lagrangian/"); },
+            [](const word& k){ return k.starts_with("lagrangian/"); },
             true // prune
         );
     }
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/foamReader/library/vtkPVFoamMesh.C b/applications/utilities/postProcessing/graphics/PVReaders/foamReader/library/vtkPVFoamMesh.C
index 5c41c4c52165d2f2d5c608191eb7cad0078158e3..b94cd67203848d8b0063d1fa5be57d9dc052f1a4 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/foamReader/library/vtkPVFoamMesh.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/foamReader/library/vtkPVFoamMesh.C
@@ -179,7 +179,7 @@ void Foam::vtkPVFoam::convertMeshPatches()
             }
         }
 
-        if (longName.startsWith("group/"))
+        if (longName.starts_with("group/"))
         {
             // Patch group. Collect patch faces.
 
diff --git a/src/OSspecific/MSwindows/MSwindows.C b/src/OSspecific/MSwindows/MSwindows.C
index 59dcfdf61e222cb53a88345a069bdbd0321178c5..c461f4a936fe2bad5fc95367f7b6326f3442e1c1 100644
--- a/src/OSspecific/MSwindows/MSwindows.C
+++ b/src/OSspecific/MSwindows/MSwindows.C
@@ -1221,7 +1221,7 @@ void* Foam::dlOpen(const fileName& libName, const bool check)
     (
         !handle
      && libName.find('/') == std::string::npos
-     && !libso.startsWith("lib")
+     && !libso.starts_with("lib")
     )
     {
         // Try with 'lib' prefix
diff --git a/src/OSspecific/POSIX/POSIX.C b/src/OSspecific/POSIX/POSIX.C
index 3febd55591d3af07179a7aaa98fbb95c600c71e5..c35a886f06effc30f847ec0e1bc70e18ef3b2b91 100644
--- a/src/OSspecific/POSIX/POSIX.C
+++ b/src/OSspecific/POSIX/POSIX.C
@@ -1674,7 +1674,7 @@ void* Foam::dlOpen(const fileName& libName, const bool check)
         if
         (
             libName.find('/') == std::string::npos
-         && !libName.startsWith("lib")
+         && !libName.starts_with("lib")
         )
         {
             // Try with 'lib' prefix
diff --git a/src/OpenFOAM/db/IOobject/IOobject.C b/src/OpenFOAM/db/IOobject/IOobject.C
index 470308a2eb99a9e7178508fd1b0606e62e1785b2..50746f5284f7bebd8095edd17934f71a567aedc9 100644
--- a/src/OpenFOAM/db/IOobject/IOobject.C
+++ b/src/OpenFOAM/db/IOobject/IOobject.C
@@ -97,17 +97,6 @@ namespace Foam
 }
 
 
-// file-scope
-//
-// A file is 'outside' of the case if it has been specified using an
-// absolute path (starts with '/')
-//
-static inline bool isOutsideOfCase(const std::string& file)
-{
-    return !file.empty() && file[0] == '/';
-}
-
-
 // * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * * //
 
 bool Foam::IOobject::fileNameComponents
@@ -119,7 +108,7 @@ bool Foam::IOobject::fileNameComponents
 )
 {
     // Convert explicit relative file-system path to absolute file-system path.
-    if (path.startsWith("./") || path.startsWith("../"))
+    if (path.starts_with("./") || path.starts_with("../"))
     {
         fileName absPath = cwd()/path;
         absPath.clean();
@@ -461,7 +450,10 @@ const Foam::fileName& Foam::IOobject::caseName() const
 
 Foam::fileName Foam::IOobject::path() const
 {
-    if (isOutsideOfCase(instance()))
+    // A file is 'outside' of the case if it has been specified using an
+    // absolute path (starts with '/')
+
+    if (instance().starts_with('/'))
     {
         return instance();
     }
diff --git a/src/OpenFOAM/db/IOobjectList/IOobjectList.C b/src/OpenFOAM/db/IOobjectList/IOobjectList.C
index f413dc4768ba03d781360f4bf281741b31741232..dd50e0c930016a2cfd371391b9827e677ba41ab9 100644
--- a/src/OpenFOAM/db/IOobjectList/IOobjectList.C
+++ b/src/OpenFOAM/db/IOobjectList/IOobjectList.C
@@ -382,7 +382,7 @@ Foam::label Foam::IOobjectList::prune_0()
     return
         HashPtrTable<IOobject>::filterKeys
         (
-            [](const word& k){ return k.endsWith("_0"); },
+            [](const word& k){ return k.ends_with("_0"); },
             true  // prune
         );
 }
diff --git a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.C b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.C
index 1b1c486680056493ca58b3fab5e92a8bafd269f8..f964a2a30364593f25dbbf4255801e0caf6bf5a1 100644
--- a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.C
+++ b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.C
@@ -924,7 +924,7 @@ void Foam::GeometricField<Type, PatchField, GeoMesh>::storeOldTimes() const
     (
         field0Ptr_
      && timeIndex_ != this->time().timeIndex()
-     && !this->name().endsWith("_0")
+     && !this->name().ends_with("_0")
     )
     {
         storeOldTime();
diff --git a/src/OpenFOAM/global/argList/argList.C b/src/OpenFOAM/global/argList/argList.C
index 4ed43d4c8c77ca4a734e8e54f6780f45b4fab7f6..99d2f04e2eee50021331aa0b69f3879ffc5e03f9 100644
--- a/src/OpenFOAM/global/argList/argList.C
+++ b/src/OpenFOAM/global/argList/argList.C
@@ -1164,7 +1164,7 @@ void Foam::argList::parse
                 }
 
                 // Case-relative if not absolute and not "./" etc
-                if (!source.isAbsolute() && !source.startsWith("."))
+                if (!source.isAbsolute() && !source.starts_with('.'))
                 {
                     source = rootPath_/globalCase_/source;
                     adjustOpt = true;
@@ -1632,8 +1632,8 @@ void Foam::argList::displayDoc(bool source) const
 
     for (const fileName& dir : docDirs)
     {
-        // http protocols are last in the list
-        if (dir.startsWith("http:") || dir.startsWith("https:"))
+        // The http protocols are last in the list
+        if (dir.starts_with("http:") || dir.starts_with("https:"))
         {
             url = dir/executable_ + docExt;
             break;
@@ -1643,7 +1643,7 @@ void Foam::argList::displayDoc(bool source) const
 
         if
         (
-            docFile.startsWith("file://")
+            docFile.starts_with("file://")
           ? isFile(docFile.substr(7))   // check part after "file://"
           : isFile(docFile)
         )
diff --git a/src/OpenFOAM/matrices/solution/solution.C b/src/OpenFOAM/matrices/solution/solution.C
index 1206376cef930f3c5fff67406520c01b27762835..916b64369f0ef1e7abd41269352f987ded44303a 100644
--- a/src/OpenFOAM/matrices/solution/solution.C
+++ b/src/OpenFOAM/matrices/solution/solution.C
@@ -77,11 +77,11 @@ void Foam::solution::read(const dictionary& dict)
             {
                 scalar value = relaxDict.get<scalar>(e);
 
-                if (e.startsWith("p"))
+                if (e.starts_with('p'))
                 {
                     fieldRelaxDict_.add(e, value);
                 }
-                else if (e.startsWith("rho"))
+                else if (e.starts_with("rho"))
                 {
                     fieldRelaxDict_.add(e, value);
                 }
diff --git a/src/OpenFOAM/primitives/strings/fileName/fileName.C b/src/OpenFOAM/primitives/strings/fileName/fileName.C
index 724c378f05115dab5194590cf561e19218816c78..64cdaa477f3d57ec51a54c2d431e45d85bbe89bd 100644
--- a/src/OpenFOAM/primitives/strings/fileName/fileName.C
+++ b/src/OpenFOAM/primitives/strings/fileName/fileName.C
@@ -191,36 +191,31 @@ bool Foam::fileName::equals(const std::string& s1, const std::string& s2)
 }
 
 
-bool Foam::fileName::isBackup(const std::string& str)
+bool Foam::fileName::isBackup(const std::string& s)
 {
-    if (str.empty())
+    if (s.empty())
     {
         return false;
     }
-    else if (str.back() == '~')
+    else if (s.back() == '~')
     {
         return true;
     }
 
     // Now check the extension
-    const auto dot = find_ext(str);
+    auto dot = find_ext(s);
 
     if (dot == npos)
     {
         return false;
     }
 
-    const std::string ending = str.substr(dot+1);
-
-    if (ending.empty())
-    {
-        return false;
-    }
+    ++dot;
 
     return
     (
-        ending == "bak" || ending == "BAK"
-     || ending == "old" || ending == "save"
+        !s.compare(dot, npos, "bak") || !s.compare(dot, npos, "BAK")
+     || !s.compare(dot, npos, "old") || !s.compare(dot, npos, "save")
     );
 }
 
@@ -448,7 +443,7 @@ Foam::fileName Foam::fileName::relative
     if
     (
         top && (f.size() > (top+1)) && f[top] == '/'
-     && f.startsWith(parent)
+     && f.starts_with(parent)
     )
     {
         if (caseTag)
diff --git a/src/OpenFOAM/primitives/strings/fileName/fileNameI.H b/src/OpenFOAM/primitives/strings/fileName/fileNameI.H
index 6f0ff34b317607268f56d9233bdcd26ca2c71529..961997331acad23f89841fe8d937209a9b046702 100644
--- a/src/OpenFOAM/primitives/strings/fileName/fileNameI.H
+++ b/src/OpenFOAM/primitives/strings/fileName/fileNameI.H
@@ -128,7 +128,7 @@ inline void Foam::fileName::stripInvalid()
         }
 
         removeRepeated('/');
-        removeTrailing('/');
+        removeEnd('/');
     }
 }
 
@@ -137,7 +137,7 @@ inline bool Foam::fileName::isAbsolute(const std::string& str)
 {
     return
     (
-        (!str.empty() && str[0] == '/')
+        (!str.empty() && str.front() == '/')  // ie, str.starts_with('/')
         #ifdef _WIN32
         ||
         (
diff --git a/src/OpenFOAM/primitives/strings/string/string.C b/src/OpenFOAM/primitives/strings/string/string.C
index fb0f02601a5734f0e65c3098e2bfe1f0983060a5..34bc400d91ac06572e8ddc2774e051d3f1228bc7 100644
--- a/src/OpenFOAM/primitives/strings/string/string.C
+++ b/src/OpenFOAM/primitives/strings/string/string.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2016-2017 OpenCFD Ltd.
+    Copyright (C) 2016-2019 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -34,7 +34,9 @@ License
 /* * * * * * * * * * * * * * * Static Member Data  * * * * * * * * * * * * * */
 
 const char* const Foam::string::typeName = "string";
-int Foam::string::debug(Foam::debug::debugSwitch(string::typeName, 0));
+
+int Foam::string::debug(Foam::debug::debugSwitch(Foam::string::typeName, 0));
+
 const Foam::string Foam::string::null;
 
 
@@ -117,16 +119,14 @@ Foam::string::size_type Foam::string::count(const char c) const
 
 Foam::string& Foam::string::replace
 (
-    const string& oldStr,
-    const string& newStr,
-    const size_type start
+    const std::string& s1,
+    const std::string& s2,
+    size_type pos
 )
 {
-    size_type pos = start;
-
-    if ((pos = find(oldStr, pos)) != npos)
+    if ((pos = find(s1, pos)) != npos)
     {
-        std::string::replace(pos, oldStr.size(), newStr);
+        std::string::replace(pos, s1.size(), s2);
     }
 
     return *this;
@@ -135,24 +135,20 @@ Foam::string& Foam::string::replace
 
 Foam::string& Foam::string::replaceAll
 (
-    const string& oldStr,
-    const string& newStr,
-    const size_type start
+    const std::string& s1,
+    const std::string& s2,
+    size_type pos
 )
 {
-    const size_type lenOld = oldStr.size();
-    const size_type lenNew = newStr.size();
+    const auto n1 = s1.length();
+    const auto n2 = s2.length();
 
-    if (lenOld)
+    if (n1)
     {
-        for
-        (
-            size_type pos = start;
-            (pos = find(oldStr, pos)) != npos;
-            pos += lenNew
-        )
+        while ((pos = find(s1, pos)) != npos)
         {
-            std::string::replace(pos, lenOld, newStr);
+            std::string::replace(pos, n1, s2);
+            pos += n2;
         }
     }
 
@@ -201,20 +197,14 @@ bool Foam::string::removeRepeated(const char character)
 }
 
 
-Foam::string Foam::string::removeRepeated(const char character) const
+bool Foam::string::removeStart(const std::string& text)
 {
-    string str(*this);
-    str.removeRepeated(character);
-    return str;
-}
+    const auto txtLen = text.length();
+    const auto strLen = length();
 
-
-bool Foam::string::removeTrailing(const char character)
-{
-    const string::size_type nChar = size();
-    if (character && nChar > 1 && operator[](nChar-1) == character)
+    if (txtLen && strLen >= txtLen && !compare(0, txtLen, text))
     {
-        resize(nChar-1);
+        erase(0, txtLen);
         return true;
     }
 
@@ -222,26 +212,14 @@ bool Foam::string::removeTrailing(const char character)
 }
 
 
-Foam::string Foam::string::removeTrailing(const char character) const
-{
-    string str(*this);
-    str.removeTrailing(character);
-    return str;
-}
-
-
-bool Foam::string::removeStart(const std::string& text)
+bool Foam::string::removeEnd(const std::string& text)
 {
-    const size_type txtLen = text.size();
-    if (!txtLen)
-    {
-        return true;
-    }
+    const auto txtLen = text.length();
+    const auto strLen = length();
 
-    const size_type strLen = this->size();
-    if (strLen >= txtLen && !compare(0, txtLen, text))
+    if (txtLen && strLen >= txtLen && !compare(strLen - txtLen, npos, text))
     {
-        this->erase(0, txtLen);
+        resize(strLen - txtLen);
         return true;
     }
 
@@ -249,18 +227,11 @@ bool Foam::string::removeStart(const std::string& text)
 }
 
 
-bool Foam::string::removeEnd(const std::string& text)
+bool Foam::string::removeStart(const char c)
 {
-    const size_type txtLen = text.size();
-    if (!txtLen)
-    {
-        return true;
-    }
-
-    const size_type strLen = this->size();
-    if (strLen >= txtLen && !compare(strLen - txtLen, npos, text))
+    if (length() > 1 && front() == c)
     {
-        this->resize(strLen - txtLen);
+        erase(0, 1);
         return true;
     }
 
@@ -268,29 +239,16 @@ bool Foam::string::removeEnd(const std::string& text)
 }
 
 
-bool Foam::string::startsWith(const std::string& text) const
-{
-    const size_type strLen = this->size();
-    const size_type txtLen = text.size();
-
-    return
-    (
-        !txtLen
-     || (strLen >= txtLen && !compare(0, txtLen, text))
-    );
-}
-
-
-bool Foam::string::endsWith(const std::string& text) const
+bool Foam::string::removeEnd(const char c)
 {
-    const size_type strLen = this->size();
-    const size_type txtLen = text.size();
+    const auto n = length();
+    if (n > 1 && back() == c)
+    {
+        resize(n-1);
+        return true;
+    }
 
-    return
-    (
-        !txtLen
-     || (strLen >= txtLen && !compare(strLen - txtLen, npos, text))
-    );
+    return false;
 }
 
 
diff --git a/src/OpenFOAM/primitives/strings/string/string.H b/src/OpenFOAM/primitives/strings/string/string.H
index aa473dd7a267cdaa0e8c79521a6c3aea5a059c8e..829b28f97843e763c5417641ece7d8aafeed2844 100644
--- a/src/OpenFOAM/primitives/strings/string/string.H
+++ b/src/OpenFOAM/primitives/strings/string/string.H
@@ -40,6 +40,7 @@ See also
     configuration directory
 
 SourceFiles
+    stringI.H
     string.C
     stringIO.C
     stringTemplates.C
@@ -51,7 +52,6 @@ SourceFiles
 
 #include "char.H"
 #include "Hasher.H"
-
 #include <string>
 #include <cstring>
 #include <cstdlib>
@@ -136,9 +136,12 @@ protected:
 
 public:
 
-    // Static data members
+    // Static Data Members
 
+        //- The type name "string"
         static const char* const typeName;
+
+        //- The debug flag
         static int debug;
 
         //- An empty string
@@ -183,12 +186,7 @@ public:
         explicit string(Istream& is);
 
 
-    // Member Functions
-
-        //- Count the number of occurrences of the specified character
-        //- in the string
-        //  Partially deprecated (NOV-2017) in favour of stringOps::count
-        size_type count(const char c) const;
+    // Static Member Functions
 
         //- Does the string contain valid characters only?
         template<class String>
@@ -215,6 +213,9 @@ public:
             const char quote = '\\'
         );
 
+
+    // Member Functions
+
         //- Test for equality.
         //  \return True when strings match literally.
         inline bool match(const std::string& text) const;
@@ -222,22 +223,23 @@ public:
         //- Avoid masking the normal std::string replace
         using std::string::replace;
 
-        //- Replace first occurrence of sub-string oldStr with newStr,
-        //- beginning at start
+        //- Replace first occurrence of sub-string s1 with s2,
+        //- beginning at pos
         string& replace
         (
-            const string& oldStr,
-            const string& newStr,
-            const size_type start = 0
+            const std::string& s1,
+            const std::string& s2,
+            size_type pos = 0
         );
 
-        //- Replace all occurrences of sub-string oldStr with newStr,
-        //- beginning at start. This is a no-op if oldStr is empty.
+        //- Replace all occurrences of sub-string s1 with s2,
+        //- beginning at pos in the string.
+        //  This is a no-op if s1 is empty.
         string& replaceAll
         (
-            const string& oldStr,
-            const string& newStr,
-            const size_type start = 0
+            const std::string& s1,
+            const std::string& s2,
+            size_type pos = 0
         );
 
         //- Inplace expand initial tags, tildes, and all occurrences of
@@ -252,34 +254,21 @@ public:
         //  \return True if string changed
         bool removeRepeated(const char character);
 
-        //- Return string with repeated characters removed
-        string removeRepeated(const char character) const;
-
-        //- Remove trailing character, unless string is a single character
-        //  \return True if string changed
-        bool removeTrailing(const char character);
-
-        //- Return string with trailing character removed,
-        //  unless string is a single character
-        string removeTrailing(const char character) const;
-
         //- Remove the given text from the start of the string.
-        //  \return True if the removal occurred or the given text is empty.
+        //  \return True if the removal occurred
         bool removeStart(const std::string& text);
 
+        //- Remove leading character, unless string is a single character
+        //  \return True if the removal occurred
+        bool removeStart(const char c);
+
         //- Remove the given text from the end of the string.
-        //  Always true if the removal occurred or the given text is empty.
+        //  \return True if the removal occurred
         bool removeEnd(const std::string& text);
 
-        //- True if the string starts with the given text.
-        //  Always true if the given text is empty or if the string
-        //  is identical to the given text.
-        bool startsWith(const std::string& text) const;
-
-        //- True if the string ends with the given text.
-        //  Always true if the given text is empty or if the string
-        //  is identical to the given text.
-        bool endsWith(const std::string& text) const;
+        //- Remove trailing character, unless string is a single character
+        //  \return True if the removal occurred
+        bool removeEnd(const char c);
 
 
     // Editing
@@ -293,6 +282,50 @@ public:
         //- Test for equality. Allows use as a predicate.
         //  \return True when strings match literally.
         inline bool operator()(const std::string& text) const;
+
+
+    // Housekeeping
+
+        //- True if string starts with the given prefix (cf. C++20)
+        bool starts_with(const std::string& s) const
+        {
+            return (size() >= s.size() && !compare(0, s.size(), s));
+        }
+
+        //- True if string starts with the given character (cf. C++20)
+        bool starts_with(const char c) const
+        {
+            return (!empty() && front() == c);
+        }
+
+        //- True if string ends with the given suffix (cf. C++20)
+        bool ends_with(const std::string& s) const
+        {
+            return (size() >= s.size() && !compare(size()-s.size(), npos, s));
+        }
+
+        //- True if string ends with the given character (cf. C++20)
+        bool ends_with(const char c) const
+        {
+            return (!empty() && back() == c);
+        }
+
+        //- Count the number of occurrences of the specified character
+        //- in the string
+        //  Partially deprecated (NOV-2017) in favour of stringOps::count
+        size_type count(const char c) const;
+
+        //- Deprecated(2019-11)
+        //  \deprecated(2019-11) use starts_with instead
+        bool startsWith(const std::string& s) const { return starts_with(s); }
+
+        //- Deprecated(2019-11)
+        //  \deprecated(2019-11) use ends_with instead
+        bool endsWith(const std::string& s) const { return ends_with(s); }
+
+        //- Deprecated(2019-11)
+        //  \deprecated(2019-11) use removeEnd instead
+        bool removeTrailing(const char c) { return removeEnd(c); }
 };
 
 
diff --git a/src/OpenFOAM/primitives/strings/string/stringI.H b/src/OpenFOAM/primitives/strings/string/stringI.H
index a5e890749ecf7e3d81750ef98a30fd2e1550528b..51a2046960bd243a0695b7eafba3922adc6da9c8 100644
--- a/src/OpenFOAM/primitives/strings/string/stringI.H
+++ b/src/OpenFOAM/primitives/strings/string/stringI.H
@@ -68,7 +68,7 @@ inline bool Foam::string::removePath()
         return false;
     }
 
-    this->erase(0, i+1);
+    erase(0, i+1);
     return true;
 }
 
@@ -82,7 +82,7 @@ inline bool Foam::string::removeExt()
         return false;
     }
 
-    this->resize(i);
+    erase(i);
     return true;
 }
 
@@ -163,7 +163,7 @@ inline bool Foam::string::stripInvalid(std::string& str)
             }
         }
 
-        str.resize(nChar);
+        str.erase(nChar);
 
         return true;
     }
@@ -228,7 +228,7 @@ Foam::string::quotemeta(const std::string& str, const char quote)
         sQuoted += c;
     }
 
-    sQuoted.resize(sQuoted.size());
+    sQuoted.shrink_to_fit();
 
     return sQuoted;
 }
@@ -251,7 +251,7 @@ inline String Foam::string::validate(const std::string& str)
         }
     }
 
-    out.resize(len);
+    out.erase(len);
 
     return out;
 }
diff --git a/src/fileFormats/ensight/name/ensightFileNameI.H b/src/fileFormats/ensight/name/ensightFileNameI.H
index 7b90a9270baf0a9c0070b1592b876a66791242c9..41d57d414347c7c2c0c957d1cb5099baf712b1c8 100644
--- a/src/fileFormats/ensight/name/ensightFileNameI.H
+++ b/src/fileFormats/ensight/name/ensightFileNameI.H
@@ -71,7 +71,7 @@ inline void Foam::ensight::FileName::stripInvalid()
     string::stripInvalid<FileName>(*this);
 
     removeRepeated('/');
-    removeTrailing('/');
+    removeEnd('/');
 
     if (empty())
     {
diff --git a/src/fileFormats/vtk/file/foamVtkSeriesWriter.C b/src/fileFormats/vtk/file/foamVtkSeriesWriter.C
index 62ab6c86aecd20719ae9165d3b836292edc01756..104127b0623a8e49e25262b3f0c9a59125b84a4f 100644
--- a/src/fileFormats/vtk/file/foamVtkSeriesWriter.C
+++ b/src/fileFormats/vtk/file/foamVtkSeriesWriter.C
@@ -618,7 +618,7 @@ Foam::label Foam::vtk::seriesWriter::scan
             return
             (
                 minLen < file.length()
-             && file.hasExt(ext) && file.startsWith(stem)
+             && file.hasExt(ext) && file.starts_with(stem)
             );
         };
 
diff --git a/src/functionObjects/lagrangian/vtkCloud/vtkCloud.C b/src/functionObjects/lagrangian/vtkCloud/vtkCloud.C
index d7812297b3fc4f6ede4e6e1b138f28a229a1b8b2..f951e510f51ec8726469dcb4b35f5b7496b5e99a 100644
--- a/src/functionObjects/lagrangian/vtkCloud/vtkCloud.C
+++ b/src/functionObjects/lagrangian/vtkCloud/vtkCloud.C
@@ -256,7 +256,7 @@ bool Foam::functionObjects::vtkCloud::writeCloud
     (
         [](const word& k)
         {
-            return k.startsWith("position") || k.startsWith("coordinate");
+            return k.starts_with("position") || k.starts_with("coordinate");
         },
         true  // prune
     );
diff --git a/src/functionObjects/utilities/ensightWrite/ensightWrite.C b/src/functionObjects/utilities/ensightWrite/ensightWrite.C
index 5d80fc6515c684da9722f641bf7fc5f72c3bc995..e2ca33cf1b54ffb6ba57ee396de4238c848b40d1 100644
--- a/src/functionObjects/utilities/ensightWrite/ensightWrite.C
+++ b/src/functionObjects/utilities/ensightWrite/ensightWrite.C
@@ -226,7 +226,7 @@ bool Foam::functionObjects::ensightWrite::write()
     // Prune restart fields
     acceptField.filterKeys
     (
-        [](const word& k){ return k.endsWith("_0"); },
+        [](const word& k){ return k.ends_with("_0"); },
         true // prune
     );
 
diff --git a/src/functionObjects/utilities/vtkWrite/vtkWrite.C b/src/functionObjects/utilities/vtkWrite/vtkWrite.C
index 3a3dd0c88189d57de2146adb4a4d190614e2c882..036bd93ddc376d56a870e5898fb34c46210836f3 100644
--- a/src/functionObjects/utilities/vtkWrite/vtkWrite.C
+++ b/src/functionObjects/utilities/vtkWrite/vtkWrite.C
@@ -304,7 +304,7 @@ bool Foam::functionObjects::vtkWrite::write()
         // Prune restart fields
         acceptField.filterKeys
         (
-            [](const word& k){ return k.endsWith("_0"); },
+            [](const word& k){ return k.ends_with("_0"); },
             true // prune
         );
 
diff --git a/src/meshTools/edgeMesh/edgeMeshFormats/obj/OBJedgeFormat.C b/src/meshTools/edgeMesh/edgeMeshFormats/obj/OBJedgeFormat.C
index 43c5b19505f8c69fd7e4511bcd31cdf928c30051..7f59885fab25e5d19ea54ceef71348749845d720 100644
--- a/src/meshTools/edgeMesh/edgeMeshFormats/obj/OBJedgeFormat.C
+++ b/src/meshTools/edgeMesh/edgeMeshFormats/obj/OBJedgeFormat.C
@@ -115,7 +115,7 @@ bool Foam::fileFormats::OBJedgeFormat::read(const fileName& filename)
         string line = this->getLineNoComment(is);
 
         // Line continuations
-        while (line.removeEnd("\\"))
+        while (line.removeEnd('\\'))
         {
             line += this->getLineNoComment(is);
         }
diff --git a/src/overset/dynamicOversetFvMesh/dynamicOversetFvMesh.C b/src/overset/dynamicOversetFvMesh/dynamicOversetFvMesh.C
index 3f286cb1e6b4a06a9da03d9a8fa61af4692fdb2c..725dd111a32767f1ffabba9875635b5c58ffc6ab 100644
--- a/src/overset/dynamicOversetFvMesh/dynamicOversetFvMesh.C
+++ b/src/overset/dynamicOversetFvMesh/dynamicOversetFvMesh.C
@@ -611,7 +611,7 @@ bool Foam::dynamicOversetFvMesh::update()
 
 Foam::word Foam::dynamicOversetFvMesh::baseName(const word& name)
 {
-    if (name.endsWith("_0"))
+    if (name.ends_with("_0"))
     {
         return baseName(name.substr(0, name.size()-2));
     }
diff --git a/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C b/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C
index 08f01d393e337e86250cc8cd972fbbfa2408f06a..51518df49c419820e0a9d52ce8073ce6d02b9895 100644
--- a/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C
@@ -149,7 +149,7 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
         // ANSA extension
         // line 1: $ANSA_NAME;<int>;<word>;
         // line 2: $partName
-        if (line.startsWith("$ANSA_NAME"))
+        if (line.starts_with("$ANSA_NAME"))
         {
             const auto sem0 = line.find(';', 0);
             const auto sem1 = line.find(';', sem0+1);
@@ -167,7 +167,7 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
 
                 string rawName;
                 is.getLine(rawName);
-                rawName.removeEnd("\r");  // Possible CR-NL
+                rawName.removeEnd('\r');  // Possible CR-NL
                 ansaName = word::validate(rawName.substr(1));
 
                 // Info<< "ANSA tag for NastranID:" << ansaId
@@ -179,7 +179,7 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
 
         // HYPERMESH extension
         // $HMNAME COMP                   1"partName"
-        if (line.startsWith("$HMNAME COMP") && line.find('"') != string::npos)
+        if (line.starts_with("$HMNAME COMP") && line.find('"') != string::npos)
         {
             label groupId = readLabel(line.substr(16, 16));
 
diff --git a/src/surfMesh/surfaceFormats/obj/OBJsurfaceFormat.C b/src/surfMesh/surfaceFormats/obj/OBJsurfaceFormat.C
index de1755f108f0ce3486f96e2d8f48fe5c759f46ca..3ad0d802f6cee55edfc912514ec9c8d920ed0f2e 100644
--- a/src/surfMesh/surfaceFormats/obj/OBJsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/obj/OBJsurfaceFormat.C
@@ -83,7 +83,7 @@ bool Foam::fileFormats::OBJsurfaceFormat<Face>::read
         string line = this->getLineNoComment(is);
 
         // Line continuations
-        while (line.removeEnd("\\"))
+        while (line.removeEnd('\\'))
         {
             line += this->getLineNoComment(is);
         }