Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(995)

Side by Side Diff: test/generated_sdk/lib/core/string.dart

Issue 1162723007: remove generated_sdk from checked in code (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
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.
4
5 part of dart.core;
6
7 /**
8 * A sequence of characters.
9 *
10 * A string can be either single or multiline. Single line strings are
11 * written using matching single or double quotes, and multiline strings are
12 * written using triple quotes. The following are all valid Dart strings:
13 *
14 * 'Single quotes';
15 * "Double quotes";
16 * 'Double quotes in "single" quotes';
17 * "Single quotes in 'double' quotes";
18 *
19 * '''A
20 * multiline
21 * string''';
22 *
23 * """
24 * Another
25 * multiline
26 * string""";
27 *
28 * Strings are immutable. Although you cannot change a string, you can perform
29 * an operation on a string and assign the result to a new string:
30 *
31 * var string = 'Dart is fun';
32 * var newString = string.substring(0, 5);
33 *
34 * You can use the plus (`+`) operator to concatenate strings:
35 *
36 * 'Dart ' + 'is ' + 'fun!'; // 'Dart is fun!'
37 *
38 * You can also use adjacent string literals for concatenation:
39 *
40 * 'Dart ' 'is ' 'fun!'; // 'Dart is fun!'
41 *
42 * You can use `${}` to interpolate the value of Dart expressions
43 * within strings. The curly braces can be omitted when evaluating identifiers:
44 *
45 * string = 'dartlang';
46 * '$string has ${string.length} letters'; // 'dartlang has 8 letters'
47 *
48 * A string is represented by a sequence of Unicode UTF-16 code units
49 * accessible through the [codeUnitAt] or the [codeUnits] members:
50 *
51 * string = 'Dart';
52 * string.codeUnitAt(0); // 68
53 * string.codeUnits; // [68, 97, 114, 116]
54 *
55 * The string representation of code units is accessible through the index
56 * operator:
57 *
58 * string[0]; // 'D'
59 *
60 * The characters of a string are encoded in UTF-16. Decoding UTF-16, which
61 * combines surrogate pairs, yields Unicode code points. Following a similar
62 * terminology to Go, we use the name 'rune' for an integer representing a
63 * Unicode code point. Use the [runes] property to get the runes of a string:
64 *
65 * string.runes.toList(); // [68, 97, 114, 116]
66 *
67 * For a character outside the Basic Multilingual Plane (plane 0) that is
68 * composed of a surrogate pair, [runes] combines the pair and returns a
69 * single integer. For example, the Unicode character for a
70 * musical G-clef ('𝄞') with rune value 0x1D11E consists of a UTF-16 surrogate
71 * pair: `0xD834` and `0xDD1E`. Using [codeUnits] returns the surrogate pair,
72 * and using `runes` returns their combined value:
73 *
74 * var clef = '\u{1D11E}';
75 * clef.codeUnits; // [0xD834, 0xDD1E]
76 * clef.runes.toList(); // [0x1D11E]
77 *
78 * The String class can not be extended or implemented. Attempting to do so
79 * yields a compile-time error.
80 *
81 * ## Other resources
82 *
83 * See [StringBuffer] to efficiently build a string incrementally. See
84 * [RegExp] to work with regular expressions.
85 *
86 * Also see:
87
88 * * [Dart Cookbook](https://www.dartlang.org/docs/cookbook/#strings)
89 * for String examples and recipes.
90 * * [Dart Up and Running]
91 * (https://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html#ch03-st rings-and-regular-expressions)
92 */
93 abstract class String implements Comparable<String>, Pattern {
94 /**
95 * Allocates a new String for the specified [charCodes].
96 *
97 * The [charCodes] can be UTF-16 code units or runes. If a char-code value is
98 * 16-bit, it is copied verbatim:
99 *
100 * new String.fromCharCodes([68]); // 'D'
101 *
102 * If a char-code value is greater than 16-bits, it is decomposed into a
103 * surrogate pair:
104 *
105 * var clef = new String.fromCharCodes([0x1D11E]);
106 * clef.codeUnitAt(0); // 0xD834
107 * clef.codeUnitAt(1); // 0xDD1E
108 *
109 * If [start] and [end] is provided, only the values of [charCodes]
110 * at positions from `start` to, but not including, `end`, are used.
111 * The `start` and `end` values must satisfy
112 * `0 <= start <= end <= charCodes.length`.
113 */
114 factory String.fromCharCodes(Iterable<int> charCodes,
115 [int start = 0, int end]) {
116 // If possible, recognize typed lists too.
117 if (charCodes is! JSArray) {
118 return _stringFromIterable(charCodes, start, end);
119 }
120
121 List list = charCodes;
122 int len = list.length;
123 if (start < 0 || start > len) {
124 throw new RangeError.range(start, 0, len);
125 }
126 if (end == null) {
127 end = len;
128 } else if (end < start || end > len) {
129 throw new RangeError.range(end, start, len);
130 }
131
132 if (start > 0 || end < len) {
133 list = list.sublist(start, end);
134 }
135 return Primitives.stringFromCharCodes(list);
136 }
137
138 /**
139 * Allocates a new String for the specified [charCode].
140 *
141 * If the [charCode] can be represented by a single UTF-16 code unit, the new
142 * string contains a single code unit. Otherwise, the [length] is 2 and
143 * the code units form a surrogate pair. See documentation for
144 * [fromCharCodes].
145 *
146 * Creating a String with half of a surrogate pair is allowed.
147 */
148 factory String.fromCharCode(int charCode) {
149 return Primitives.stringFromCharCode(charCode);
150 }
151
152 /**
153 * Returns the string value of the environment declaration [name].
154 *
155 * Environment declarations are provided by the surrounding system compiling
156 * or running the Dart program. Declarations map a string key to a string
157 * value.
158 *
159 * If [name] is not declared in the environment, the result is instead
160 * [defaultValue].
161 *
162 * Example of getting a value:
163 *
164 * const String.fromEnvironment("defaultFloo", defaultValue: "no floo")
165 *
166 * Example of checking whether a declaration is there at all:
167 *
168 * var isDeclared = const String.fromEnvironment("maybeDeclared") != null;
169 */
170 factory String.fromEnvironment(String name, {String defaultValue}) {
171 throw new UnsupportedError(
172 'String.fromEnvironment can only be used as a const constructor');
173 }
174
175 /**
176 * Gets the character (as a single-code-unit [String]) at the given [index].
177 *
178 * The returned string represents exactly one UTF-16 code unit, which may be
179 * half of a surrogate pair. A single member of a surrogate pair is an
180 * invalid UTF-16 string:
181 *
182 * var clef = '\u{1D11E}';
183 * // These represent invalid UTF-16 strings.
184 * clef[0].codeUnits; // [0xD834]
185 * clef[1].codeUnits; // [0xDD1E]
186 *
187 * This method is equivalent to
188 * `new String.fromCharCode(this.codeUnitAt(index))`.
189 */
190 String operator [](int index);
191
192 /**
193 * Returns the 16-bit UTF-16 code unit at the given [index].
194 */
195 int codeUnitAt(int index);
196
197 /**
198 * The length of the string.
199 *
200 * Returns the number of UTF-16 code units in this string. The number
201 * of [runes] might be fewer, if the string contains characters outside
202 * the Basic Multilingual Plane (plane 0):
203 *
204 * 'Dart'.length; // 4
205 * 'Dart'.runes.length; // 4
206 *
207 * var clef = '\u{1D11E}';
208 * clef.length; // 2
209 * clef.runes.length; // 1
210 */
211 int get length;
212
213 /**
214 * Returns a hash code derived from the code units of the string.
215 *
216 * This is compatible with [operator==]. Strings with the same sequence
217 * of code units have the same hash code.
218 */
219 int get hashCode;
220
221 /**
222 * Returns true if other is a `String` with the same sequence of code units.
223 *
224 * This method compares each individual code unit of the strings.
225 * It does not check for Unicode equivalence.
226 * For example, both the following strings represent the string 'Amélie',
227 * but due to their different encoding, are not equal:
228 *
229 * 'Am\xe9lie' == 'Ame\u{301}lie'; // false
230 *
231 * The first string encodes 'é' as a single unicode code unit (also
232 * a single rune), whereas the second string encodes it as 'e' with the
233 * combining accent character '◌́'.
234 */
235 bool operator ==(Object other);
236
237 /**
238 * Returns true if this string ends with [other]. For example:
239 *
240 * 'Dart'.endsWith('t'); // true
241 */
242 bool endsWith(String other);
243
244 /**
245 * Returns true if this string starts with a match of [pattern].
246 *
247 * var string = 'Dart';
248 * string.startsWith('D'); // true
249 * string.startsWith(new RegExp(r'[A-Z][a-z]')); // true
250 *
251 * If [index] is provided, this method checks if the substring starting
252 * at that index starts with a match of [pattern]:
253 *
254 * string.startsWith('art', 1); // true
255 * string.startsWith(new RegExp(r'\w{3}')); // true
256 *
257 * [index] must not be negative or greater than [length].
258 *
259 * A [RegExp] containing '^' does not match if the [index] is greater than
260 * zero. The pattern works on the string as a whole, and does not extract
261 * a substring starting at [index] first:
262 *
263 * string.startsWith(new RegExp(r'^art'), 1); // false
264 * string.startsWith(new RegExp(r'art'), 1); // true
265 */
266 bool startsWith(Pattern pattern, [int index = 0]);
267
268 /**
269 * Returns the position of the first match of [pattern] in this string,
270 * starting at [start], inclusive:
271 *
272 * var string = 'Dartisans';
273 * string.indexOf('art'); // 1
274 * string.indexOf(new RegExp(r'[A-Z][a-z]')); // 0
275 *
276 * Returns -1 if no match is found:
277 *
278 * string.indexOf(new RegExp(r'dart')); // -1
279 *
280 * [start] must not be negative or greater than [length].
281 */
282 int indexOf(Pattern pattern, [int start]);
283
284 /**
285 * Returns the position of the last match [pattern] in this string, searching
286 * backward starting at [start], inclusive:
287 *
288 * var string = 'Dartisans';
289 * string.lastIndexOf('a'); // 6
290 * string.lastIndexOf(new RegExp(r'a(r|n)')); // 6
291 *
292 * Returns -1 if [other] could not be found.
293 *
294 * string.lastIndexOf(new RegExp(r'DART')); // -1
295 *
296 * [start] must not be negative or greater than [length].
297 */
298 int lastIndexOf(Pattern pattern, [int start]);
299
300 /**
301 * Returns true if this string is empty.
302 */
303 bool get isEmpty;
304
305 /**
306 * Returns true if this string is not empty.
307 */
308 bool get isNotEmpty;
309
310 /**
311 * Creates a new string by concatenating this string with [other].
312 *
313 * 'dart' + 'lang'; // 'dartlang'
314 */
315 String operator +(String other);
316
317 /**
318 * Returns the substring of this string that extends from [startIndex],
319 * inclusive, to [endIndex], exclusive.
320 *
321 * var string = 'dartlang';
322 * string.substring(1); // 'artlang'
323 * string.substring(1, 4); // 'art'
324 */
325 String substring(int startIndex, [int endIndex]);
326
327 /**
328 * Returns the string without any leading and trailing whitespace.
329 *
330 * If the string contains leading or trailing whitespace, a new string with no
331 * leading and no trailing whitespace is returned:
332 *
333 * '\tDart is fun\n'.trim(); // 'Dart is fun'
334 *
335 * Otherwise, the original string itself is returned:
336 *
337 * var str1 = 'Dart';
338 * var str2 = str1.trim();
339 * identical(str1, str2); // true
340 *
341 * Whitespace is defined by the Unicode White_Space property (as defined in
342 * version 6.2 or later) and the BOM character, 0xFEFF.
343 *
344 * Here is the list of trimmed characters (following version 6.2):
345 *
346 * 0009..000D ; White_Space # Cc <control-0009>..<control-000D>
347 * 0020 ; White_Space # Zs SPACE
348 * 0085 ; White_Space # Cc <control-0085>
349 * 00A0 ; White_Space # Zs NO-BREAK SPACE
350 * 1680 ; White_Space # Zs OGHAM SPACE MARK
351 * 180E ; White_Space # Zs MONGOLIAN VOWEL SEPARATOR
352 * 2000..200A ; White_Space # Zs EN QUAD..HAIR SPACE
353 * 2028 ; White_Space # Zl LINE SEPARATOR
354 * 2029 ; White_Space # Zp PARAGRAPH SEPARATOR
355 * 202F ; White_Space # Zs NARROW NO-BREAK SPACE
356 * 205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE
357 * 3000 ; White_Space # Zs IDEOGRAPHIC SPACE
358 *
359 * FEFF ; BOM ZERO WIDTH NO_BREAK SPACE
360 */
361 String trim();
362
363 /**
364 * Returns the string without any leading whitespace.
365 *
366 * As [trim], but only removes leading whitespace.
367 */
368 String trimLeft();
369
370 /**
371 * Returns the string without any trailing whitespace.
372 *
373 * As [trim], but only removes trailing whitespace.
374 */
375 String trimRight();
376
377 /**
378 * Creates a new string by concatenating this string with itself a number
379 * of times.
380 *
381 * The result of `str * n` is equivalent to
382 * `str + str + ...`(n times)`... + str`.
383 *
384 * Returns an empty string if [times] is zero or negative.
385 */
386 String operator *(int times);
387
388 /**
389 * Pads this string on the left if it is shorther than [width].
390 *
391 * Return a new string that prepends [padding] onto this string
392 * one time for each position the length is less than [width].
393 *
394 * If [width] is already smaller than or equal to `this.length`,
395 * no padding is added. A negative `width` is treated as zero.
396 *
397 * If [padding] has length different from 1, the result will not
398 * have length `width`. This may be useful for cases where the
399 * padding is a longer string representing a single character, like
400 * `"&nbsp;"` or `"\u{10002}`".
401 * In that case, the user should make sure that `this.length` is
402 * the correct measure of the strings length.
403 */
404 String padLeft(int width, [String padding = ' ']);
405
406 /**
407 * Pads this string on the right if it is shorther than [width].
408 *
409 * Return a new string that appends [padding] after this string
410 * one time for each position the length is less than [width].
411 *
412 * If [width] is already smaller than or equal to `this.length`,
413 * no padding is added. A negative `width` is treated as zero.
414 *
415 * If [padding] has length different from 1, the result will not
416 * have length `width`. This may be useful for cases where the
417 * padding is a longer string representing a single character, like
418 * `"&nbsp;"` or `"\u{10002}`".
419 * In that case, the user should make sure that `this.length` is
420 * the correct measure of the strings length.
421 */
422 String padRight(int width, [String padding = ' ']);
423
424 /**
425 * Returns true if this string contains a match of [other]:
426 *
427 * var string = 'Dart strings';
428 * string.contains('D'); // true
429 * string.contains(new RegExp(r'[A-Z]')); // true
430 *
431 * If [startIndex] is provided, this method matches only at or after that
432 * index:
433 *
434 * string.contains('X', 1); // false
435 * string.contains(new RegExp(r'[A-Z]'), 1); // false
436 *
437 * [startIndex] must not be negative or greater than [length].
438 */
439 bool contains(Pattern other, [int startIndex = 0]);
440
441 /**
442 * Returns a new string in which the first occurence of [from] in this string
443 * is replaced with [to], starting from [startIndex]:
444 *
445 * '0.0001'.replaceFirst(new RegExp(r'0'), ''); // '.0001'
446 * '0.0001'.replaceFirst(new RegExp(r'0'), '7', 1); // '0.7001'
447 */
448 String replaceFirst(Pattern from, String to, [int startIndex = 0]);
449
450 /**
451 * Replaces all substrings that match [from] with [replace].
452 *
453 * Returns a new string in which the non-overlapping substrings matching
454 * [from] (the ones iterated by `from.allMatches(thisString)`) are replaced
455 * by the literal string [replace].
456 *
457 * 'resume'.replaceAll(new RegExp(r'e'), 'é'); // 'résumé'
458 *
459 * Notice that the [replace] string is not interpreted. If the replacement
460 * depends on the match (for example on a [RegExp]'s capture groups), use
461 * the [replaceAllMapped] method instead.
462 */
463 String replaceAll(Pattern from, String replace);
464
465 /**
466 * Replace all substrings that match [from] by a string computed from the
467 * match.
468 *
469 * Returns a new string in which the non-overlapping substrings that match
470 * [from] (the ones iterated by `from.allMatches(thisString)`) are replaced
471 * by the result of calling [replace] on the corresponding [Match] object.
472 *
473 * This can be used to replace matches with new content that depends on the
474 * match, unlike [replaceAll] where the replacement string is always the same.
475 *
476 * The [replace] function is called with the [Match] generated
477 * by the pattern, and its result is used as replacement.
478 *
479 * The function defined below converts each word in a string to simplified
480 * 'pig latin' using [replaceAllMapped]:
481 *
482 * pigLatin(String words) => words.replaceAllMapped(
483 * new RegExp(r'\b(\w*?)([aeiou]\w*)', caseSensitive: false),
484 * (Match m) => "${m[2]}${m[1]}${m[1].isEmpty ? 'way' : 'ay'}");
485 *
486 * pigLatin('I have a secret now!'); // 'Iway avehay away ecretsay ownay!'
487 */
488 String replaceAllMapped(Pattern from, String replace(Match match));
489
490 /**
491 * Splits the string at matches of [pattern] and returns a list of substrings.
492 *
493 * Finds all the matches of `pattern` in this string,
494 * and returns the list of the substrings between the matches.
495 *
496 * var string = "Hello world!";
497 * string.split(" "); // ['Hello', 'world!'];
498 *
499 * Empty matches at the beginning and end of the strings are ignored,
500 * and so are empty matches right after another match.
501 *
502 * var string = "abba";
503 * string.split(new RegExp(r"b*")); // ['a', 'a']
504 * // not ['', 'a', 'a', '']
505 *
506 * If this string is empty, the result is an empty list if `pattern` matches
507 * the empty string, and it is `[""]` if the pattern doesn't match.
508 *
509 * var string = '';
510 * string.split(''); // []
511 * string.split("a"); // ['']
512 *
513 * Splitting with an empty pattern splits the string into single-code unit
514 * strings.
515 *
516 * var string = 'Pub';
517 * string.split(''); // ['P', 'u', 'b']
518 *
519 * string.codeUnits.map((unit) {
520 * return new String.fromCharCode(unit);
521 * }).toList(); // ['P', 'u', 'b']
522 *
523 * Splitting happens at UTF-16 code unit boundaries,
524 * and not at rune boundaries:
525 *
526 * // String made up of two code units, but one rune.
527 * string = '\u{1D11E}';
528 * string.split('').length; // 2 surrogate values
529 *
530 * To get a list of strings containing the individual runes of a string,
531 * you should not use split. You can instead map each rune to a string
532 * as follows:
533 *
534 * string.runes.map((rune) => new String.fromCharCode(rune)).toList();
535 */
536 List<String> split(Pattern pattern);
537
538 /**
539 * Splits the string, converts its parts, and combines them into a new
540 * string.
541 *
542 * [pattern] is used to split the string into parts and separating matches.
543 *
544 * Each match is converted to a string by calling [onMatch]. If [onMatch]
545 * is omitted, the matched string is used.
546 *
547 * Each non-matched part is converted by a call to [onNonMatch]. If
548 * [onNonMatch] is omitted, the non-matching part is used.
549 *
550 * Then all the converted parts are combined into the resulting string.
551 *
552 * 'Eats shoots leaves'.splitMapJoin((new RegExp(r'shoots')),
553 * onMatch: (m) => '${m.group(0)}',
554 * onNonMatch: (n) => '*'); // *shoots*
555 */
556 String splitMapJoin(Pattern pattern,
557 {String onMatch(Match match),
558 String onNonMatch(String nonMatch)});
559
560 /**
561 * Returns an unmodifiable list of the UTF-16 code units of this string.
562 */
563 List<int> get codeUnits;
564
565 /**
566 * Returns an [Iterable] of Unicode code-points of this string.
567 *
568 * If the string contains surrogate pairs, they are combined and returned
569 * as one integer by this iterator. Unmatched surrogate halves are treated
570 * like valid 16-bit code-units.
571 */
572 Runes get runes;
573
574 /**
575 * Converts all characters in this string to lower case.
576 * If the string is already in all lower case, this method returns [:this:].
577 *
578 * 'ALPHABET'.toLowerCase(); // 'alphabet'
579 * 'abc'.toLowerCase(); // 'abc'
580 *
581 * This function uses the language independent Unicode mapping and thus only
582 * works in some languages.
583 */
584 // TODO(floitsch): document better. (See EcmaScript for description).
585 String toLowerCase();
586
587 /**
588 * Converts all characters in this string to upper case.
589 * If the string is already in all upper case, this method returns [:this:].
590 *
591 * 'alphabet'.toUpperCase(); // 'ALPHABET'
592 * 'ABC'.toUpperCase(); // 'ABC'
593 *
594 * This function uses the language independent Unicode mapping and thus only
595 * works in some languages.
596 */
597 // TODO(floitsch): document better. (See EcmaScript for description).
598 String toUpperCase();
599
600 static String _stringFromIterable(Iterable<int> charCodes,
601 int start, int end) {
602 if (start < 0) throw new RangeError.range(start, 0, charCodes.length);
603 if (end != null && end < start) {
604 throw new RangeError.range(end, start, charCodes.length);
605 }
606 var it = charCodes.iterator;
607 for (int i = 0; i < start; i++) {
608 if (!it.moveNext()) {
609 throw new RangeError.range(start, 0, i);
610 }
611 }
612 var list = [];
613 if (end == null) {
614 while (it.moveNext()) list.add(it.current);
615 } else {
616 for (int i = start; i < end; i++) {
617 if (!it.moveNext()) {
618 throw new RangeError.range(end, start, i);
619 }
620 list.add(it.current);
621 }
622 }
623 return Primitives.stringFromCharCodes(list);
624 }
625 }
626
627 /**
628 * The runes (integer Unicode code points) of a [String].
629 */
630 class Runes extends IterableBase<int> {
631 final String string;
632 Runes(this.string);
633
634 RuneIterator get iterator => new RuneIterator(string);
635
636 int get last {
637 if (string.length == 0) {
638 throw new StateError('No elements.');
639 }
640 int length = string.length;
641 int code = string.codeUnitAt(length - 1);
642 if (_isTrailSurrogate(code) && string.length > 1) {
643 int previousCode = string.codeUnitAt(length - 2);
644 if (_isLeadSurrogate(previousCode)) {
645 return _combineSurrogatePair(previousCode, code);
646 }
647 }
648 return code;
649 }
650
651 }
652
653 // Is then code (a 16-bit unsigned integer) a UTF-16 lead surrogate.
654 bool _isLeadSurrogate(int code) => (code & 0xFC00) == 0xD800;
655
656 // Is then code (a 16-bit unsigned integer) a UTF-16 trail surrogate.
657 bool _isTrailSurrogate(int code) => (code & 0xFC00) == 0xDC00;
658
659 // Combine a lead and a trail surrogate value into a single code point.
660 int _combineSurrogatePair(int start, int end) {
661 return 0x10000 + ((start & 0x3FF) << 10) + (end & 0x3FF);
662 }
663
664 /** [Iterator] for reading runes (integer Unicode code points) out of a Dart
665 * string.
666 */
667 class RuneIterator implements BidirectionalIterator<int> {
668 /** String being iterated. */
669 final String string;
670 /** Position before the current code point. */
671 int _position;
672 /** Position after the current code point. */
673 int _nextPosition;
674 /**
675 * Current code point.
676 *
677 * If the iterator has hit either end, the [_currentCodePoint] is null
678 * and [: _position == _nextPosition :].
679 */
680 num _currentCodePoint;
681
682 /** Create an iterator positioned at the beginning of the string. */
683 RuneIterator(String string)
684 : this.string = string, _position = 0, _nextPosition = 0;
685
686 /**
687 * Create an iterator positioned before the [index]th code unit of the string.
688 *
689 * When created, there is no [current] value.
690 * A [moveNext] will use the rune starting at [index] the current value,
691 * and a [movePrevious] will use the rune ending just before [index] as the
692 * the current value.
693 *
694 * The [index] position must not be in the middle of a surrogate pair.
695 */
696 RuneIterator.at(String string, int index)
697 : string = string, _position = index, _nextPosition = index {
698 RangeError.checkValueInInterval(index, 0, string.length);
699 _checkSplitSurrogate(index);
700 }
701
702 /** Throw an error if the index is in the middle of a surrogate pair. */
703 void _checkSplitSurrogate(int index) {
704 if (index > 0 && index < string.length &&
705 _isLeadSurrogate(string.codeUnitAt(index - 1)) &&
706 _isTrailSurrogate(string.codeUnitAt(index))) {
707 throw new ArgumentError('Index inside surrogate pair: $index');
708 }
709 }
710
711 /**
712 * Returns the starting position of the current rune in the string.
713 *
714 * Returns null if the [current] rune is null.
715 */
716 int get rawIndex => (_position != _nextPosition) ? _position : null;
717
718 /**
719 * Resets the iterator to the rune at the specified index of the string.
720 *
721 * Setting a negative [rawIndex], or one greater than or equal to
722 * [:string.length:],
723 * is an error. So is setting it in the middle of a surrogate pair.
724 *
725 * Setting the position to the end of then string will set [current] to null.
726 */
727 void set rawIndex(int rawIndex) {
728 RangeError.checkValidIndex(rawIndex, string, "rawIndex");
729 reset(rawIndex);
730 moveNext();
731 }
732
733 /**
734 * Resets the iterator to the given index into the string.
735 *
736 * After this the [current] value is unset.
737 * You must call [moveNext] make the rune at the position current,
738 * or [movePrevious] for the last rune before the position.
739 *
740 * Setting a negative [rawIndex], or one greater than [:string.length:],
741 * is an error. So is setting it in the middle of a surrogate pair.
742 */
743 void reset([int rawIndex = 0]) {
744 RangeError.checkValueInInterval(rawIndex, 0, string.length, "rawIndex");
745 _checkSplitSurrogate(rawIndex);
746 _position = _nextPosition = rawIndex;
747 _currentCodePoint = null;
748 }
749
750 /** The rune (integer Unicode code point) starting at the current position in
751 * the string.
752 */
753 int get current => _currentCodePoint;
754
755 /**
756 * The number of code units comprising the current rune.
757 *
758 * Returns zero if there is no current rune ([current] is null).
759 */
760 int get currentSize => _nextPosition - _position;
761
762 /**
763 * A string containing the current rune.
764 *
765 * For runes outside the basic multilingual plane, this will be
766 * a String of length 2, containing two code units.
767 *
768 * Returns null if [current] is null.
769 */
770 String get currentAsString {
771 if (_position == _nextPosition) return null;
772 if (_position + 1 == _nextPosition) return string[_position];
773 return string.substring(_position, _nextPosition);
774 }
775
776 bool moveNext() {
777 _position = _nextPosition;
778 if (_position == string.length) {
779 _currentCodePoint = null;
780 return false;
781 }
782 int codeUnit = string.codeUnitAt(_position);
783 int nextPosition = _position + 1;
784 if (_isLeadSurrogate(codeUnit) && nextPosition < string.length) {
785 int nextCodeUnit = string.codeUnitAt(nextPosition);
786 if (_isTrailSurrogate(nextCodeUnit)) {
787 _nextPosition = nextPosition + 1;
788 _currentCodePoint = _combineSurrogatePair(codeUnit, nextCodeUnit);
789 return true;
790 }
791 }
792 _nextPosition = nextPosition;
793 _currentCodePoint = codeUnit;
794 return true;
795 }
796
797 bool movePrevious() {
798 _nextPosition = _position;
799 if (_position == 0) {
800 _currentCodePoint = null;
801 return false;
802 }
803 int position = _position - 1;
804 int codeUnit = string.codeUnitAt(position);
805 if (_isTrailSurrogate(codeUnit) && position > 0) {
806 int prevCodeUnit = string.codeUnitAt(position - 1);
807 if (_isLeadSurrogate(prevCodeUnit)) {
808 _position = position - 1;
809 _currentCodePoint = _combineSurrogatePair(prevCodeUnit, codeUnit);
810 return true;
811 }
812 }
813 _position = position;
814 _currentCodePoint = codeUnit;
815 return true;
816 }
817 }
OLDNEW
« no previous file with comments | « test/generated_sdk/lib/core/stopwatch.dart ('k') | test/generated_sdk/lib/core/string_buffer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698