Skip to content

Commit a385d9b

Browse files
author
thk123
committed
Allowed split_string to be used on whitespace if not also trying to strip
Also improved comments (and moved to doxygen) as I assumed strip would remove whitespace from throughout the string but actually only does the final string Replace asserts in string utils Adding tests for behaviour with whitespace delimiter
1 parent 145f474 commit a385d9b

File tree

3 files changed

+109
-7
lines changed

3 files changed

+109
-7
lines changed

src/util/string_utils.cpp

+27-4
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ Author: Daniel Poetzl
77
\*******************************************************************/
88

99
#include "string_utils.h"
10+
#include "invariant.h"
1011

1112
#include <cassert>
1213
#include <cctype>
1314
#include <algorithm>
1415

16+
/// Remove all whitespace characters from either end of a string. Whitespace
17+
/// in the middle of the string is left unchanged
18+
/// \param s: the string to strip
19+
/// \return The stripped string
1520
std::string strip_string(const std::string &s)
1621
{
1722
auto pred=[](char c){ return std::isspace(c); };
@@ -30,15 +35,29 @@ std::string strip_string(const std::string &s)
3035
return s.substr(i, (j-i+1));
3136
}
3237

38+
/// Given a string s, split into a sequence of substrings when separated by
39+
/// specified delimiter.
40+
/// \param s: The string to split up
41+
/// \param delim: The character to use as the delimiter
42+
/// \param [out] result: The sub strings. Must be empty.
43+
/// \param strip: If true, strip_string will be used on each element, removing
44+
/// whitespace from the beginning and end of each element
45+
/// \param remove_empty: If true, all empty-string elements will be removed.
46+
/// This is applied after strip so whitespace only elements will be removed if
47+
/// both are set to true
3348
void split_string(
3449
const std::string &s,
3550
char delim,
3651
std::vector<std::string> &result,
3752
bool strip,
3853
bool remove_empty)
3954
{
40-
assert(result.empty());
41-
assert(!std::isspace(delim));
55+
PRECONDITION(result.empty());
56+
if(strip && std::isspace(delim))
57+
{
58+
throw std::invalid_argument(
59+
"delim can't be a space character if using strip");
60+
}
4261

4362
if(s.empty())
4463
{
@@ -47,7 +66,7 @@ void split_string(
4766
}
4867

4968
std::string::size_type n=s.length();
50-
assert(n>0);
69+
INVARIANT(n > 0, "Empty string case should already be handled");
5170

5271
std::string::size_type start=0;
5372
std::string::size_type i;
@@ -87,7 +106,11 @@ void split_string(
87106
std::string &right,
88107
bool strip)
89108
{
90-
assert(!std::isspace(delim));
109+
if(strip && std::isspace(delim))
110+
{
111+
throw std::invalid_argument(
112+
"delim can't be a space character if using strip");
113+
}
91114

92115
std::vector<std::string> result;
93116

src/util/string_utils.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ std::string strip_string(const std::string &s);
1818

1919
void split_string(
2020
const std::string &s,
21-
char delim, // must not be a whitespace character
21+
char delim,
2222
std::vector<std::string> &result,
23-
bool strip=false, // strip whitespace from elements
24-
bool remove_empty=false); // remove empty elements
23+
bool strip = false,
24+
bool remove_empty = false);
2525

2626
void split_string(
2727
const std::string &s,

unit/util/string_utils/split_string.cpp

+79
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,58 @@ SCENARIO("split_string", "[core][utils][string_utils][split_string]")
134134
run_on_all_variants(string, ',', expected_results);
135135
}
136136
}
137+
GIVEN("A whitespace delimter")
138+
{
139+
std::string string = "a\nb\nc";
140+
const char delimiter = '\n';
141+
142+
WHEN("Not stripping, not removing empty")
143+
{
144+
std::vector<std::string> result;
145+
split_string(string, delimiter, result, false, false);
146+
147+
THEN("Should get expected vector")
148+
{
149+
std::vector<std::string> expected_result = {"a", "b", "c"};
150+
REQUIRE_THAT(
151+
result,
152+
Catch::Matchers::Vector::EqualsMatcher<std::string>{expected_result});
153+
}
154+
}
155+
WHEN("Not stripping, removing empty")
156+
{
157+
std::vector<std::string> result;
158+
split_string(string, delimiter, result, false, true);
159+
160+
THEN("Should get expected vector")
161+
{
162+
std::vector<std::string> expected_result = {"a", "b", "c"};
163+
REQUIRE_THAT(
164+
result,
165+
Catch::Matchers::Vector::EqualsMatcher<std::string>{expected_result});
166+
}
167+
}
168+
WHEN("Stripping, not removing empty")
169+
{
170+
std::vector<std::string> result;
171+
THEN("Should throw an exception")
172+
{
173+
REQUIRE_THROWS_AS(
174+
split_string(string, delimiter, result, true, false),
175+
std::invalid_argument);
176+
}
177+
}
178+
WHEN("Stripping and removing empty")
179+
{
180+
std::vector<std::string> result;
181+
THEN("Should throw an exception")
182+
{
183+
REQUIRE_THROWS_AS(
184+
split_string(string, delimiter, result, true, true),
185+
std::invalid_argument);
186+
}
187+
}
188+
}
137189
}
138190

139191
SCENARIO("split_string into two", "[core][utils][string_utils][split_string]")
@@ -155,4 +207,31 @@ SCENARIO("split_string into two", "[core][utils][string_utils][split_string]")
155207
}
156208
}
157209
}
210+
GIVEN("A string and a whitespace delimiter")
211+
{
212+
std::string string = "a\nb";
213+
const char delimiter = '\n';
214+
215+
WHEN("Splitting in two and not stripping")
216+
{
217+
std::string s1;
218+
std::string s2;
219+
split_string(string, delimiter, s1, s2, false);
220+
THEN("The string should be split")
221+
{
222+
REQUIRE(s1 == "a");
223+
REQUIRE(s2 == "b");
224+
}
225+
}
226+
WHEN("Splitting in two and stripping")
227+
{
228+
THEN("An invalid argument exception should be raised")
229+
{
230+
std::string s1;
231+
std::string s2;
232+
REQUIRE_THROWS_AS(
233+
split_string(string, delimiter, s1, s2, true), std::invalid_argument);
234+
}
235+
}
236+
}
158237
}

0 commit comments

Comments
 (0)