1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/strings/string_split.h"
6
7 #include <stddef.h>
8
9 #include <string_view>
10
11 #include "base/logging.h"
12 #include "base/strings/string_split_internal.h"
13 #include "base/strings/string_util.h"
14 #include "base/third_party/icu/icu_utf.h"
15
16 namespace base {
17
18 namespace {
19
20 // Helper for the various *SplitStringOnce implementations. When returning a
21 // pair of `std::string_view`, does not include the character at `position`.
22 std::optional<std::pair<std::string_view, std::string_view>>
SplitStringAtExclusive(std::string_view input,size_t position)23 SplitStringAtExclusive(std::string_view input, size_t position) {
24 if (position == std::string_view::npos) {
25 return std::nullopt;
26 }
27
28 return std::pair(input.substr(0, position), input.substr(position + 1));
29 }
30
AppendStringKeyValue(std::string_view input,char delimiter,StringPairs * result)31 bool AppendStringKeyValue(std::string_view input,
32 char delimiter,
33 StringPairs* result) {
34 // Always append a new item regardless of success (it might be empty). The
35 // below code will copy the strings directly into the result pair.
36 result->resize(result->size() + 1);
37 auto& result_pair = result->back();
38
39 // Find the delimiter.
40 size_t end_key_pos = input.find_first_of(delimiter);
41 if (end_key_pos == std::string::npos) {
42 DVLOG(1) << "cannot find delimiter in: " << input;
43 return false; // No delimiter.
44 }
45 result_pair.first = std::string(input.substr(0, end_key_pos));
46
47 // Find the value string.
48 std::string_view remains =
49 input.substr(end_key_pos, input.size() - end_key_pos);
50 size_t begin_value_pos = remains.find_first_not_of(delimiter);
51 if (begin_value_pos == std::string_view::npos) {
52 DVLOG(1) << "cannot parse value from input: " << input;
53 return false; // No value.
54 }
55
56 result_pair.second = std::string(
57 remains.substr(begin_value_pos, remains.size() - begin_value_pos));
58
59 return true;
60 }
61
62 } // namespace
63
SplitStringOnce(std::string_view input,char separator)64 std::optional<std::pair<std::string_view, std::string_view>> SplitStringOnce(
65 std::string_view input,
66 char separator) {
67 return SplitStringAtExclusive(input, input.find(separator));
68 }
69
SplitStringOnce(std::string_view input,std::string_view separators)70 std::optional<std::pair<std::string_view, std::string_view>> SplitStringOnce(
71 std::string_view input,
72 std::string_view separators) {
73 return SplitStringAtExclusive(input, input.find_first_of(separators));
74 }
75
RSplitStringOnce(std::string_view input,char separator)76 std::optional<std::pair<std::string_view, std::string_view>> RSplitStringOnce(
77 std::string_view input,
78 char separator) {
79 return SplitStringAtExclusive(input, input.rfind(separator));
80 }
81
RSplitStringOnce(std::string_view input,std::string_view separators)82 std::optional<std::pair<std::string_view, std::string_view>> RSplitStringOnce(
83 std::string_view input,
84 std::string_view separators) {
85 return SplitStringAtExclusive(input, input.find_last_of(separators));
86 }
87
SplitString(std::string_view input,std::string_view separators,WhitespaceHandling whitespace,SplitResult result_type)88 std::vector<std::string> SplitString(std::string_view input,
89 std::string_view separators,
90 WhitespaceHandling whitespace,
91 SplitResult result_type) {
92 return internal::SplitStringT<std::string>(input, separators, whitespace,
93 result_type);
94 }
95
SplitString(std::u16string_view input,std::u16string_view separators,WhitespaceHandling whitespace,SplitResult result_type)96 std::vector<std::u16string> SplitString(std::u16string_view input,
97 std::u16string_view separators,
98 WhitespaceHandling whitespace,
99 SplitResult result_type) {
100 return internal::SplitStringT<std::u16string>(input, separators, whitespace,
101 result_type);
102 }
103
SplitStringPiece(std::string_view input,std::string_view separators,WhitespaceHandling whitespace,SplitResult result_type)104 std::vector<std::string_view> SplitStringPiece(std::string_view input,
105 std::string_view separators,
106 WhitespaceHandling whitespace,
107 SplitResult result_type) {
108 return internal::SplitStringT<std::string_view>(input, separators, whitespace,
109 result_type);
110 }
111
SplitStringPiece(std::u16string_view input,std::u16string_view separators,WhitespaceHandling whitespace,SplitResult result_type)112 std::vector<std::u16string_view> SplitStringPiece(
113 std::u16string_view input,
114 std::u16string_view separators,
115 WhitespaceHandling whitespace,
116 SplitResult result_type) {
117 return internal::SplitStringT<std::u16string_view>(input, separators,
118 whitespace, result_type);
119 }
120
SplitStringIntoKeyValuePairs(std::string_view input,char key_value_delimiter,char key_value_pair_delimiter,StringPairs * key_value_pairs)121 bool SplitStringIntoKeyValuePairs(std::string_view input,
122 char key_value_delimiter,
123 char key_value_pair_delimiter,
124 StringPairs* key_value_pairs) {
125 return SplitStringIntoKeyValuePairsUsingSubstr(
126 input, key_value_delimiter,
127 std::string_view(&key_value_pair_delimiter, 1), key_value_pairs);
128 }
129
SplitStringIntoKeyValuePairsUsingSubstr(std::string_view input,char key_value_delimiter,std::string_view key_value_pair_delimiter,StringPairs * key_value_pairs)130 bool SplitStringIntoKeyValuePairsUsingSubstr(
131 std::string_view input,
132 char key_value_delimiter,
133 std::string_view key_value_pair_delimiter,
134 StringPairs* key_value_pairs) {
135 key_value_pairs->clear();
136
137 std::vector<std::string_view> pairs = SplitStringPieceUsingSubstr(
138 input, key_value_pair_delimiter, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
139 key_value_pairs->reserve(pairs.size());
140
141 bool success = true;
142 for (std::string_view pair : pairs) {
143 if (!AppendStringKeyValue(pair, key_value_delimiter, key_value_pairs)) {
144 // Don't return here, to allow for pairs without associated
145 // value or key; just record that the split failed.
146 success = false;
147 }
148 }
149 return success;
150 }
151
SplitStringUsingSubstr(std::u16string_view input,std::u16string_view delimiter,WhitespaceHandling whitespace,SplitResult result_type)152 std::vector<std::u16string> SplitStringUsingSubstr(
153 std::u16string_view input,
154 std::u16string_view delimiter,
155 WhitespaceHandling whitespace,
156 SplitResult result_type) {
157 return internal::SplitStringUsingSubstrT<std::u16string>(
158 input, delimiter, whitespace, result_type);
159 }
160
SplitStringUsingSubstr(std::string_view input,std::string_view delimiter,WhitespaceHandling whitespace,SplitResult result_type)161 std::vector<std::string> SplitStringUsingSubstr(std::string_view input,
162 std::string_view delimiter,
163 WhitespaceHandling whitespace,
164 SplitResult result_type) {
165 return internal::SplitStringUsingSubstrT<std::string>(
166 input, delimiter, whitespace, result_type);
167 }
168
SplitStringPieceUsingSubstr(std::u16string_view input,std::u16string_view delimiter,WhitespaceHandling whitespace,SplitResult result_type)169 std::vector<std::u16string_view> SplitStringPieceUsingSubstr(
170 std::u16string_view input,
171 std::u16string_view delimiter,
172 WhitespaceHandling whitespace,
173 SplitResult result_type) {
174 std::vector<std::u16string_view> result;
175 return internal::SplitStringUsingSubstrT<std::u16string_view>(
176 input, delimiter, whitespace, result_type);
177 }
178
SplitStringPieceUsingSubstr(std::string_view input,std::string_view delimiter,WhitespaceHandling whitespace,SplitResult result_type)179 std::vector<std::string_view> SplitStringPieceUsingSubstr(
180 std::string_view input,
181 std::string_view delimiter,
182 WhitespaceHandling whitespace,
183 SplitResult result_type) {
184 return internal::SplitStringUsingSubstrT<std::string_view>(
185 input, delimiter, whitespace, result_type);
186 }
187
188 } // namespace base
189