Chromium Code Reviews| Index: sdk/lib/core/string.dart |
| diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart |
| index 7f2dcbd48b4fc51306c3fcf896c0c1c91a876b14..e685523b4e98caced7f2e3e03f777a66403ee7b0 100644 |
| --- a/sdk/lib/core/string.dart |
| +++ b/sdk/lib/core/string.dart |
| @@ -189,3 +189,97 @@ abstract class String implements Comparable, Pattern { |
| */ |
| String toUpperCase(); |
| } |
| + |
| +class Runes implements Iterable<int> { |
| + String _string; |
| + Runes(this._string); |
| + RuneIterator get iterator => new RuneIterator(_string); |
| +} |
| + |
| +/** [Iterator] for reading Unicode code points out of a Dart string. */ |
| +class RuneIterator implements BiDirectionalIterator<int> { |
| + /** String being iterated. */ |
| + final String _string; |
| + /** Position before the current code point. */ |
| + int _position; |
| + /** Position after the current code point. */ |
| + int _nextPosition; |
| + /** |
| + * Current code point. |
| + * |
| + * If the iterator has hit either end, the [_currentCodePoint] is null |
| + * and [: _position == _nextPosition :]. |
| + */ |
| + int _currentCodePoint; |
| + |
| + /** Create an iterator positioned at the beginning of the string. */ |
| + RuneIterator(String string) |
| + : _string = string, _position = 0, _nextPosition = 0; |
| + |
| + /** |
| + * Create an iterator positioned before the [start]th code unit of the string. |
| + * |
| + * A [moveNext] will make the following code point the current value, and a |
| + * [movePrevious] will make the preceding code pount the current value. |
| + * |
| + * If the [start] position is in the middle of a surrogate pair, then the |
| + * first result in either direction will be an unmatched surrogate. |
| + */ |
| + RuneIterator.at(String string, int start) |
| + : _string = string, _position = start, _nextPosition = start { |
| + if (start < 0 || start > string.length) { |
| + throw new RangeError.range(start, 0, string.length); |
| + } |
| + } |
| + |
| + int get current => _currentCodePoint; |
| + |
| + bool moveNext() { |
|
erikcorry
2013/01/30 13:26:55
This one is factored into two functions, whereas t
Lasse Reichstein Nielsen
2013/01/30 14:03:37
ACK. I was using _readCharForward in the .at const
|
| + _position = _nextPosition; |
| + if (_position == _string.length) { |
| + _currentCodePoint = null; |
| + return false; |
| + } |
| + _readCharForward(); |
| + return true; |
| + } |
| + |
| + // Decodes code units at _position, updates _currentCodePoint, _nextPosition. |
| + void _readCharForward() { |
| + int codeUnit = _string.charCodeAt(_position); |
| + int nextPosition = _position + 1; |
| + if ((codeUnit & 0xFC00) == 0xD800 && nextPosition < _string.length) { |
| + int nextCodeUnit = _string.charCodeAt(nextPosition); |
| + if ((nextCodeUnit & 0xFC00) == 0xDC00) { |
| + _nextPosition = nextPosition + 1; |
| + _currentCodePoint = |
| + 0x10000 + ((nextCodeUnit & 0x3FF) << 10) | (codeUnit & 0x3FF); |
|
Lasse Reichstein Nielsen
2013/01/30 14:03:37
Good catch, these two are swapped (copy-n-paste bu
|
| + return; |
| + } |
| + } |
| + _nextPosition = nextPosition; |
| + _currentCodePoint = codeUnit; |
| + } |
| + |
| + bool movePrevious() { |
| + if (_position == 0) { |
| + _currentCodePoint = null; |
| + return false; |
| + } |
| + int position = _position - 1; |
| + _nextPosition = _position; |
| + int codeUnit = _string.charCodeAt(position); |
| + if ((codeUnit & 0xFC00) == 0xDC00 && position > 0) { |
| + int prevCodeUnit = _string.charCodeAt(position - 1); |
| + if ((prevCodeUnit & 0xFC00) == 0xD800) { |
| + _position = position - 1; |
| + _currentCodePoint = |
| + 0x10000 + ((prevCodeUnit & 0x3FF) << 10) | (codeUnit & 0x3FF); |
| + return true; |
| + } |
| + } |
| + _position = position; |
| + _currentCodePoint = codeUnit; |
| + return true; |
| + } |
| +} |