| 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 patternLength = this.length; |
| 305 | 272 int startIndex = 0; |
| 306 int ix = 0; | 273 while (true) { |
| 307 while (ix < str.length) { | 274 int position = str.indexOf(this, startIndex); |
| 308 int foundIx = str.indexOf(this, ix); | 275 if (position == -1) { |
| 309 if (foundIx < 0) break; | 276 break; |
| 310 result.add(new _StringMatch(foundIx, str, this)); | 277 } |
| 311 ix = foundIx + length; | 278 result.add(new _StringMatch(position, str, this)); |
| 279 int endIndex = position + patternLength; |
| 280 if (endIndex == length) { |
| 281 break; |
| 282 } else if (position == endIndex) { |
| 283 ++startIndex; // empty match, advance and restart |
| 284 } else { |
| 285 startIndex = endIndex; |
| 286 } |
| 312 } | 287 } |
| 313 return result; | 288 return result; |
| 314 } | 289 } |
| 315 | 290 |
| 316 List<String> split(Pattern pattern) { | 291 List<String> split(Pattern pattern) { |
| 292 int length = this.length; |
| 293 Iterator iterator = pattern.allMatches(this).iterator(); |
| 294 if (length == 0 && iterator.hasNext()) { |
| 295 // A matched empty string input returns the empty list. |
| 296 return <String>[]; |
| 297 } |
| 317 List<String> result = new List<String>(); | 298 List<String> result = new List<String>(); |
| 318 if (pattern is RegExp) { | 299 int startIndex = 0; |
| 319 int startIndex = 0; | 300 int previousIndex = 0; |
| 320 for (Match match in pattern.allMatches(this)) { | 301 while (true) { |
| 321 result.add(this.substring(startIndex, match.start())); | 302 if (startIndex == length || !iterator.hasNext()) { |
| 322 startIndex = match.end(); | 303 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; | 304 break; |
| 340 } | 305 } |
| 341 result.add(this.substring(ix, foundIx)); | 306 Match match = iterator.next(); |
| 342 ix = foundIx + pattern.length; | 307 if (match.start() == length) { |
| 343 } | 308 result.add(this.substring(previousIndex, length)); |
| 344 if (ix == this.length) { | 309 break; |
| 345 result.add(""); | 310 } |
| 311 int endIndex = match.end(); |
| 312 if (startIndex == endIndex && endIndex == previousIndex) { |
| 313 ++startIndex; // empty match, advance and restart |
| 314 continue; |
| 315 } |
| 316 result.add(this.substring(previousIndex, match.start())); |
| 317 startIndex = previousIndex = endIndex; |
| 346 } | 318 } |
| 347 return result; | 319 return result; |
| 348 } | 320 } |
| 349 | 321 |
| 350 List<String> splitChars() { | 322 List<String> splitChars() { |
| 351 int len = this.length; | 323 int len = this.length; |
| 352 final result = new List<String>(len); | 324 final result = new List<String>(len); |
| 353 for (int i = 0; i < len; i++) { | 325 for (int i = 0; i < len; i++) { |
| 354 result[i] = this[i]; | 326 result[i] = this[i]; |
| 355 } | 327 } |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 } | 396 } |
| 425 | 397 |
| 426 } | 398 } |
| 427 | 399 |
| 428 | 400 |
| 429 class TwoByteString extends StringBase implements String { | 401 class TwoByteString extends StringBase implements String { |
| 430 factory TwoByteString._uninstantiable() { | 402 factory TwoByteString._uninstantiable() { |
| 431 throw const UnsupportedOperationException( | 403 throw const UnsupportedOperationException( |
| 432 "TwoByteString can only be allocated by the VM"); | 404 "TwoByteString can only be allocated by the VM"); |
| 433 } | 405 } |
| 434 | 406 |
| 435 // Checks for one-byte whitespaces only. | 407 // Checks for one-byte whitespaces only. |
| 436 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid | 408 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid |
| 437 // whitespaces. Add checking for multi-byte whitespace codepoints. | 409 // whitespaces. Add checking for multi-byte whitespace codepoints. |
| 438 bool _isWhitespace(int codePoint) { | 410 bool _isWhitespace(int codePoint) { |
| 439 return | 411 return |
| 440 (codePoint === 32) || // Space. | 412 (codePoint === 32) || // Space. |
| 441 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. | 413 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. |
| 442 } | 414 } |
| 443 } | 415 } |
| 444 | 416 |
| 445 | 417 |
| 446 class FourByteString extends StringBase implements String { | 418 class FourByteString extends StringBase implements String { |
| 447 factory FourByteString._uninstantiable() { | 419 factory FourByteString._uninstantiable() { |
| 448 throw const UnsupportedOperationException( | 420 throw const UnsupportedOperationException( |
| 449 "FourByteString can only be allocated by the VM"); | 421 "FourByteString can only be allocated by the VM"); |
| 450 } | 422 } |
| 451 | 423 |
| 452 // Checks for one-byte whitespaces only. | 424 // Checks for one-byte whitespaces only. |
| 453 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid | 425 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid |
| 454 // whitespaces. Add checking for multi-byte whitespace codepoints. | 426 // whitespaces. Add checking for multi-byte whitespace codepoints. |
| 455 bool _isWhitespace(int codePoint) { | 427 bool _isWhitespace(int codePoint) { |
| 456 return | 428 return |
| 457 (codePoint === 32) || // Space. | 429 (codePoint === 32) || // Space. |
| 458 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. | 430 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. |
| 459 } | 431 } |
| 460 } | 432 } |
| 461 | 433 |
| 462 | 434 |
| 463 class ExternalOneByteString extends StringBase implements String { | 435 class ExternalOneByteString extends StringBase implements String { |
| 464 factory ExternalOneByteString._uninstantiable() { | 436 factory ExternalOneByteString._uninstantiable() { |
| 465 throw const UnsupportedOperationException( | 437 throw const UnsupportedOperationException( |
| 466 "ExternalOneByteString can only be allocated by the VM"); | 438 "ExternalOneByteString can only be allocated by the VM"); |
| 467 } | 439 } |
| 468 | 440 |
| 469 // Checks for one-byte whitespaces only. | 441 // Checks for one-byte whitespaces only. |
| 470 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid | 442 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid |
| 471 // whitespaces for one byte strings. | 443 // whitespaces for one byte strings. |
| 472 bool _isWhitespace(int codePoint) { | 444 bool _isWhitespace(int codePoint) { |
| 473 return | 445 return |
| 474 (codePoint === 32) || // Space. | 446 (codePoint === 32) || // Space. |
| 475 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. | 447 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. |
| 476 } | 448 } |
| 477 } | 449 } |
| 478 | 450 |
| 479 | 451 |
| 480 class ExternalTwoByteString extends StringBase implements String { | 452 class ExternalTwoByteString extends StringBase implements String { |
| 481 factory ExternalTwoByteString._uninstantiable() { | 453 factory ExternalTwoByteString._uninstantiable() { |
| 482 throw const UnsupportedOperationException( | 454 throw const UnsupportedOperationException( |
| 483 "ExternalTwoByteString can only be allocated by the VM"); | 455 "ExternalTwoByteString can only be allocated by the VM"); |
| 484 } | 456 } |
| 485 | 457 |
| 486 // Checks for one-byte whitespaces only. | 458 // Checks for one-byte whitespaces only. |
| 487 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid | 459 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid |
| 488 // whitespaces. Add checking for multi-byte whitespace codepoints. | 460 // whitespaces. Add checking for multi-byte whitespace codepoints. |
| 489 bool _isWhitespace(int codePoint) { | 461 bool _isWhitespace(int codePoint) { |
| 490 return | 462 return |
| 491 (codePoint === 32) || // Space. | 463 (codePoint === 32) || // Space. |
| 492 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. | 464 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. |
| 493 } | 465 } |
| 494 } | 466 } |
| 495 | 467 |
| 496 | 468 |
| 497 class ExternalFourByteString extends StringBase implements String { | 469 class ExternalFourByteString extends StringBase implements String { |
| 498 factory ExternalFourByteString._uninstantiable() { | 470 factory ExternalFourByteString._uninstantiable() { |
| 499 throw const UnsupportedOperationException( | 471 throw const UnsupportedOperationException( |
| 500 "ExternalFourByteString can only be allocated by the VM"); | 472 "ExternalFourByteString can only be allocated by the VM"); |
| 501 } | 473 } |
| 502 | 474 |
| 503 // Checks for one-byte whitespaces only. | 475 // Checks for one-byte whitespaces only. |
| 504 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid | 476 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid |
| 505 // whitespaces. Add checking for multi-byte whitespace codepoints. | 477 // whitespaces. Add checking for multi-byte whitespace codepoints. |
| 506 bool _isWhitespace(int codePoint) { | 478 bool _isWhitespace(int codePoint) { |
| 507 return | 479 return |
| 508 (codePoint === 32) || // Space. | 480 (codePoint === 32) || // Space. |
| 509 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. | 481 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. |
| 510 } | 482 } |
| 511 } | 483 } |
| 512 | 484 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 533 for (int g in groups) { | 505 for (int g in groups) { |
| 534 result.add(group(g)); | 506 result.add(group(g)); |
| 535 } | 507 } |
| 536 return result; | 508 return result; |
| 537 } | 509 } |
| 538 | 510 |
| 539 final int _start; | 511 final int _start; |
| 540 final String str; | 512 final String str; |
| 541 final String pattern; | 513 final String pattern; |
| 542 } | 514 } |
| OLD | NEW |