Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * [StringBase] contains common methods used by concrete String implementations, | 6 * [StringBase] contains common methods used by concrete String implementations, |
| 7 * e.g., OneByteString. | 7 * e.g., OneByteString. |
| 8 */ | 8 */ |
| 9 class StringBase { | 9 class StringBase { |
| 10 | 10 |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 184 } | 184 } |
| 185 if ((first == 0) && (last == (len - 1))) { | 185 if ((first == 0) && (last == (len - 1))) { |
| 186 // Returns this string if it does not have leading or trailing | 186 // Returns this string if it does not have leading or trailing |
| 187 // whitespaces. | 187 // whitespaces. |
| 188 return this; | 188 return this; |
| 189 } else { | 189 } else { |
| 190 return substringUnchecked_(first, last + 1); | 190 return substringUnchecked_(first, last + 1); |
| 191 } | 191 } |
| 192 } | 192 } |
| 193 | 193 |
| 194 bool contains(Pattern other, [int startIndex = 0]) { | 194 bool contains(Pattern pattern, [int startIndex = 0]) { |
| 195 if (other is String) { | 195 if (pattern is String) { |
| 196 return indexOf(other, startIndex) >= 0; | 196 return indexOf(pattern, startIndex) >= 0; |
| 197 } | 197 } |
| 198 return other.allMatches(this.substring(startIndex)).iterator().hasNext(); | 198 return pattern.allMatches(this.substring(startIndex)).iterator().hasNext(); |
| 199 } | 199 } |
| 200 | 200 |
| 201 String replaceFirst(Pattern pattern, String to) { | 201 String replaceFirst(Pattern pattern, String replacement) { |
| 202 if (pattern is RegExp) { | 202 if (pattern is! Pattern) { |
| 203 StringBuffer buffer = new StringBuffer(); | 203 throw new IllegalArgumentException("${pattern} is not a Pattern"); |
| 204 int startIndex = 0; | |
| 205 Match match = pattern.firstMatch(this); | |
| 206 if (match != null) { | |
| 207 buffer.add(this.substring(startIndex, match.start())).add(to); | |
| 208 startIndex = match.end(); | |
| 209 } | |
| 210 return buffer.add(this.substring(startIndex)).toString(); | |
| 211 } | 204 } |
| 212 int pos = this.indexOf(pattern, 0); | 205 if (replacement is! String) { |
| 213 if (pos < 0) { | 206 throw new IllegalArgumentException("${replacement} is not a String"); |
| 214 return this; | |
| 215 } | 207 } |
| 216 String s1 = this.substring(0, pos); | 208 StringBuffer buffer = new StringBuffer(); |
| 217 String s2 = this.substring(pos + pattern.length, this.length); | 209 int startIndex = 0; |
| 218 return s1.concat(to.concat(s2)); | 210 Iterator iterator = pattern.allMatches(this).iterator(); |
| 211 if (iterator.hasNext()) { | |
| 212 Match match = iterator.next(); | |
| 213 buffer.add(this.substring(startIndex, match.start())).add(replacement); | |
| 214 startIndex = match.end(); | |
| 215 } | |
| 216 return buffer.add(this.substring(startIndex)).toString(); | |
| 219 } | 217 } |
| 220 | 218 |
| 221 String replaceAll(Pattern pattern, String to) { | 219 String replaceAll(Pattern pattern, String replacement) { |
| 222 if (pattern is RegExp) { | 220 if (pattern is! Pattern) { |
| 223 StringBuffer buffer = new StringBuffer(); | 221 throw new IllegalArgumentException("${pattern} is not a Pattern"); |
| 224 int startIndex = 0; | |
| 225 for (Match match in pattern.allMatches(this)) { | |
| 226 buffer.add(this.substring(startIndex, match.start())).add(to); | |
| 227 startIndex = match.end(); | |
| 228 } | |
| 229 return buffer.add(this.substring(startIndex)).toString(); | |
| 230 } | 222 } |
| 231 String from = pattern; | 223 if (replacement is! String) { |
| 232 int fromLength = from.length; | 224 throw new IllegalArgumentException("${replacement} is not a String"); |
| 233 int toLength = to.length; | |
| 234 int thisLength = this.length; | |
| 235 | |
| 236 StringBuffer result = new StringBuffer(""); | |
| 237 // Special case the empty string replacement where [to] is | |
| 238 // inserted in between each character. | |
| 239 if (fromLength === 0) { | |
| 240 result.add(to); | |
| 241 for (int i = 0; i < thisLength; i++) { | |
| 242 result.add(this.substring(i, i + 1)); | |
| 243 result.add(to); | |
| 244 } | |
| 245 return result.toString(); | |
| 246 } | 225 } |
| 247 | 226 StringBuffer buffer = new StringBuffer(); |
| 248 int index = indexOf(from, 0); | 227 int startIndex = 0; |
| 249 if (index < 0) { | 228 for (Match match in pattern.allMatches(this)) { |
| 250 return this; | 229 buffer.add(this.substring(startIndex, match.start())).add(replacement); |
| 230 startIndex = match.end(); | |
| 251 } | 231 } |
| 252 int startIndex = 0; | 232 return buffer.add(this.substring(startIndex)).toString(); |
| 253 do { | |
| 254 result.add(this.substring(startIndex, index)); | |
| 255 result.add(to); | |
| 256 startIndex = index + fromLength; | |
| 257 } while ((index = indexOf(from, startIndex)) >= 0); | |
| 258 | |
| 259 // If there are remaining code points, add them to the string | |
| 260 // buffer. | |
| 261 if (startIndex < thisLength) { | |
| 262 result.add(this.substring(startIndex, thisLength)); | |
| 263 } | |
| 264 | |
| 265 return result.toString(); | |
| 266 } | 233 } |
| 267 | 234 |
| 268 /** | 235 /** |
| 269 * Convert argument obj to string and concat it with this string. | 236 * Convert argument obj to string and concat it with this string. |
| 270 * Returns concatenated string. | 237 * Returns concatenated string. |
| 271 */ | 238 */ |
| 272 String operator +(Object obj) { | 239 String operator +(Object obj) { |
| 273 return this.concat(obj.toString()); | 240 return this.concat(obj.toString()); |
| 274 } | 241 } |
| 275 | 242 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 293 int strLength = str.length; | 260 int strLength = str.length; |
| 294 for (int k = 0; k < strLength; k++) { | 261 for (int k = 0; k < strLength; k++) { |
| 295 codepoints[intArrayIx++] = str.charCodeAt(k); | 262 codepoints[intArrayIx++] = str.charCodeAt(k); |
| 296 } | 263 } |
| 297 } | 264 } |
| 298 return StringBase.createFromCharCodes(codepoints); | 265 return StringBase.createFromCharCodes(codepoints); |
| 299 } | 266 } |
| 300 | 267 |
| 301 Iterable<Match> allMatches(String str) { | 268 Iterable<Match> allMatches(String str) { |
| 302 List<Match> result = new List<Match>(); | 269 List<Match> result = new List<Match>(); |
| 303 if (this.isEmpty()) return result; | 270 int length = str.length; |
| 304 int length = this.length; | 271 int startIndex = 0; |
| 305 | 272 while (true) { |
| 306 int ix = 0; | 273 int position = str.indexOf(this, startIndex); |
| 307 while (ix < str.length) { | 274 if (position == -1) { |
| 308 int foundIx = str.indexOf(this, ix); | 275 break; |
| 309 if (foundIx < 0) break; | 276 } |
| 310 result.add(new _StringMatch(foundIx, str, this)); | 277 result.add(new _StringMatch(position, str, this)); |
| 311 ix = foundIx + length; | 278 int endIndex = position + this.length; |
|
Ivan Posva
2012/03/16 21:43:57
Want to pull this.length out in a similar fashion
cshapiro
2012/03/19 17:50:56
Good idea. Done.
| |
| 279 if (endIndex == length) { | |
| 280 break; | |
| 281 } else if (position == endIndex) { | |
| 282 ++startIndex; // empty match, advance and restart | |
| 283 } else { | |
| 284 startIndex = endIndex; | |
| 285 } | |
| 312 } | 286 } |
| 313 return result; | 287 return result; |
| 314 } | 288 } |
| 315 | 289 |
| 316 List<String> split(Pattern pattern) { | 290 List<String> split(Pattern pattern) { |
| 291 int length = this.length; | |
| 292 Iterator iterator = pattern.allMatches(this).iterator(); | |
| 293 if (length == 0) { | |
| 294 return iterator.hasNext() ? [] : [this]; | |
|
Ivan Posva
2012/03/16 21:43:57
Can you please add a comment explaining this somew
ngeoffray
2012/03/17 09:43:58
[] : [this] -> <String>[] : <String>[this]?
cshapiro
2012/03/19 06:39:29
can you give me more context for why this might be
Ivan Posva
2012/03/19 06:42:20
Because the return type of the method is List<Stri
cshapiro
2012/03/19 06:51:45
I am curious to know if some combination of tools
ngeoffray
2012/03/19 08:25:38
If you return just a list, the VM will not complai
cshapiro
2012/03/19 17:50:56
Sure, done. I have simplified the condition somew
cshapiro
2012/03/19 17:50:56
Got it. Thanks.
| |
| 295 } | |
| 317 List<String> result = new List<String>(); | 296 List<String> result = new List<String>(); |
| 318 if (pattern is RegExp) { | 297 int startIndex = 0; |
| 319 int startIndex = 0; | 298 int previousIndex = 0; |
| 320 for (Match match in pattern.allMatches(this)) { | 299 while (true) { |
| 321 result.add(this.substring(startIndex, match.start())); | 300 if (startIndex == length || !iterator.hasNext()) { |
| 322 startIndex = match.end(); | 301 result.add(this.substring(previousIndex, length)); |
| 323 } | |
| 324 result.add(this.substring(startIndex)); | |
| 325 return result; | |
| 326 } | |
| 327 if (pattern.isEmpty()) { | |
| 328 for (int i = 0; i < this.length; i++) { | |
| 329 result.add(this.substring(i, i+1)); | |
| 330 } | |
| 331 return result; | |
| 332 } | |
| 333 int ix = 0; | |
| 334 while (ix < this.length) { | |
| 335 int foundIx = this.indexOf(pattern, ix); | |
| 336 if (foundIx < 0) { | |
| 337 // Not found, add remaining. | |
| 338 result.add(this.substring(ix, this.length)); | |
| 339 break; | 302 break; |
| 340 } | 303 } |
| 341 result.add(this.substring(ix, foundIx)); | 304 Match match = iterator.next(); |
| 342 ix = foundIx + pattern.length; | 305 if (match.start() == length) { |
| 343 } | 306 result.add(this.substring(previousIndex, length)); |
| 344 if (ix == this.length) { | 307 break; |
| 345 result.add(""); | 308 } |
| 309 var endIndex = match.end(); | |
| 310 if (startIndex == endIndex && endIndex == previousIndex) { | |
| 311 ++startIndex; // empty match, advance and restart | |
| 312 continue; | |
| 313 } | |
| 314 result.add(this.substring(previousIndex, match.start())); | |
| 315 startIndex = previousIndex = endIndex; | |
| 346 } | 316 } |
| 347 return result; | 317 return result; |
| 348 } | 318 } |
| 349 | 319 |
| 350 List<String> splitChars() { | 320 List<String> splitChars() { |
| 351 int len = this.length; | 321 int len = this.length; |
| 352 final result = new List<String>(len); | 322 final result = new List<String>(len); |
| 353 for (int i = 0; i < len; i++) { | 323 for (int i = 0; i < len; i++) { |
| 354 result[i] = this[i]; | 324 result[i] = this[i]; |
| 355 } | 325 } |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 424 } | 394 } |
| 425 | 395 |
| 426 } | 396 } |
| 427 | 397 |
| 428 | 398 |
| 429 class TwoByteString extends StringBase implements String { | 399 class TwoByteString extends StringBase implements String { |
| 430 factory TwoByteString._uninstantiable() { | 400 factory TwoByteString._uninstantiable() { |
| 431 throw const UnsupportedOperationException( | 401 throw const UnsupportedOperationException( |
| 432 "TwoByteString can only be allocated by the VM"); | 402 "TwoByteString can only be allocated by the VM"); |
| 433 } | 403 } |
| 434 | 404 |
| 435 // Checks for one-byte whitespaces only. | 405 // Checks for one-byte whitespaces only. |
| 436 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid | 406 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid |
| 437 // whitespaces. Add checking for multi-byte whitespace codepoints. | 407 // whitespaces. Add checking for multi-byte whitespace codepoints. |
| 438 bool _isWhitespace(int codePoint) { | 408 bool _isWhitespace(int codePoint) { |
| 439 return | 409 return |
| 440 (codePoint === 32) || // Space. | 410 (codePoint === 32) || // Space. |
| 441 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. | 411 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. |
| 442 } | 412 } |
| 443 } | 413 } |
| 444 | 414 |
| 445 | 415 |
| 446 class FourByteString extends StringBase implements String { | 416 class FourByteString extends StringBase implements String { |
| 447 factory FourByteString._uninstantiable() { | 417 factory FourByteString._uninstantiable() { |
| 448 throw const UnsupportedOperationException( | 418 throw const UnsupportedOperationException( |
| 449 "FourByteString can only be allocated by the VM"); | 419 "FourByteString can only be allocated by the VM"); |
| 450 } | 420 } |
| 451 | 421 |
| 452 // Checks for one-byte whitespaces only. | 422 // Checks for one-byte whitespaces only. |
| 453 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid | 423 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid |
| 454 // whitespaces. Add checking for multi-byte whitespace codepoints. | 424 // whitespaces. Add checking for multi-byte whitespace codepoints. |
| 455 bool _isWhitespace(int codePoint) { | 425 bool _isWhitespace(int codePoint) { |
| 456 return | 426 return |
| 457 (codePoint === 32) || // Space. | 427 (codePoint === 32) || // Space. |
| 458 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. | 428 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. |
| 459 } | 429 } |
| 460 } | 430 } |
| 461 | 431 |
| 462 | 432 |
| 463 class ExternalOneByteString extends StringBase implements String { | 433 class ExternalOneByteString extends StringBase implements String { |
| 464 factory ExternalOneByteString._uninstantiable() { | 434 factory ExternalOneByteString._uninstantiable() { |
| 465 throw const UnsupportedOperationException( | 435 throw const UnsupportedOperationException( |
| 466 "ExternalOneByteString can only be allocated by the VM"); | 436 "ExternalOneByteString can only be allocated by the VM"); |
| 467 } | 437 } |
| 468 | 438 |
| 469 // Checks for one-byte whitespaces only. | 439 // Checks for one-byte whitespaces only. |
| 470 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid | 440 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid |
| 471 // whitespaces for one byte strings. | 441 // whitespaces for one byte strings. |
| 472 bool _isWhitespace(int codePoint) { | 442 bool _isWhitespace(int codePoint) { |
| 473 return | 443 return |
| 474 (codePoint === 32) || // Space. | 444 (codePoint === 32) || // Space. |
| 475 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. | 445 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. |
| 476 } | 446 } |
| 477 } | 447 } |
| 478 | 448 |
| 479 | 449 |
| 480 class ExternalTwoByteString extends StringBase implements String { | 450 class ExternalTwoByteString extends StringBase implements String { |
| 481 factory ExternalTwoByteString._uninstantiable() { | 451 factory ExternalTwoByteString._uninstantiable() { |
| 482 throw const UnsupportedOperationException( | 452 throw const UnsupportedOperationException( |
| 483 "ExternalTwoByteString can only be allocated by the VM"); | 453 "ExternalTwoByteString can only be allocated by the VM"); |
| 484 } | 454 } |
| 485 | 455 |
| 486 // Checks for one-byte whitespaces only. | 456 // Checks for one-byte whitespaces only. |
| 487 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid | 457 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid |
| 488 // whitespaces. Add checking for multi-byte whitespace codepoints. | 458 // whitespaces. Add checking for multi-byte whitespace codepoints. |
| 489 bool _isWhitespace(int codePoint) { | 459 bool _isWhitespace(int codePoint) { |
| 490 return | 460 return |
| 491 (codePoint === 32) || // Space. | 461 (codePoint === 32) || // Space. |
| 492 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. | 462 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. |
| 493 } | 463 } |
| 494 } | 464 } |
| 495 | 465 |
| 496 | 466 |
| 497 class ExternalFourByteString extends StringBase implements String { | 467 class ExternalFourByteString extends StringBase implements String { |
| 498 factory ExternalFourByteString._uninstantiable() { | 468 factory ExternalFourByteString._uninstantiable() { |
| 499 throw const UnsupportedOperationException( | 469 throw const UnsupportedOperationException( |
| 500 "ExternalFourByteString can only be allocated by the VM"); | 470 "ExternalFourByteString can only be allocated by the VM"); |
| 501 } | 471 } |
| 502 | 472 |
| 503 // Checks for one-byte whitespaces only. | 473 // Checks for one-byte whitespaces only. |
| 504 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid | 474 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid |
| 505 // whitespaces. Add checking for multi-byte whitespace codepoints. | 475 // whitespaces. Add checking for multi-byte whitespace codepoints. |
| 506 bool _isWhitespace(int codePoint) { | 476 bool _isWhitespace(int codePoint) { |
| 507 return | 477 return |
| 508 (codePoint === 32) || // Space. | 478 (codePoint === 32) || // Space. |
| 509 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. | 479 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. |
| 510 } | 480 } |
| 511 } | 481 } |
| 512 | 482 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 533 for (int g in groups) { | 503 for (int g in groups) { |
| 534 result.add(group(g)); | 504 result.add(group(g)); |
| 535 } | 505 } |
| 536 return result; | 506 return result; |
| 537 } | 507 } |
| 538 | 508 |
| 539 final int _start; | 509 final int _start; |
| 540 final String str; | 510 final String str; |
| 541 final String pattern; | 511 final String pattern; |
| 542 } | 512 } |
| OLD | NEW |