OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/strings/string_split.h" | 5 #include "base/strings/string_split.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/strings/string_util.h" | 8 #include "base/strings/string_util.h" |
9 #include "base/third_party/icu/icu_utf.h" | 9 #include "base/third_party/icu/icu_utf.h" |
10 | 10 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 | 92 |
93 if (whitespace == TRIM_WHITESPACE) | 93 if (whitespace == TRIM_WHITESPACE) |
94 piece = TrimString(piece, WhitespaceForType<Str>(), TRIM_ALL); | 94 piece = TrimString(piece, WhitespaceForType<Str>(), TRIM_ALL); |
95 | 95 |
96 if (result_type == SPLIT_WANT_ALL || !piece.empty()) | 96 if (result_type == SPLIT_WANT_ALL || !piece.empty()) |
97 result.push_back(PieceToOutputType<Str, OutputStringType>(piece)); | 97 result.push_back(PieceToOutputType<Str, OutputStringType>(piece)); |
98 } | 98 } |
99 return result; | 99 return result; |
100 } | 100 } |
101 | 101 |
102 bool SplitStringIntoKeyValue(const std::string& line, | 102 bool AppendStringKeyValue(StringPiece input, |
103 char key_value_delimiter, | 103 char delimiter, |
104 std::string* key, | 104 StringPairs* result) { |
105 std::string* value) { | 105 // Always append a new item regardless of success (it might be empty). The |
106 key->clear(); | 106 // below code will copy the strings directly into the result pair. |
107 value->clear(); | 107 result->resize(result->size() + 1); |
| 108 auto& result_pair = result->back(); |
108 | 109 |
109 // Find the delimiter. | 110 // Find the delimiter. |
110 size_t end_key_pos = line.find_first_of(key_value_delimiter); | 111 size_t end_key_pos = input.find_first_of(delimiter); |
111 if (end_key_pos == std::string::npos) { | 112 if (end_key_pos == std::string::npos) { |
112 DVLOG(1) << "cannot find delimiter in: " << line; | 113 DVLOG(1) << "cannot find delimiter in: " << input; |
113 return false; // no delimiter | 114 return false; // No delimiter. |
114 } | 115 } |
115 key->assign(line, 0, end_key_pos); | 116 input.substr(0, end_key_pos).CopyToString(&result_pair.first); |
116 | 117 |
117 // Find the value string. | 118 // Find the value string. |
118 std::string remains(line, end_key_pos, line.size() - end_key_pos); | 119 StringPiece remains = input.substr(end_key_pos, input.size() - end_key_pos); |
119 size_t begin_value_pos = remains.find_first_not_of(key_value_delimiter); | 120 size_t begin_value_pos = remains.find_first_not_of(delimiter); |
120 if (begin_value_pos == std::string::npos) { | 121 if (begin_value_pos == StringPiece::npos) { |
121 DVLOG(1) << "cannot parse value from line: " << line; | 122 DVLOG(1) << "cannot parse value from input: " << input; |
122 return false; // no value | 123 return false; // No value. |
123 } | 124 } |
124 value->assign(remains, begin_value_pos, remains.size() - begin_value_pos); | 125 remains.substr(begin_value_pos, remains.size() - begin_value_pos) |
| 126 .CopyToString(&result_pair.second); |
| 127 |
125 return true; | 128 return true; |
126 } | 129 } |
127 | 130 |
128 template <typename STR> | 131 template <typename Str> |
129 void SplitStringUsingSubstrT(const STR& str, | 132 void SplitStringUsingSubstrT(BasicStringPiece<Str> input, |
130 const STR& s, | 133 BasicStringPiece<Str> delimiter, |
131 std::vector<STR>* r) { | 134 std::vector<Str>* result) { |
132 r->clear(); | 135 using Piece = BasicStringPiece<Str>; |
133 typename STR::size_type begin_index = 0; | 136 using size_type = typename Piece::size_type; |
| 137 |
| 138 result->clear(); |
| 139 size_type begin_index = 0; |
134 while (true) { | 140 while (true) { |
135 const typename STR::size_type end_index = str.find(s, begin_index); | 141 size_type end_index = input.find(delimiter, begin_index); |
136 if (end_index == STR::npos) { | 142 if (end_index == Piece::npos) { |
137 const STR term = str.substr(begin_index); | 143 // No delimiter, use the rest of the string. |
138 STR tmp; | 144 Piece term = TrimString(input.substr(begin_index), |
139 TrimWhitespace(term, TRIM_ALL, &tmp); | 145 WhitespaceForType<Str>(), TRIM_ALL); |
140 r->push_back(tmp); | 146 result->push_back(term.as_string()); |
141 return; | 147 return; |
142 } | 148 } |
143 const STR term = str.substr(begin_index, end_index - begin_index); | 149 Piece term = TrimString(input.substr(begin_index, end_index - begin_index), |
144 STR tmp; | 150 WhitespaceForType<Str>(), TRIM_ALL); |
145 TrimWhitespace(term, TRIM_ALL, &tmp); | 151 result->push_back(term.as_string()); |
146 r->push_back(tmp); | 152 begin_index = end_index + delimiter.size(); |
147 begin_index = end_index + s.size(); | |
148 } | 153 } |
149 } | 154 } |
150 | 155 |
151 } // namespace | 156 } // namespace |
152 | 157 |
153 std::vector<std::string> SplitString(StringPiece input, | 158 std::vector<std::string> SplitString(StringPiece input, |
154 StringPiece separators, | 159 StringPiece separators, |
155 WhitespaceHandling whitespace, | 160 WhitespaceHandling whitespace, |
156 SplitResult result_type) { | 161 SplitResult result_type) { |
157 if (separators.size() == 1) { | 162 if (separators.size() == 1) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 WhitespaceHandling whitespace, | 196 WhitespaceHandling whitespace, |
192 SplitResult result_type) { | 197 SplitResult result_type) { |
193 if (separators.size() == 1) { | 198 if (separators.size() == 1) { |
194 return SplitStringT<string16, StringPiece16, char16>( | 199 return SplitStringT<string16, StringPiece16, char16>( |
195 input, separators[0], whitespace, result_type); | 200 input, separators[0], whitespace, result_type); |
196 } | 201 } |
197 return SplitStringT<string16, StringPiece16, StringPiece16>( | 202 return SplitStringT<string16, StringPiece16, StringPiece16>( |
198 input, separators, whitespace, result_type); | 203 input, separators, whitespace, result_type); |
199 } | 204 } |
200 | 205 |
201 void SplitString(const string16& str, | 206 bool SplitStringIntoKeyValuePairs(StringPiece input, |
202 char16 c, | |
203 std::vector<string16>* result) { | |
204 DCHECK(CBU16_IS_SINGLE(c)); | |
205 *result = SplitStringT<string16, string16, char16>( | |
206 str, c, TRIM_WHITESPACE, SPLIT_WANT_ALL); | |
207 | |
208 // Backward-compat hack: The old SplitString implementation would keep | |
209 // empty substrings, for example: | |
210 // "a,,b" -> ["a", "", "b"] | |
211 // "a, ,b" -> ["a", "", "b"] | |
212 // which the current code also does. But the old one would discard them when | |
213 // the only result was that empty string: | |
214 // " " -> [] | |
215 // In the latter case, our new code will give [""] | |
216 if (result->size() == 1 && (*result)[0].empty()) | |
217 result->clear(); | |
218 } | |
219 | |
220 void SplitString(const std::string& str, | |
221 char c, | |
222 std::vector<std::string>* result) { | |
223 #if CHAR_MIN < 0 | |
224 DCHECK_GE(c, 0); | |
225 #endif | |
226 DCHECK_LT(c, 0x7F); | |
227 *result = SplitStringT<std::string, std::string, char>( | |
228 str, c, TRIM_WHITESPACE, SPLIT_WANT_ALL); | |
229 | |
230 // Backward-compat hack, see above. | |
231 if (result->size() == 1 && (*result)[0].empty()) | |
232 result->clear(); | |
233 } | |
234 | |
235 bool SplitStringIntoKeyValuePairs(const std::string& line, | |
236 char key_value_delimiter, | 207 char key_value_delimiter, |
237 char key_value_pair_delimiter, | 208 char key_value_pair_delimiter, |
238 StringPairs* key_value_pairs) { | 209 StringPairs* key_value_pairs) { |
239 key_value_pairs->clear(); | 210 key_value_pairs->clear(); |
240 | 211 |
241 std::vector<std::string> pairs; | 212 std::vector<StringPiece> pairs = SplitStringPiece( |
242 SplitString(line, key_value_pair_delimiter, &pairs); | 213 input, std::string(1, key_value_pair_delimiter), |
| 214 TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); |
| 215 key_value_pairs->reserve(pairs.size()); |
243 | 216 |
244 bool success = true; | 217 bool success = true; |
245 for (size_t i = 0; i < pairs.size(); ++i) { | 218 for (const StringPiece& pair : pairs) { |
246 // Don't add empty pairs into the result. | 219 if (!AppendStringKeyValue(pair, key_value_delimiter, key_value_pairs)) { |
247 if (pairs[i].empty()) | |
248 continue; | |
249 | |
250 std::string key; | |
251 std::string value; | |
252 if (!SplitStringIntoKeyValue(pairs[i], key_value_delimiter, &key, &value)) { | |
253 // Don't return here, to allow for pairs without associated | 220 // Don't return here, to allow for pairs without associated |
254 // value or key; just record that the split failed. | 221 // value or key; just record that the split failed. |
255 success = false; | 222 success = false; |
256 } | 223 } |
257 key_value_pairs->push_back(make_pair(key, value)); | |
258 } | 224 } |
259 return success; | 225 return success; |
260 } | 226 } |
261 | 227 |
262 void SplitStringUsingSubstr(const string16& str, | 228 void SplitStringUsingSubstr(StringPiece16 input, |
263 const string16& s, | 229 StringPiece16 delimiter, |
264 std::vector<string16>* r) { | 230 std::vector<string16>* result) { |
265 SplitStringUsingSubstrT(str, s, r); | 231 SplitStringUsingSubstrT(input, delimiter, result); |
266 } | 232 } |
267 | 233 |
268 void SplitStringUsingSubstr(const std::string& str, | 234 void SplitStringUsingSubstr(StringPiece input, |
269 const std::string& s, | 235 StringPiece delimiter, |
270 std::vector<std::string>* r) { | 236 std::vector<std::string>* result) { |
271 SplitStringUsingSubstrT(str, s, r); | 237 SplitStringUsingSubstrT(input, delimiter, result); |
272 } | 238 } |
273 | 239 |
274 } // namespace base | 240 } // namespace base |
OLD | NEW |