| 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 |