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/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
10 #include "base/third_party/icu/icu_utf.h" | 10 #include "base/third_party/icu/icu_utf.h" |
11 | 11 |
12 namespace base { | 12 namespace base { |
13 | 13 |
14 template<typename STR> | 14 namespace { |
15 static void SplitStringT(const STR& str, | 15 |
16 const typename STR::value_type s, | 16 template <typename STR> |
17 bool trim_whitespace, | 17 void SplitStringT(const STR& str, |
18 std::vector<STR>* r) { | 18 const typename STR::value_type s, |
| 19 bool trim_whitespace, |
| 20 std::vector<STR>* r) { |
19 r->clear(); | 21 r->clear(); |
20 size_t last = 0; | 22 size_t last = 0; |
21 size_t c = str.size(); | 23 size_t c = str.size(); |
22 for (size_t i = 0; i <= c; ++i) { | 24 for (size_t i = 0; i <= c; ++i) { |
23 if (i == c || str[i] == s) { | 25 if (i == c || str[i] == s) { |
24 STR tmp(str, last, i - last); | 26 STR tmp(str, last, i - last); |
25 if (trim_whitespace) | 27 if (trim_whitespace) |
26 TrimWhitespace(tmp, TRIM_ALL, &tmp); | 28 TrimWhitespace(tmp, TRIM_ALL, &tmp); |
27 // Avoid converting an empty or all-whitespace source string into a vector | 29 // Avoid converting an empty or all-whitespace source string into a vector |
28 // of one empty string. | 30 // of one empty string. |
29 if (i != c || !r->empty() || !tmp.empty()) | 31 if (i != c || !r->empty() || !tmp.empty()) |
30 r->push_back(tmp); | 32 r->push_back(tmp); |
31 last = i + 1; | 33 last = i + 1; |
32 } | 34 } |
33 } | 35 } |
34 } | 36 } |
35 | 37 |
36 void SplitString(const string16& str, | 38 bool SplitStringIntoKeyValue(const std::string& line, |
37 char16 c, | 39 char key_value_delimiter, |
38 std::vector<string16>* r) { | 40 std::string* key, |
39 DCHECK(CBU16_IS_SINGLE(c)); | 41 std::string* value) { |
40 SplitStringT(str, c, true, r); | 42 key->clear(); |
41 } | 43 value->clear(); |
42 | 44 |
43 void SplitString(const std::string& str, | 45 // Find the delimiter. |
44 char c, | |
45 std::vector<std::string>* r) { | |
46 #if CHAR_MIN < 0 | |
47 DCHECK(c >= 0); | |
48 #endif | |
49 DCHECK(c < 0x7F); | |
50 SplitStringT(str, c, true, r); | |
51 } | |
52 | |
53 bool SplitStringIntoKeyValues( | |
54 const std::string& line, | |
55 char key_value_delimiter, | |
56 std::string* key, std::vector<std::string>* values) { | |
57 key->clear(); | |
58 values->clear(); | |
59 | |
60 // Find the key string. | |
61 size_t end_key_pos = line.find_first_of(key_value_delimiter); | 46 size_t end_key_pos = line.find_first_of(key_value_delimiter); |
62 if (end_key_pos == std::string::npos) { | 47 if (end_key_pos == std::string::npos) { |
63 DVLOG(1) << "cannot parse key from line: " << line; | 48 DVLOG(1) << "cannot find delimiter in: " << line; |
64 return false; // no key | 49 return false; // no delimiter |
65 } | 50 } |
66 key->assign(line, 0, end_key_pos); | 51 key->assign(line, 0, end_key_pos); |
67 | 52 |
68 // Find the values string. | 53 // Find the value string. |
69 std::string remains(line, end_key_pos, line.size() - end_key_pos); | 54 std::string remains(line, end_key_pos, line.size() - end_key_pos); |
70 size_t begin_values_pos = remains.find_first_not_of(key_value_delimiter); | 55 size_t begin_value_pos = remains.find_first_not_of(key_value_delimiter); |
71 if (begin_values_pos == std::string::npos) { | 56 if (begin_value_pos == std::string::npos) { |
72 DVLOG(1) << "cannot parse value from line: " << line; | 57 DVLOG(1) << "cannot parse value from line: " << line; |
73 return false; // no value | 58 return false; // no value |
74 } | 59 } |
75 std::string values_string(remains, begin_values_pos, | 60 value->assign(remains, begin_value_pos, remains.size() - begin_value_pos); |
76 remains.size() - begin_values_pos); | |
77 | |
78 // Construct the values vector. | |
79 values->push_back(values_string); | |
80 return true; | 61 return true; |
81 } | 62 } |
82 | 63 |
83 bool SplitStringIntoKeyValuePairs(const std::string& line, | |
84 char key_value_delimiter, | |
85 char key_value_pair_delimiter, | |
86 StringPairs* key_value_pairs) { | |
87 key_value_pairs->clear(); | |
88 | |
89 std::vector<std::string> pairs; | |
90 SplitString(line, key_value_pair_delimiter, &pairs); | |
91 | |
92 bool success = true; | |
93 for (size_t i = 0; i < pairs.size(); ++i) { | |
94 // Empty pair. SplitStringIntoKeyValues is more strict about an empty pair | |
95 // line, so continue with the next pair. | |
96 if (pairs[i].empty()) | |
97 continue; | |
98 | |
99 std::string key; | |
100 std::vector<std::string> value; | |
101 if (!SplitStringIntoKeyValues(pairs[i], | |
102 key_value_delimiter, | |
103 &key, &value)) { | |
104 // Don't return here, to allow for keys without associated | |
105 // values; just record that our split failed. | |
106 success = false; | |
107 } | |
108 DCHECK_LE(value.size(), 1U); | |
109 key_value_pairs->push_back( | |
110 make_pair(key, value.empty() ? std::string() : value[0])); | |
111 } | |
112 return success; | |
113 } | |
114 | |
115 template <typename STR> | 64 template <typename STR> |
116 static void SplitStringUsingSubstrT(const STR& str, | 65 void SplitStringUsingSubstrT(const STR& str, |
117 const STR& s, | 66 const STR& s, |
118 std::vector<STR>* r) { | 67 std::vector<STR>* r) { |
119 r->clear(); | 68 r->clear(); |
120 typename STR::size_type begin_index = 0; | 69 typename STR::size_type begin_index = 0; |
121 while (true) { | 70 while (true) { |
122 const typename STR::size_type end_index = str.find(s, begin_index); | 71 const typename STR::size_type end_index = str.find(s, begin_index); |
123 if (end_index == STR::npos) { | 72 if (end_index == STR::npos) { |
124 const STR term = str.substr(begin_index); | 73 const STR term = str.substr(begin_index); |
125 STR tmp; | 74 STR tmp; |
126 TrimWhitespace(term, TRIM_ALL, &tmp); | 75 TrimWhitespace(term, TRIM_ALL, &tmp); |
127 r->push_back(tmp); | 76 r->push_back(tmp); |
128 return; | 77 return; |
129 } | 78 } |
130 const STR term = str.substr(begin_index, end_index - begin_index); | 79 const STR term = str.substr(begin_index, end_index - begin_index); |
131 STR tmp; | 80 STR tmp; |
132 TrimWhitespace(term, TRIM_ALL, &tmp); | 81 TrimWhitespace(term, TRIM_ALL, &tmp); |
133 r->push_back(tmp); | 82 r->push_back(tmp); |
134 begin_index = end_index + s.size(); | 83 begin_index = end_index + s.size(); |
135 } | 84 } |
136 } | 85 } |
137 | 86 |
138 void SplitStringUsingSubstr(const string16& str, | |
139 const string16& s, | |
140 std::vector<string16>* r) { | |
141 SplitStringUsingSubstrT(str, s, r); | |
142 } | |
143 | |
144 void SplitStringUsingSubstr(const std::string& str, | |
145 const std::string& s, | |
146 std::vector<std::string>* r) { | |
147 SplitStringUsingSubstrT(str, s, r); | |
148 } | |
149 | |
150 void SplitStringDontTrim(const string16& str, | |
151 char16 c, | |
152 std::vector<string16>* r) { | |
153 DCHECK(CBU16_IS_SINGLE(c)); | |
154 SplitStringT(str, c, false, r); | |
155 } | |
156 | |
157 void SplitStringDontTrim(const std::string& str, | |
158 char c, | |
159 std::vector<std::string>* r) { | |
160 DCHECK(IsStringUTF8(str)); | |
161 #if CHAR_MIN < 0 | |
162 DCHECK(c >= 0); | |
163 #endif | |
164 DCHECK(c < 0x7F); | |
165 SplitStringT(str, c, false, r); | |
166 } | |
167 | |
168 template<typename STR> | 87 template<typename STR> |
169 void SplitStringAlongWhitespaceT(const STR& str, std::vector<STR>* result) { | 88 void SplitStringAlongWhitespaceT(const STR& str, std::vector<STR>* result) { |
170 result->clear(); | 89 result->clear(); |
171 const size_t length = str.length(); | 90 const size_t length = str.length(); |
172 if (!length) | 91 if (!length) |
173 return; | 92 return; |
174 | 93 |
175 bool last_was_ws = false; | 94 bool last_was_ws = false; |
176 size_t last_non_ws_start = 0; | 95 size_t last_non_ws_start = 0; |
177 for (size_t i = 0; i < length; ++i) { | 96 for (size_t i = 0; i < length; ++i) { |
(...skipping 21 matching lines...) Expand all Loading... |
199 } | 118 } |
200 break; | 119 break; |
201 } | 120 } |
202 } | 121 } |
203 if (!last_was_ws) { | 122 if (!last_was_ws) { |
204 result->push_back( | 123 result->push_back( |
205 str.substr(last_non_ws_start, length - last_non_ws_start)); | 124 str.substr(last_non_ws_start, length - last_non_ws_start)); |
206 } | 125 } |
207 } | 126 } |
208 | 127 |
| 128 } // namespace |
| 129 |
| 130 void SplitString(const string16& str, |
| 131 char16 c, |
| 132 std::vector<string16>* r) { |
| 133 DCHECK(CBU16_IS_SINGLE(c)); |
| 134 SplitStringT(str, c, true, r); |
| 135 } |
| 136 |
| 137 void SplitString(const std::string& str, |
| 138 char c, |
| 139 std::vector<std::string>* r) { |
| 140 #if CHAR_MIN < 0 |
| 141 DCHECK(c >= 0); |
| 142 #endif |
| 143 DCHECK(c < 0x7F); |
| 144 SplitStringT(str, c, true, r); |
| 145 } |
| 146 |
| 147 bool SplitStringIntoKeyValuePairs(const std::string& line, |
| 148 char key_value_delimiter, |
| 149 char key_value_pair_delimiter, |
| 150 StringPairs* key_value_pairs) { |
| 151 key_value_pairs->clear(); |
| 152 |
| 153 std::vector<std::string> pairs; |
| 154 SplitString(line, key_value_pair_delimiter, &pairs); |
| 155 |
| 156 bool success = true; |
| 157 for (size_t i = 0; i < pairs.size(); ++i) { |
| 158 // Don't add empty pairs into the result. |
| 159 if (pairs[i].empty()) |
| 160 continue; |
| 161 |
| 162 std::string key; |
| 163 std::string value; |
| 164 if (!SplitStringIntoKeyValue(pairs[i], key_value_delimiter, &key, &value)) { |
| 165 // Don't return here, to allow for pairs without associated |
| 166 // value or key; just record that the split failed. |
| 167 success = false; |
| 168 } |
| 169 key_value_pairs->push_back(make_pair(key, value)); |
| 170 } |
| 171 return success; |
| 172 } |
| 173 |
| 174 void SplitStringUsingSubstr(const string16& str, |
| 175 const string16& s, |
| 176 std::vector<string16>* r) { |
| 177 SplitStringUsingSubstrT(str, s, r); |
| 178 } |
| 179 |
| 180 void SplitStringUsingSubstr(const std::string& str, |
| 181 const std::string& s, |
| 182 std::vector<std::string>* r) { |
| 183 SplitStringUsingSubstrT(str, s, r); |
| 184 } |
| 185 |
| 186 void SplitStringDontTrim(const string16& str, |
| 187 char16 c, |
| 188 std::vector<string16>* r) { |
| 189 DCHECK(CBU16_IS_SINGLE(c)); |
| 190 SplitStringT(str, c, false, r); |
| 191 } |
| 192 |
| 193 void SplitStringDontTrim(const std::string& str, |
| 194 char c, |
| 195 std::vector<std::string>* r) { |
| 196 DCHECK(IsStringUTF8(str)); |
| 197 #if CHAR_MIN < 0 |
| 198 DCHECK(c >= 0); |
| 199 #endif |
| 200 DCHECK(c < 0x7F); |
| 201 SplitStringT(str, c, false, r); |
| 202 } |
| 203 |
209 void SplitStringAlongWhitespace(const string16& str, | 204 void SplitStringAlongWhitespace(const string16& str, |
210 std::vector<string16>* result) { | 205 std::vector<string16>* result) { |
211 SplitStringAlongWhitespaceT(str, result); | 206 SplitStringAlongWhitespaceT(str, result); |
212 } | 207 } |
213 | 208 |
214 void SplitStringAlongWhitespace(const std::string& str, | 209 void SplitStringAlongWhitespace(const std::string& str, |
215 std::vector<std::string>* result) { | 210 std::vector<std::string>* result) { |
216 SplitStringAlongWhitespaceT(str, result); | 211 SplitStringAlongWhitespaceT(str, result); |
217 } | 212 } |
218 | 213 |
219 } // namespace base | 214 } // namespace base |
OLD | NEW |