libutil/strings: add partitionString

This partitions a string into two parts based on the first occurrence of
the separator.

This function handles the case when the separator never occur in the
target string by returning an optional<T> in the second argument of the
pair.

Change-Id: I9ad44375dbaa137a4d21d2408bc2ffa34fab62a7
Signed-off-by: Raito Bezarius <raito@lix.systems>
This commit is contained in:
Raito Bezarius
2026-03-03 20:54:08 +00:00
parent 135c28be53
commit da37164630
3 changed files with 84 additions and 0 deletions
+10
View File
@@ -36,6 +36,16 @@ template Strings tokenizeString(std::string_view s, std::string_view separators)
template StringSet tokenizeString(std::string_view s, std::string_view separators);
template std::vector<std::string> tokenizeString(std::string_view s, std::string_view separators);
std::pair<std::string_view, std::optional<std::string_view>>
partitionString(std::string_view s, char separator)
{
auto pos = s.find_first_of(separator);
if (pos == std::string::npos) {
return {s, std::nullopt};
} else {
return {s.substr(0, pos), s.substr(pos + 1)};
}
}
std::string chomp(std::string_view s)
{
+9
View File
@@ -35,6 +35,15 @@ MakeError(FormatError, Error);
*/
template<class C> C tokenizeString(std::string_view s, std::string_view separators = " \t\n\r");
/**
* Returns a pair that partitions the string when the separator is encountered for the first time in the
* string. e.g. `a=b` with separator `=` would split into {a, b} If the string passed does not contain the
* separator, the returned pair will set the second element to nullopt and put the whole string in the first
* element.
*/
std::pair<std::string_view, std::optional<std::string_view>>
partitionString(std::string_view s, char separator);
/**
* Concatenate the given strings with a separator between the
* elements.
+65
View File
@@ -729,6 +729,71 @@ namespace nix {
ASSERT_EQ(tokenizeString<Strings>(s, ","), expected);
}
/* ----------------------------------------------------------------------------
* partitionString
* --------------------------------------------------------------------------*/
TEST(partitionString, emptyString)
{
auto result = partitionString("", '=');
ASSERT_EQ(result.first, "");
ASSERT_FALSE(result.second.has_value());
}
TEST(partitionString, noSeparator)
{
auto result = partitionString("foobar", '=');
ASSERT_EQ(result.first, "foobar");
ASSERT_FALSE(result.second.has_value());
}
TEST(partitionString, separatorInMiddle)
{
auto result = partitionString("a=b", '=');
ASSERT_EQ(result.first, "a");
ASSERT_TRUE(result.second.has_value());
ASSERT_EQ(result.second.value(), "b");
}
TEST(partitionString, separatorAtBeginning)
{
auto result = partitionString("=abc", '=');
ASSERT_EQ(result.first, "");
ASSERT_TRUE(result.second.has_value());
ASSERT_EQ(result.second.value(), "abc");
}
TEST(partitionString, separatorAtEnd)
{
auto result = partitionString("abc=", '=');
ASSERT_EQ(result.first, "abc");
ASSERT_TRUE(result.second.has_value());
ASSERT_EQ(result.second.value(), "");
}
TEST(partitionString, multipleSeparatorsOnlyFirstIsUsed)
{
auto result = partitionString("a=b=c", '=');
ASSERT_EQ(result.first, "a");
ASSERT_TRUE(result.second.has_value());
ASSERT_EQ(result.second.value(), "b=c");
}
TEST(partitionString, differentSeparator)
{
auto result = partitionString("key:value", ':');
ASSERT_EQ(result.first, "key");
ASSERT_TRUE(result.second.has_value());
ASSERT_EQ(result.second.value(), "value");
}
/* ----------------------------------------------------------------------------
* get
* --------------------------------------------------------------------------*/