ENH: add offset support to stringOps::split functions

- for example,

     string buffer = ...;
     SubStrings<string> split;
     {
         auto colon = buffer.find(':');

         if (colon != std::string::npos)
         {
             split = stringOps::splitSpace(buffer, colon+1);
         }
     }

    Not really possible with a substr() since that would create a new
    temporary which then disappears.  Similarly awkward to split and
    then scan for the ':' to decide how many to discard.

ENH: add pop_front() and pop_back() methods to SubStrings

- the content is trivial enough (a pair of iterators) and the total
  number of elements is usually reasonable short so that removal of
  elements is inexpensive

  For example,

     string buffer = ...;
     auto split = stringOps::splitSpace(buffer);

     if (!split.empty() && split[0].str() == "face")
     {
         split.pop_front();
     }
This commit is contained in:
Mark Olesen 2024-05-02 15:47:53 +02:00
parent 3fed41547f
commit 883196981d
12 changed files with 177 additions and 87 deletions

View File

@ -123,7 +123,7 @@ int main(int argc, char *argv[])
);
Info<< testInput << nl;
SubStrings<string> args = stringOps::splitSpace(testInput);
auto args = stringOps::splitSpace(testInput);
Info<< "split into " << args.size() << " args" << nl;
CStringList inC(args);

View File

@ -47,7 +47,7 @@ using namespace Foam;
template<class PrimitiveType>
static List<PrimitiveType> splitStringToList(const std::string& str)
{
const SubStrings<std::string> items = stringOps::splitAny(str, " ,;");
const auto items = stringOps::splitAny(str, " ,;");
DynamicList<PrimitiveType> values(items.size());

View File

@ -148,7 +148,7 @@ int main(int argc, char *argv[])
Info<< "input: " << input << nl
<< "expand: " << output << nl
<< "split: " << stringOps::split(output, "/") << nl << nl;
<< "split: " << stringOps::split(output, '/') << nl << nl;
}
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2021 OpenCFD Ltd.
Copyright (C) 2017-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -34,6 +34,7 @@ Description
#include "argList.H"
#include "fileName.H"
#include "stringOps.H"
#include "Switch.H"
using namespace Foam;
@ -65,6 +66,9 @@ int main(int argc, char *argv[])
{
argList::noBanner();
argList::noParallel();
argList::noMandatoryArgs();
argList::addArgument("string .. stringN");
argList::addOption
(
"any",
@ -89,6 +93,12 @@ int main(int argc, char *argv[])
"int",
"test split on fixed width"
);
argList::addOption
(
"begin",
"int",
"begin offset for splits"
);
argList::addBoolOption
(
"slash",
@ -104,18 +114,25 @@ int main(int argc, char *argv[])
"empty",
"preserve empty strings in split"
);
argList args(argc, argv, false, true);
argList args(argc, argv);
if (args.size() <= 1 && args.options().empty())
{
args.printUsage();
}
const label beginOffset = args.getOrDefault<label>("begin", 0);
const bool keepEmpty = args.found("empty");
Info<< "begin offset: " << beginOffset << nl;
Info<< "keep empty : " << Switch::name(keepEmpty) << nl;
const label nopts =
args.count({"any", "slash", "space", "sub", "fixed", "char"});
if (args.found("any"))
{
const std::string& str = args["any"];
@ -125,7 +142,7 @@ int main(int argc, char *argv[])
for (label argi=1; argi < args.size(); ++argi)
{
const auto split = stringOps::splitAny(args[argi], str);
auto split = stringOps::splitAny(args[argi], str, beginOffset);
printSubStrings(args[argi], split);
}
@ -144,7 +161,7 @@ int main(int argc, char *argv[])
for (label argi=1; argi < args.size(); ++argi)
{
const auto split = stringOps::split(args[argi], str);
auto split = stringOps::split(args[argi], str, beginOffset);
printSubStrings(args[argi], split);
}
@ -161,7 +178,11 @@ int main(int argc, char *argv[])
for (label argi=1; argi < args.size(); ++argi)
{
const auto split = stringOps::splitSpace(args[argi]);
auto split = stringOps::splitSpace(args[argi], beginOffset);
printSubStrings(args[argi], split);
Info<< "pop_front(2)" << nl;
split.pop_front(2);
printSubStrings(args[argi], split);
}
@ -180,7 +201,8 @@ int main(int argc, char *argv[])
for (label argi=1; argi < args.size(); ++argi)
{
const auto split = stringOps::split(args[argi], delim, keepEmpty);
auto split =
stringOps::split(args[argi], delim, beginOffset, keepEmpty);
printSubStrings(args[argi], split);
}
@ -199,7 +221,7 @@ int main(int argc, char *argv[])
for (label argi=1; argi < args.size(); ++argi)
{
const auto split = stringOps::splitFixed(args[argi], width);
auto split = stringOps::splitFixed(args[argi], width, beginOffset);
printSubStrings(args[argi], split);
}
@ -219,7 +241,8 @@ int main(int argc, char *argv[])
for (label argi=1; argi < args.size(); ++argi)
{
const auto split = stringOps::split(args[argi], delim, keepEmpty);
auto split =
stringOps::split(args[argi], delim, beginOffset, keepEmpty);
printSubStrings(args[argi], split);
}
}

View File

@ -42,7 +42,7 @@ namespace Foam
template<class PrimitiveType>
static List<PrimitiveType> splitStringToList(const std::string& str)
{
const SubStrings<std::string> items = stringOps::splitAny(str, " ,;");
const auto items = stringOps::splitAny(str, " ,;");
DynamicList<PrimitiveType> values(items.size());

View File

@ -36,7 +36,7 @@ Foam::scalarRanges Foam::scalarRanges::parse
bool report
)
{
const SubStrings<std::string> items = stringOps::splitAny(str, " ,;");
const auto items = stringOps::splitAny(str, " ,;");
scalarRanges ranges(items.size());

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2021 OpenCFD Ltd.
Copyright (C) 2017-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -66,12 +66,6 @@ public:
typename StringType::const_iterator;
// Constructors
//- Default construct
SubStrings() = default;
// Member Functions
//- The total string length of all sub-elements.
@ -109,6 +103,40 @@ public:
this->push_back(range);
}
//- Reduce size by 1 or more elements. Can be called on an empty list.
void pop_back(size_t n = 1)
{
if (n >= this->size())
{
this->clear();
}
else if (n > 0)
{
this->resize(this->size() - n);
}
}
//- Reduce size by 1 or more elements (from the front).
//- Can be called on an empty list.
void pop_front(size_t n = 1)
{
if (n >= this->size())
{
this->clear();
}
else if (n > 0)
{
// Overlapping range, avoid std::copy, std::move
for (size_t src = n, dst = 0; src < this->size(); ++src, ++dst)
{
(*this)[dst] = (*this)[src];
}
this->resize(this->size() - n);
}
}
// FUTURE?
// #if __cplusplus >= 201703L
// std::string_view view(size_t pos) const

View File

@ -372,8 +372,13 @@ namespace stringOps
template<class StringType>
Foam::SubStrings<StringType> split
(
//! The string to split
const StringType& str,
//! The delimiter for splitting. Ill-defined if NUL character
const char delim,
//! Offset within string to start splitting
std::string::size_type pos = 0,
//! Retain empty fields
const bool keepEmpty = false
);
@ -382,8 +387,13 @@ namespace stringOps
template<class StringType>
Foam::SubStrings<StringType> split
(
//! The string to split
const StringType& str,
//! The delimiters for splitting. Ill-defined if empty
const std::string& delim,
//! Offset within string to start splitting
std::string::size_type pos = 0,
//! Retain empty fields
const bool keepEmpty = false
);
@ -393,22 +403,25 @@ namespace stringOps
template<class StringType>
Foam::SubStrings<StringType> splitAny
(
//! The string to split
const StringType& str,
const std::string& delim
//! The delimiters for splitting. Ill-defined if empty!
const std::string& delim,
//! Offset within string to start splitting
std::string::size_type pos = 0
);
//- Split string into sub-strings using a fixed field width.
// Behaviour is ill-defined if width is zero.
// \param str the string to be split
// \param width the fixed field width for each sub-string
// \param start the optional offset of where to start the splitting.
// Any text prior to start is ignored in the operation.
template<class StringType>
Foam::SubStrings<StringType> splitFixed
(
//! The string to split
const StringType& str,
//! Fixed field width for each sub-string
const std::string::size_type width,
const std::string::size_type start = 0
//! Offset within string to start splitting
std::string::size_type pos = 0
);
//- Split string into sub-strings at whitespace (TAB, NL, VT, FF, CR, SPC)
@ -416,23 +429,25 @@ namespace stringOps
template<class StringType>
Foam::SubStrings<StringType> splitSpace
(
const StringType& str
//! The string to split
const StringType& str,
//! Offset within string to start splitting
std::string::size_type pos = 0
);
//- Output string with text wrapping.
// Always includes a trailing newline, unless the string itself is empty.
//
// \param os the output stream
// \param str the text to be output
// \param width the max-width before wrapping
// \param indent indentation for continued lines
// \param escape escape any backslashes on output
void writeWrapped
(
//! The output stream
OSstream& os,
//! The text to be output
const std::string& str,
//! The max-width before wrapping
const std::string::size_type width,
//! Indentation for continued lines
const std::string::size_type indent = 0,
//! Escape any backslashes on output
const bool escape = false
);

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2023 OpenCFD Ltd.
Copyright (C) 2016-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -98,34 +98,40 @@ Foam::SubStrings<StringType> Foam::stringOps::split
(
const StringType& str,
const char delim,
std::string::size_type pos,
const bool keepEmpty
)
{
Foam::SubStrings<StringType> lst;
if (str.empty() || !delim)
Foam::SubStrings<StringType> list;
if
(
!delim
|| (pos == std::string::npos || pos >= str.size())
)
{
return lst;
return list;
}
lst.reserve(20);
list.reserve(20);
std::string::size_type beg = 0, end = 0;
while ((end = str.find(delim, beg)) != std::string::npos)
std::string::size_type end;
while ((end = str.find(delim, pos)) != std::string::npos)
{
if (keepEmpty || (beg < end))
if (keepEmpty || (pos < end))
{
lst.append(str.cbegin() + beg, str.cbegin() + end);
list.append(str.cbegin() + pos, str.cbegin() + end);
}
beg = end + 1;
pos = end + 1;
}
// Trailing element
if (keepEmpty ? (beg <= str.size()) : (beg < str.size()))
if (keepEmpty ? (pos <= str.size()) : (pos < str.size()))
{
lst.append(str.cbegin() + beg, str.cend());
list.append(str.cbegin() + pos, str.cend());
}
return lst;
return list;
}
@ -134,34 +140,40 @@ Foam::SubStrings<StringType> Foam::stringOps::split
(
const StringType& str,
const std::string& delim,
std::string::size_type pos,
const bool keepEmpty
)
{
Foam::SubStrings<StringType> lst;
if (str.empty() || delim.empty())
Foam::SubStrings<StringType> list;
if
(
delim.empty()
|| (pos == std::string::npos || pos >= str.size())
)
{
return lst;
return list;
}
lst.reserve(20);
list.reserve(20);
std::string::size_type beg = 0, end = 0;
while ((end = str.find(delim, beg)) != std::string::npos)
std::string::size_type end;
while ((end = str.find(delim, pos)) != std::string::npos)
{
if (keepEmpty || (beg < end))
if (keepEmpty || (pos < end))
{
lst.append(str.cbegin() + beg, str.cbegin() + end);
list.append(str.cbegin() + pos, str.cbegin() + end);
}
beg = end + delim.size();
pos = end + delim.size();
}
// Trailing element
if (keepEmpty ? (beg <= str.size()) : (beg < str.size()))
if (keepEmpty ? (pos <= str.size()) : (pos < str.size()))
{
lst.append(str.cbegin() + beg, str.cend());
list.append(str.cbegin() + pos, str.cend());
}
return lst;
return list;
}
@ -169,40 +181,41 @@ template<class StringType>
Foam::SubStrings<StringType> Foam::stringOps::splitAny
(
const StringType& str,
const std::string& delim
const std::string& delim,
std::string::size_type pos
)
{
Foam::SubStrings<StringType> lst;
if (str.empty() || delim.empty())
Foam::SubStrings<StringType> list;
if
(
delim.empty()
|| (pos == std::string::npos || pos >= str.size())
)
{
return lst;
return list;
}
lst.reserve(20);
list.reserve(20);
for
(
std::string::size_type pos = 0;
(pos = str.find_first_not_of(delim, pos)) != std::string::npos;
/*nil*/
)
while ((pos = str.find_first_not_of(delim, pos)) != std::string::npos)
{
const auto end = str.find_first_of(delim, pos);
if (end == std::string::npos)
{
// Trailing element
lst.append(str.cbegin() + pos, str.cend());
list.append(str.cbegin() + pos, str.cend());
break;
}
// Intermediate element
lst.append(str.cbegin() + pos, str.cbegin() + end);
list.append(str.cbegin() + pos, str.cbegin() + end);
pos = end + 1;
}
return lst;
return list;
}
@ -211,43 +224,53 @@ Foam::SubStrings<StringType> Foam::stringOps::splitFixed
(
const StringType& str,
const std::string::size_type width,
const std::string::size_type start
std::string::size_type pos
)
{
Foam::SubStrings<StringType> lst;
if (str.empty() || !width)
Foam::SubStrings<StringType> list;
if
(
!width
|| (pos == std::string::npos || pos >= str.size())
)
{
return lst;
return list;
}
const auto len = str.size();
lst.reserve(1 + (len / width));
list.reserve(1 + ((str.size() - pos) / width));
for (std::string::size_type pos = start; pos < len; pos += width)
const auto len = str.size();
while (pos < len)
{
const auto end = (pos + width);
if (end >= len)
{
// Trailing element
lst.append(str.cbegin() + pos, str.cend());
list.append(str.cbegin() + pos, str.cend());
break;
}
lst.append(str.cbegin() + pos, str.cbegin() + end);
// Intermediate element
list.append(str.cbegin() + pos, str.cbegin() + end);
pos += width;
}
return lst;
return list;
}
template<class StringType>
Foam::SubStrings<StringType> Foam::stringOps::splitSpace
(
const StringType& str
const StringType& str,
std::string::size_type pos
)
{
return splitAny(str, "\t\n\v\f\r ");
return splitAny(str, "\t\n\v\f\r ", pos);
}

View File

@ -120,7 +120,7 @@ bool Foam::fileFormats::OBJedgeFormat::read(const fileName& filename)
line += this->getLineNoComment(is);
}
const SubStrings<string> tokens = stringOps::splitSpace(line);
const auto tokens = stringOps::splitSpace(line);
// Require command and some arguments
if (tokens.size() < 2)

View File

@ -193,7 +193,8 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
if (line.starts_with("$ANSA_NAME"))
{
// Keep empty elements when splitting
const auto args = stringOps::split<std::string>(line, ';', true);
const auto args =
stringOps::split<std::string>(line, ';', 0, true);
if (args.size() > 4 && line.starts_with("$ANSA_NAME_COMMENT"))
{

View File

@ -91,7 +91,7 @@ bool Foam::fileFormats::OBJsurfaceFormat<Face>::read
line += this->getLineNoComment(is);
}
const SubStrings<string> tokens = stringOps::splitSpace(line);
const auto tokens = stringOps::splitSpace(line);
// Require command and some arguments
if (tokens.size() < 2)