Include empty tokens when splitting if necessary (#1893)

Fixes #1881
This commit is contained in:
Jérôme BOULMIER 2019-11-21 22:26:53 +01:00 committed by Patrick Ziegler
parent 8d3dedc2bd
commit e5783d4113
7 changed files with 71 additions and 40 deletions

View File

@ -88,8 +88,8 @@ namespace string_util {
string utf8_truncate(string&& value, size_t len);
string join(const vector<string>& strs, const string& delim);
vector<string>& split_into(const string& s, char delim, vector<string>& container);
vector<string> split(const string& s, char delim);
std::vector<std::string> tokenize(const string& str, char delimiters);
size_t find_nth(const string& haystack, size_t pos, const string& needle, size_t nth);

View File

@ -131,7 +131,7 @@ namespace modules {
m_icons->add(DEFAULT_ICON, factory_util::shared<label>(m_conf.get(name(), DEFAULT_ICON, ""s)));
for (const auto& workspace : m_conf.get_list<string>(name(), "ws-icon", {})) {
auto vec = string_util::split(workspace, ';');
auto vec = string_util::tokenize(workspace, ';');
if (vec.size() == 2) {
m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
}
@ -224,11 +224,7 @@ namespace modules {
size_t workspace_n{0U};
for (auto&& tag : string_util::split(data, ':')) {
if (tag.empty()) {
continue;
}
auto value = !tag.empty() ? tag.substr(1) : "";
auto value = tag.substr(1);
auto mode_flag = mode::NONE;
unsigned int workspace_mask{0U};

View File

@ -58,7 +58,7 @@ namespace modules {
m_icons->add(DEFAULT_WS_ICON, factory_util::shared<label>(m_conf.get(name(), DEFAULT_WS_ICON, ""s)));
for (const auto& workspace : m_conf.get_list<string>(name(), "ws-icon", {})) {
auto vec = string_util::split(workspace, ';');
auto vec = string_util::tokenize(workspace, ';');
if (vec.size() == 2) {
m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
}

View File

@ -49,7 +49,7 @@ namespace modules {
m_layout_icons->add(DEFAULT_LAYOUT_ICON, load_optional_label(m_conf, name(), DEFAULT_LAYOUT_ICON, ""s));
for (const auto& it : m_conf.get_list<string>(name(), "layout-icon", {})) {
auto vec = string_util::split(it, ';');
auto vec = string_util::tokenize(it, ';');
if (vec.size() == 2) {
m_layout_icons->add(vec[0], factory_util::shared<label>(vec[1]));
}
@ -80,7 +80,7 @@ namespace modules {
m_indicator_icons_off = factory_util::shared<iconset>();
m_indicator_icons_on = factory_util::shared<iconset>();
auto icon_pair = string_util::split(m_conf.get(name(), DEFAULT_INDICATOR_ICON, ""s), ';');
auto icon_pair = string_util::tokenize(m_conf.get(name(), DEFAULT_INDICATOR_ICON, ""s), ';');
if(icon_pair.size() == 2) {
m_indicator_icons_off->add(DEFAULT_INDICATOR_ICON, factory_util::shared<label>(icon_pair[0]));
m_indicator_icons_on->add(DEFAULT_INDICATOR_ICON, factory_util::shared<label>(icon_pair[1]));
@ -90,7 +90,7 @@ namespace modules {
}
for (const auto& it : m_conf.get_list<string>(name(), "indicator-icon", {})) {
auto icon_triple = string_util::split(it, ';');
auto icon_triple = string_util::tokenize(it, ';');
if (icon_triple.size() == 3) {
auto const indicator_str = string_util::lower(icon_triple[0]);
m_indicator_icons_off->add(indicator_str, factory_util::shared<label>(icon_triple[1]));

View File

@ -72,7 +72,7 @@ namespace modules {
m_icons->add(DEFAULT_ICON, factory_util::shared<label>(m_conf.get(name(), DEFAULT_ICON, ""s)));
for (const auto& workspace : m_conf.get_list<string>(name(), "icon", {})) {
auto vec = string_util::split(workspace, ';');
auto vec = string_util::tokenize(workspace, ';');
if (vec.size() == 2) {
m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
}

View File

@ -222,27 +222,42 @@ namespace string_util {
}
/**
* Explode string by delim into container
*/
vector<string>& split_into(const string& s, char delim, vector<string>& container) {
string str;
std::stringstream buffer(s);
while (getline(buffer, str, delim)) {
container.emplace_back(str);
}
return container;
}
/**
* Explode string by delim
* Explode string by delim, ignore empty tokens
*/
vector<string> split(const string& s, char delim) {
vector<string> vec;
return split_into(s, delim, vec);
std::string::size_type pos = 0;
std::vector<std::string> result;
while ((pos = s.find_first_not_of(delim, pos)) != std::string::npos) {
auto nextpos = s.find_first_of(delim, pos);
result.emplace_back(s.substr(pos, nextpos - pos));
pos = nextpos;
}
return result;
}
/**
* Find the nth occurence of needle in haystack starting from pos
* Explode string by delim, include empty tokens
*/
std::vector<std::string> tokenize(const string& str, char delimiters) {
std::vector<std::string> tokens;
std::string::size_type lastPos = 0;
auto pos = str.find_first_of(delimiters, lastPos);
while (pos != std::string::npos && lastPos != std::string::npos) {
tokens.emplace_back(str.substr(lastPos, pos - lastPos));
lastPos = pos + 1;
pos = str.find_first_of(delimiters, lastPos);
}
tokens.emplace_back(str.substr(lastPos, pos - lastPos));
return tokens;
}
/**
* Find the nth occurrence of needle in haystack starting from pos
*/
size_t find_nth(const string& haystack, size_t pos, const string& needle, size_t nth) {
size_t found_pos = haystack.find(needle, pos);

View File

@ -64,20 +64,40 @@ TEST(String, join) {
EXPECT_EQ("A, B, C", string_util::join({"A", "B", "C"}, ", "));
}
TEST(String, splitInto) {
vector<string> strings;
string_util::split_into("A,B,C", ',', strings);
EXPECT_EQ(3, strings.size());
EXPECT_EQ("A", strings[0]);
EXPECT_EQ("C", strings[2]);
TEST(String, split) {
{
vector<string> strings = string_util::split("A,B,C", ',');
EXPECT_EQ(3, strings.size());
EXPECT_EQ("A", strings[0]);
EXPECT_EQ("B", strings[1]);
EXPECT_EQ("C", strings[2]);
}
{
vector<string> strings = string_util::split(",A,,B,,C,", ',');
EXPECT_EQ(3, strings.size());
EXPECT_EQ("A", strings[0]);
EXPECT_EQ("B", strings[1]);
EXPECT_EQ("C", strings[2]);
}
}
TEST(String, split) {
vector<string> strings{"foo", "bar"};
vector<string> result{string_util::split("foo,bar", ',')};
EXPECT_EQ(strings.size(), result.size());
EXPECT_EQ(strings[0], result[0]);
EXPECT_EQ("bar", result[1]);
TEST(String, tokenize) {
{
vector<string> strings = string_util::tokenize("A,B,C", ',');
EXPECT_EQ(3, strings.size());
EXPECT_EQ("A", strings[0]);
EXPECT_EQ("B", strings[1]);
EXPECT_EQ("C", strings[2]);
}
{
using namespace std::string_literals;
vector<string> strings = string_util::tokenize(",A,,B,,C,", ',');
vector<string> result{""s, "A"s, ""s, "B"s, ""s, "C"s, ""s};
EXPECT_TRUE(strings == result);
}
}
TEST(String, findNth) {