From 47328c96d91ca71b57b8976df2df1fe51579a955 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Thu, 19 Mar 2015 13:24:26 -0700 Subject: Update string Split API. Return a new vector rather than appending to the parameter. Delimiters are also a string rather than a character. Split on any character in the string. Change-Id: I039b332ace5578590df9e7ca0e8fa3db28db30a3 --- base/include/base/strings.h | 13 +++++++++---- base/logging.cpp | 3 +-- base/strings.cpp | 40 ++++++++++++++++++++++++++-------------- base/strings_test.cpp | 35 +++++++++++++++++++++++++++-------- 4 files changed, 63 insertions(+), 28 deletions(-) (limited to 'base') diff --git a/base/include/base/strings.h b/base/include/base/strings.h index 5ddfbbd..ab56aad 100644 --- a/base/include/base/strings.h +++ b/base/include/base/strings.h @@ -23,10 +23,15 @@ namespace android { namespace base { -// Splits a string using the given separator character into a vector of strings. -// Empty strings will be omitted. -void Split(const std::string& s, char separator, - std::vector* result); +// Splits a string into a vector of strings. +// +// The string is split at each occurence of a character in delimiters. +// +// Empty splits will be omitted. I.e. Split("a,,b", ",") -> {"a", "b"} +// +// The empty string is not a valid delimiter list. +std::vector Split(const std::string& s, + const std::string& delimiters); // Trims whitespace off both ends of the given string. std::string Trim(const std::string& s); diff --git a/base/logging.cpp b/base/logging.cpp index 3d6c0c2..5b70c7d 100644 --- a/base/logging.cpp +++ b/base/logging.cpp @@ -108,8 +108,7 @@ void InitLogging(char* argv[]) { return; } - std::vector specs; - Split(tags, ' ', &specs); + std::vector specs = Split(tags, " "); for (size_t i = 0; i < specs.size(); ++i) { // "tag-pattern:[vdiwefs]" std::string spec(specs[i]); diff --git a/base/strings.cpp b/base/strings.cpp index 224a46f..5f7eccc 100644 --- a/base/strings.cpp +++ b/base/strings.cpp @@ -16,27 +16,39 @@ #include "base/strings.h" +#include + #include #include namespace android { namespace base { -void Split(const std::string& s, char separator, - std::vector* result) { - const char* p = s.data(); - const char* end = p + s.size(); - while (p != end) { - if (*p == separator) { - ++p; - } else { - const char* start = p; - while (++p != end && *p != separator) { - // Skip to the next occurrence of the separator. - } - result->push_back(std::string(start, p - start)); - } +#define CHECK_NE(a, b) \ + if ((a) == (b)) abort(); + +std::vector Split(const std::string& s, + const std::string& delimiters) { + CHECK_NE(delimiters.size(), 0U); + + std::vector split; + if (s.size() == 0) { + // Split("", d) returns {} rather than {""}. + return split; } + + size_t base = 0; + size_t found; + do { + found = s.find_first_of(delimiters, base); + if (found != base) { + split.push_back(s.substr(base, found - base)); + } + + base = found + 1; + } while (found != s.npos); + + return split; } std::string Trim(const std::string& s) { diff --git a/base/strings_test.cpp b/base/strings_test.cpp index 824598d..1bf07a1 100644 --- a/base/strings_test.cpp +++ b/base/strings_test.cpp @@ -22,21 +22,18 @@ #include TEST(strings, split_empty) { - std::vector parts; - android::base::Split("", '\0', &parts); + std::vector parts = android::base::Split("", ","); ASSERT_EQ(0U, parts.size()); } TEST(strings, split_single) { - std::vector parts; - android::base::Split("foo", ',', &parts); + std::vector parts = android::base::Split("foo", ","); ASSERT_EQ(1U, parts.size()); ASSERT_EQ("foo", parts[0]); } TEST(strings, split_simple) { - std::vector parts; - android::base::Split("foo,bar,baz", ',', &parts); + std::vector parts = android::base::Split("foo,bar,baz", ","); ASSERT_EQ(3U, parts.size()); ASSERT_EQ("foo", parts[0]); ASSERT_EQ("bar", parts[1]); @@ -44,8 +41,30 @@ TEST(strings, split_simple) { } TEST(strings, split_with_empty_part) { - std::vector parts; - android::base::Split("foo,,bar", ',', &parts); + std::vector parts = android::base::Split("foo,,bar", ","); + ASSERT_EQ(2U, parts.size()); + ASSERT_EQ("foo", parts[0]); + ASSERT_EQ("bar", parts[1]); +} + +TEST(strings, split_null_char) { + std::vector parts = + android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1)); + ASSERT_EQ(2U, parts.size()); + ASSERT_EQ("foo", parts[0]); + ASSERT_EQ("bar", parts[1]); +} + +TEST(strings, split_any) { + std::vector parts = android::base::Split("foo:bar,baz", ",:"); + ASSERT_EQ(3U, parts.size()); + ASSERT_EQ("foo", parts[0]); + ASSERT_EQ("bar", parts[1]); + ASSERT_EQ("baz", parts[2]); +} + +TEST(strings, split_any_with_empty_part) { + std::vector parts = android::base::Split("foo:,bar", ",:"); ASSERT_EQ(2U, parts.size()); ASSERT_EQ("foo", parts[0]); ASSERT_EQ("bar", parts[1]); -- cgit v1.1