123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565 |
- //
- // Copyright 2017 The Abseil Authors.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // https://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- // -----------------------------------------------------------------------------
- // File: str_split.h
- // -----------------------------------------------------------------------------
- //
- // This file contains functions for splitting strings. It defines the main
- // `StrSplit()` function, several delimiters for determining the boundaries on
- // which to split the string, and predicates for filtering delimited results.
- // `StrSplit()` adapts the returned collection to the type specified by the
- // caller.
- //
- // Example:
- //
- // // Splits the given string on commas. Returns the results in a
- // // vector of strings.
- // std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
- // // Can also use ","
- // // v[0] == "a", v[1] == "b", v[2] == "c"
- //
- // See StrSplit() below for more information.
- #ifndef ABSL_STRINGS_STR_SPLIT_H_
- #define ABSL_STRINGS_STR_SPLIT_H_
- #include <algorithm>
- #include <cstddef>
- #include <map>
- #include <set>
- #include <string>
- #include <utility>
- #include <vector>
- #include "absl/base/internal/raw_logging.h"
- #include "absl/base/macros.h"
- #include "absl/strings/internal/str_split_internal.h"
- #include "absl/strings/string_view.h"
- #include "absl/strings/strip.h"
- namespace absl {
- ABSL_NAMESPACE_BEGIN
- //------------------------------------------------------------------------------
- // Delimiters
- //------------------------------------------------------------------------------
- //
- // `StrSplit()` uses delimiters to define the boundaries between elements in the
- // provided input. Several `Delimiter` types are defined below. If a string
- // (`const char*`, `std::string`, or `absl::string_view`) is passed in place of
- // an explicit `Delimiter` object, `StrSplit()` treats it the same way as if it
- // were passed a `ByString` delimiter.
- //
- // A `Delimiter` is an object with a `Find()` function that knows how to find
- // the first occurrence of itself in a given `absl::string_view`.
- //
- // The following `Delimiter` types are available for use within `StrSplit()`:
- //
- // - `ByString` (default for string arguments)
- // - `ByChar` (default for a char argument)
- // - `ByAnyChar`
- // - `ByLength`
- // - `MaxSplits`
- //
- // A Delimiter's `Find()` member function will be passed an input `text` that is
- // to be split and a position (`pos`) to begin searching for the next delimiter
- // in `text`. The returned absl::string_view should refer to the next occurrence
- // (after `pos`) of the represented delimiter; this returned absl::string_view
- // represents the next location where the input `text` should be broken.
- //
- // The returned absl::string_view may be zero-length if the Delimiter does not
- // represent a part of the string (e.g., a fixed-length delimiter). If no
- // delimiter is found in the input `text`, a zero-length absl::string_view
- // referring to `text.end()` should be returned (e.g.,
- // `text.substr(text.size())`). It is important that the returned
- // absl::string_view always be within the bounds of the input `text` given as an
- // argument--it must not refer to a string that is physically located outside of
- // the given string.
- //
- // The following example is a simple Delimiter object that is created with a
- // single char and will look for that char in the text passed to the `Find()`
- // function:
- //
- // struct SimpleDelimiter {
- // const char c_;
- // explicit SimpleDelimiter(char c) : c_(c) {}
- // absl::string_view Find(absl::string_view text, size_t pos) {
- // auto found = text.find(c_, pos);
- // if (found == absl::string_view::npos)
- // return text.substr(text.size());
- //
- // return text.substr(found, 1);
- // }
- // };
- // ByString
- //
- // A sub-string delimiter. If `StrSplit()` is passed a string in place of a
- // `Delimiter` object, the string will be implicitly converted into a
- // `ByString` delimiter.
- //
- // Example:
- //
- // // Because a string literal is converted to an `absl::ByString`,
- // // the following two splits are equivalent.
- //
- // std::vector<std::string> v1 = absl::StrSplit("a, b, c", ", ");
- //
- // using absl::ByString;
- // std::vector<std::string> v2 = absl::StrSplit("a, b, c",
- // ByString(", "));
- // // v[0] == "a", v[1] == "b", v[2] == "c"
- class ByString {
- public:
- explicit ByString(absl::string_view sp);
- absl::string_view Find(absl::string_view text, size_t pos) const;
- private:
- const std::string delimiter_;
- };
- // ByAsciiWhitespace
- //
- // A sub-string delimiter that splits by ASCII whitespace
- // (space, tab, vertical tab, formfeed, linefeed, or carriage return).
- // Note: you probably want to use absl::SkipEmpty() as well!
- //
- // This class is equivalent to ByAnyChar with ASCII whitespace chars.
- //
- // Example:
- //
- // std::vector<std::string> v = absl::StrSplit(
- // "a b\tc\n d \n", absl::ByAsciiWhitespace(), absl::SkipEmpty());
- // // v[0] == "a", v[1] == "b", v[2] == "c", v[3] == "d"
- class ByAsciiWhitespace {
- public:
- absl::string_view Find(absl::string_view text, size_t pos) const;
- };
- // ByChar
- //
- // A single character delimiter. `ByChar` is functionally equivalent to a
- // 1-char string within a `ByString` delimiter, but slightly more efficient.
- //
- // Example:
- //
- // // Because a char literal is converted to a absl::ByChar,
- // // the following two splits are equivalent.
- // std::vector<std::string> v1 = absl::StrSplit("a,b,c", ',');
- // using absl::ByChar;
- // std::vector<std::string> v2 = absl::StrSplit("a,b,c", ByChar(','));
- // // v[0] == "a", v[1] == "b", v[2] == "c"
- //
- // `ByChar` is also the default delimiter if a single character is given
- // as the delimiter to `StrSplit()`. For example, the following calls are
- // equivalent:
- //
- // std::vector<std::string> v = absl::StrSplit("a-b", '-');
- //
- // using absl::ByChar;
- // std::vector<std::string> v = absl::StrSplit("a-b", ByChar('-'));
- //
- class ByChar {
- public:
- explicit ByChar(char c) : c_(c) {}
- absl::string_view Find(absl::string_view text, size_t pos) const;
- private:
- char c_;
- };
- // ByAnyChar
- //
- // A delimiter that will match any of the given byte-sized characters within
- // its provided string.
- //
- // Note: this delimiter works with single-byte string data, but does not work
- // with variable-width encodings, such as UTF-8.
- //
- // Example:
- //
- // using absl::ByAnyChar;
- // std::vector<std::string> v = absl::StrSplit("a,b=c", ByAnyChar(",="));
- // // v[0] == "a", v[1] == "b", v[2] == "c"
- //
- // If `ByAnyChar` is given the empty string, it behaves exactly like
- // `ByString` and matches each individual character in the input string.
- //
- class ByAnyChar {
- public:
- explicit ByAnyChar(absl::string_view sp);
- absl::string_view Find(absl::string_view text, size_t pos) const;
- private:
- const std::string delimiters_;
- };
- // ByLength
- //
- // A delimiter for splitting into equal-length strings. The length argument to
- // the constructor must be greater than 0.
- //
- // Note: this delimiter works with single-byte string data, but does not work
- // with variable-width encodings, such as UTF-8.
- //
- // Example:
- //
- // using absl::ByLength;
- // std::vector<std::string> v = absl::StrSplit("123456789", ByLength(3));
- // // v[0] == "123", v[1] == "456", v[2] == "789"
- //
- // Note that the string does not have to be a multiple of the fixed split
- // length. In such a case, the last substring will be shorter.
- //
- // using absl::ByLength;
- // std::vector<std::string> v = absl::StrSplit("12345", ByLength(2));
- //
- // // v[0] == "12", v[1] == "34", v[2] == "5"
- class ByLength {
- public:
- explicit ByLength(ptrdiff_t length);
- absl::string_view Find(absl::string_view text, size_t pos) const;
- private:
- const ptrdiff_t length_;
- };
- namespace strings_internal {
- // A traits-like metafunction for selecting the default Delimiter object type
- // for a particular Delimiter type. The base case simply exposes type Delimiter
- // itself as the delimiter's Type. However, there are specializations for
- // string-like objects that map them to the ByString delimiter object.
- // This allows functions like absl::StrSplit() and absl::MaxSplits() to accept
- // string-like objects (e.g., ',') as delimiter arguments but they will be
- // treated as if a ByString delimiter was given.
- template <typename Delimiter>
- struct SelectDelimiter {
- using type = Delimiter;
- };
- template <>
- struct SelectDelimiter<char> {
- using type = ByChar;
- };
- template <>
- struct SelectDelimiter<char*> {
- using type = ByString;
- };
- template <>
- struct SelectDelimiter<const char*> {
- using type = ByString;
- };
- template <>
- struct SelectDelimiter<absl::string_view> {
- using type = ByString;
- };
- template <>
- struct SelectDelimiter<std::string> {
- using type = ByString;
- };
- // Wraps another delimiter and sets a max number of matches for that delimiter.
- template <typename Delimiter>
- class MaxSplitsImpl {
- public:
- MaxSplitsImpl(Delimiter delimiter, int limit)
- : delimiter_(delimiter), limit_(limit), count_(0) {}
- absl::string_view Find(absl::string_view text, size_t pos) {
- if (count_++ == limit_) {
- return absl::string_view(text.data() + text.size(),
- 0); // No more matches.
- }
- return delimiter_.Find(text, pos);
- }
- private:
- Delimiter delimiter_;
- const int limit_;
- int count_;
- };
- } // namespace strings_internal
- // MaxSplits()
- //
- // A delimiter that limits the number of matches which can occur to the passed
- // `limit`. The last element in the returned collection will contain all
- // remaining unsplit pieces, which may contain instances of the delimiter.
- // The collection will contain at most `limit` + 1 elements.
- // Example:
- //
- // using absl::MaxSplits;
- // std::vector<std::string> v = absl::StrSplit("a,b,c", MaxSplits(',', 1));
- //
- // // v[0] == "a", v[1] == "b,c"
- template <typename Delimiter>
- inline strings_internal::MaxSplitsImpl<
- typename strings_internal::SelectDelimiter<Delimiter>::type>
- MaxSplits(Delimiter delimiter, int limit) {
- typedef
- typename strings_internal::SelectDelimiter<Delimiter>::type DelimiterType;
- return strings_internal::MaxSplitsImpl<DelimiterType>(
- DelimiterType(delimiter), limit);
- }
- //------------------------------------------------------------------------------
- // Predicates
- //------------------------------------------------------------------------------
- //
- // Predicates filter the results of a `StrSplit()` by determining whether or not
- // a resultant element is included in the result set. A predicate may be passed
- // as an optional third argument to the `StrSplit()` function.
- //
- // Predicates are unary functions (or functors) that take a single
- // `absl::string_view` argument and return a bool indicating whether the
- // argument should be included (`true`) or excluded (`false`).
- //
- // Predicates are useful when filtering out empty substrings. By default, empty
- // substrings may be returned by `StrSplit()`, which is similar to the way split
- // functions work in other programming languages.
- // AllowEmpty()
- //
- // Always returns `true`, indicating that all strings--including empty
- // strings--should be included in the split output. This predicate is not
- // strictly needed because this is the default behavior of `StrSplit()`;
- // however, it might be useful at some call sites to make the intent explicit.
- //
- // Example:
- //
- // std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', AllowEmpty());
- //
- // // v[0] == " a ", v[1] == " ", v[2] == "", v[3] = "b", v[4] == ""
- struct AllowEmpty {
- bool operator()(absl::string_view) const { return true; }
- };
- // SkipEmpty()
- //
- // Returns `false` if the given `absl::string_view` is empty, indicating that
- // `StrSplit()` should omit the empty string.
- //
- // Example:
- //
- // std::vector<std::string> v = absl::StrSplit(",a,,b,", ',', SkipEmpty());
- //
- // // v[0] == "a", v[1] == "b"
- //
- // Note: `SkipEmpty()` does not consider a string containing only whitespace
- // to be empty. To skip such whitespace as well, use the `SkipWhitespace()`
- // predicate.
- struct SkipEmpty {
- bool operator()(absl::string_view sp) const { return !sp.empty(); }
- };
- // SkipWhitespace()
- //
- // Returns `false` if the given `absl::string_view` is empty *or* contains only
- // whitespace, indicating that `StrSplit()` should omit the string.
- //
- // Example:
- //
- // std::vector<std::string> v = absl::StrSplit(" a , ,,b,",
- // ',', SkipWhitespace());
- // // v[0] == " a ", v[1] == "b"
- //
- // // SkipEmpty() would return whitespace elements
- // std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', SkipEmpty());
- // // v[0] == " a ", v[1] == " ", v[2] == "b"
- struct SkipWhitespace {
- bool operator()(absl::string_view sp) const {
- sp = absl::StripAsciiWhitespace(sp);
- return !sp.empty();
- }
- };
- template <typename T>
- using EnableSplitIfString =
- typename std::enable_if<std::is_same<T, std::string>::value ||
- std::is_same<T, const std::string>::value,
- int>::type;
- //------------------------------------------------------------------------------
- // StrSplit()
- //------------------------------------------------------------------------------
- // StrSplit()
- //
- // Splits a given string based on the provided `Delimiter` object, returning the
- // elements within the type specified by the caller. Optionally, you may pass a
- // `Predicate` to `StrSplit()` indicating whether to include or exclude the
- // resulting element within the final result set. (See the overviews for
- // Delimiters and Predicates above.)
- //
- // Example:
- //
- // std::vector<std::string> v = absl::StrSplit("a,b,c,d", ',');
- // // v[0] == "a", v[1] == "b", v[2] == "c", v[3] == "d"
- //
- // You can also provide an explicit `Delimiter` object:
- //
- // Example:
- //
- // using absl::ByAnyChar;
- // std::vector<std::string> v = absl::StrSplit("a,b=c", ByAnyChar(",="));
- // // v[0] == "a", v[1] == "b", v[2] == "c"
- //
- // See above for more information on delimiters.
- //
- // By default, empty strings are included in the result set. You can optionally
- // include a third `Predicate` argument to apply a test for whether the
- // resultant element should be included in the result set:
- //
- // Example:
- //
- // std::vector<std::string> v = absl::StrSplit(" a , ,,b,",
- // ',', SkipWhitespace());
- // // v[0] == " a ", v[1] == "b"
- //
- // See above for more information on predicates.
- //
- //------------------------------------------------------------------------------
- // StrSplit() Return Types
- //------------------------------------------------------------------------------
- //
- // The `StrSplit()` function adapts the returned collection to the collection
- // specified by the caller (e.g. `std::vector` above). The returned collections
- // may contain `std::string`, `absl::string_view` (in which case the original
- // string being split must ensure that it outlives the collection), or any
- // object that can be explicitly created from an `absl::string_view`. This
- // behavior works for:
- //
- // 1) All standard STL containers including `std::vector`, `std::list`,
- // `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap`
- // 2) `std::pair` (which is not actually a container). See below.
- //
- // Example:
- //
- // // The results are returned as `absl::string_view` objects. Note that we
- // // have to ensure that the input string outlives any results.
- // std::vector<absl::string_view> v = absl::StrSplit("a,b,c", ',');
- //
- // // Stores results in a std::set<std::string>, which also performs
- // // de-duplication and orders the elements in ascending order.
- // std::set<std::string> a = absl::StrSplit("b,a,c,a,b", ',');
- // // a[0] == "a", a[1] == "b", a[2] == "c"
- //
- // // `StrSplit()` can be used within a range-based for loop, in which case
- // // each element will be of type `absl::string_view`.
- // std::vector<std::string> v;
- // for (const auto sv : absl::StrSplit("a,b,c", ',')) {
- // if (sv != "b") v.emplace_back(sv);
- // }
- // // v[0] == "a", v[1] == "c"
- //
- // // Stores results in a map. The map implementation assumes that the input
- // // is provided as a series of key/value pairs. For example, the 0th element
- // // resulting from the split will be stored as a key to the 1st element. If
- // // an odd number of elements are resolved, the last element is paired with
- // // a default-constructed value (e.g., empty string).
- // std::map<std::string, std::string> m = absl::StrSplit("a,b,c", ',');
- // // m["a"] == "b", m["c"] == "" // last component value equals ""
- //
- // Splitting to `std::pair` is an interesting case because it can hold only two
- // elements and is not a collection type. When splitting to a `std::pair` the
- // first two split strings become the `std::pair` `.first` and `.second`
- // members, respectively. The remaining split substrings are discarded. If there
- // are less than two split substrings, the empty string is used for the
- // corresponding `std::pair` member.
- //
- // Example:
- //
- // // Stores first two split strings as the members in a std::pair.
- // std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
- // // p.first == "a", p.second == "b" // "c" is omitted.
- //
- // The `StrSplit()` function can be used multiple times to perform more
- // complicated splitting logic, such as intelligently parsing key-value pairs.
- //
- // Example:
- //
- // // The input string "a=b=c,d=e,f=,g" becomes
- // // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" }
- // std::map<std::string, std::string> m;
- // for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) {
- // m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1)));
- // }
- // EXPECT_EQ("b=c", m.find("a")->second);
- // EXPECT_EQ("e", m.find("d")->second);
- // EXPECT_EQ("", m.find("f")->second);
- // EXPECT_EQ("", m.find("g")->second);
- //
- // WARNING: Due to a legacy bug that is maintained for backward compatibility,
- // splitting the following empty string_views produces different results:
- //
- // absl::StrSplit(absl::string_view(""), '-'); // {""}
- // absl::StrSplit(absl::string_view(), '-'); // {}, but should be {""}
- //
- // Try not to depend on this distinction because the bug may one day be fixed.
- template <typename Delimiter>
- strings_internal::Splitter<
- typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty,
- absl::string_view>
- StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) {
- using DelimiterType =
- typename strings_internal::SelectDelimiter<Delimiter>::type;
- return strings_internal::Splitter<DelimiterType, AllowEmpty,
- absl::string_view>(
- text.value(), DelimiterType(d), AllowEmpty());
- }
- template <typename Delimiter, typename StringType,
- EnableSplitIfString<StringType> = 0>
- strings_internal::Splitter<
- typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty,
- std::string>
- StrSplit(StringType&& text, Delimiter d) {
- using DelimiterType =
- typename strings_internal::SelectDelimiter<Delimiter>::type;
- return strings_internal::Splitter<DelimiterType, AllowEmpty, std::string>(
- std::move(text), DelimiterType(d), AllowEmpty());
- }
- template <typename Delimiter, typename Predicate>
- strings_internal::Splitter<
- typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate,
- absl::string_view>
- StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d,
- Predicate p) {
- using DelimiterType =
- typename strings_internal::SelectDelimiter<Delimiter>::type;
- return strings_internal::Splitter<DelimiterType, Predicate,
- absl::string_view>(
- text.value(), DelimiterType(std::move(d)), std::move(p));
- }
- template <typename Delimiter, typename Predicate, typename StringType,
- EnableSplitIfString<StringType> = 0>
- strings_internal::Splitter<
- typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate,
- std::string>
- StrSplit(StringType&& text, Delimiter d, Predicate p) {
- using DelimiterType =
- typename strings_internal::SelectDelimiter<Delimiter>::type;
- return strings_internal::Splitter<DelimiterType, Predicate, std::string>(
- std::move(text), DelimiterType(d), std::move(p));
- }
- ABSL_NAMESPACE_END
- } // namespace absl
- #endif // ABSL_STRINGS_STR_SPLIT_H_
|