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 utf8_truncate(string&& value, size_t len);
string join(const vector<string>& strs, const string& delim); 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); 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); 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))); 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", {})) { 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) { if (vec.size() == 2) {
m_icons->add(vec[0], factory_util::shared<label>(vec[1])); m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
} }
@ -224,11 +224,7 @@ namespace modules {
size_t workspace_n{0U}; size_t workspace_n{0U};
for (auto&& tag : string_util::split(data, ':')) { for (auto&& tag : string_util::split(data, ':')) {
if (tag.empty()) { auto value = tag.substr(1);
continue;
}
auto value = !tag.empty() ? tag.substr(1) : "";
auto mode_flag = mode::NONE; auto mode_flag = mode::NONE;
unsigned int workspace_mask{0U}; 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))); 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", {})) { 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) { if (vec.size() == 2) {
m_icons->add(vec[0], factory_util::shared<label>(vec[1])); 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)); 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", {})) { 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) { if (vec.size() == 2) {
m_layout_icons->add(vec[0], factory_util::shared<label>(vec[1])); 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_off = factory_util::shared<iconset>();
m_indicator_icons_on = 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) { if(icon_pair.size() == 2) {
m_indicator_icons_off->add(DEFAULT_INDICATOR_ICON, factory_util::shared<label>(icon_pair[0])); 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])); 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", {})) { 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) { if (icon_triple.size() == 3) {
auto const indicator_str = string_util::lower(icon_triple[0]); auto const indicator_str = string_util::lower(icon_triple[0]);
m_indicator_icons_off->add(indicator_str, factory_util::shared<label>(icon_triple[1])); 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))); 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", {})) { 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) { if (vec.size() == 2) {
m_icons->add(vec[0], factory_util::shared<label>(vec[1])); 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 * Explode string by delim, ignore empty tokens
*/
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
*/ */
vector<string> split(const string& s, char delim) { vector<string> split(const string& s, char delim) {
vector<string> vec; std::string::size_type pos = 0;
return split_into(s, delim, vec); 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 find_nth(const string& haystack, size_t pos, const string& needle, size_t nth) {
size_t found_pos = haystack.find(needle, pos); 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"}, ", ")); EXPECT_EQ("A, B, C", string_util::join({"A", "B", "C"}, ", "));
} }
TEST(String, splitInto) { TEST(String, split) {
vector<string> strings; {
string_util::split_into("A,B,C", ',', strings); vector<string> strings = string_util::split("A,B,C", ',');
EXPECT_EQ(3, strings.size()); EXPECT_EQ(3, strings.size());
EXPECT_EQ("A", strings[0]); EXPECT_EQ("A", strings[0]);
EXPECT_EQ("B", strings[1]);
EXPECT_EQ("C", strings[2]); 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) { TEST(String, tokenize) {
vector<string> strings{"foo", "bar"}; {
vector<string> result{string_util::split("foo,bar", ',')}; vector<string> strings = string_util::tokenize("A,B,C", ',');
EXPECT_EQ(strings.size(), result.size()); EXPECT_EQ(3, strings.size());
EXPECT_EQ(strings[0], result[0]); EXPECT_EQ("A", strings[0]);
EXPECT_EQ("bar", result[1]); 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) { TEST(String, findNth) {