OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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 part of dart.core; | 5 part of dart.core; |
6 | 6 |
7 /** | 7 /** |
8 * The String class represents character strings. Strings are | 8 * The String class represents character strings. Strings are |
9 * immutable. A string is represented by a list of 32-bit Unicode | 9 * immutable. A string is represented by a list of 32-bit Unicode |
10 * scalar character codes accessible through the [charCodeAt] or the | 10 * scalar character codes accessible through the [charCodeAt] or the |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
182 * where all characters are made lower case. Returns [:this:] otherwise. | 182 * where all characters are made lower case. Returns [:this:] otherwise. |
183 */ | 183 */ |
184 String toLowerCase(); | 184 String toLowerCase(); |
185 | 185 |
186 /** | 186 /** |
187 * If this string is not already all uper case, returns a new string | 187 * If this string is not already all uper case, returns a new string |
188 * where all characters are made upper case. Returns [:this:] otherwise. | 188 * where all characters are made upper case. Returns [:this:] otherwise. |
189 */ | 189 */ |
190 String toUpperCase(); | 190 String toUpperCase(); |
191 } | 191 } |
192 | |
193 class Runes implements Iterable<int> { | |
194 String _string; | |
195 Runes(this._string); | |
196 RuneIterator get iterator => new RuneIterator(_string); | |
197 } | |
198 | |
199 /** [Iterator] for reading Unicode code points out of a Dart string. */ | |
200 class RuneIterator implements BiDirectionalIterator<int> { | |
201 /** String being iterated. */ | |
202 final String _string; | |
203 /** Position before the current code point. */ | |
204 int _position; | |
205 /** Position after the current code point. */ | |
206 int _nextPosition; | |
207 /** | |
208 * Current code point. | |
209 * | |
210 * If the iterator has hit either end, the [_currentCodePoint] is null | |
211 * and [: _position == _nextPosition :]. | |
212 */ | |
213 int _currentCodePoint; | |
214 | |
215 /** Create an iterator positioned at the beginning of the string. */ | |
216 RuneIterator(String string) | |
217 : _string = string, _position = 0, _nextPosition = 0; | |
218 | |
219 /** | |
220 * Create an iterator positioned before the [start]th code unit of the string. | |
221 * | |
222 * A [moveNext] will make the following code point the current value, and a | |
223 * [movePrevious] will make the preceding code pount the current value. | |
224 * | |
225 * If the [start] position is in the middle of a surrogate pair, then the | |
226 * first result in either direction will be an unmatched surrogate. | |
227 */ | |
228 RuneIterator.at(String string, int start) | |
229 : _string = string, _position = start, _nextPosition = start { | |
230 if (start < 0 || start > string.length) { | |
231 throw new RangeError.range(start, 0, string.length); | |
232 } | |
233 } | |
234 | |
235 int get current => _currentCodePoint; | |
236 | |
237 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
| |
238 _position = _nextPosition; | |
239 if (_position == _string.length) { | |
240 _currentCodePoint = null; | |
241 return false; | |
242 } | |
243 _readCharForward(); | |
244 return true; | |
245 } | |
246 | |
247 // Decodes code units at _position, updates _currentCodePoint, _nextPosition. | |
248 void _readCharForward() { | |
249 int codeUnit = _string.charCodeAt(_position); | |
250 int nextPosition = _position + 1; | |
251 if ((codeUnit & 0xFC00) == 0xD800 && nextPosition < _string.length) { | |
252 int nextCodeUnit = _string.charCodeAt(nextPosition); | |
253 if ((nextCodeUnit & 0xFC00) == 0xDC00) { | |
254 _nextPosition = nextPosition + 1; | |
255 _currentCodePoint = | |
256 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
| |
257 return; | |
258 } | |
259 } | |
260 _nextPosition = nextPosition; | |
261 _currentCodePoint = codeUnit; | |
262 } | |
263 | |
264 bool movePrevious() { | |
265 if (_position == 0) { | |
266 _currentCodePoint = null; | |
267 return false; | |
268 } | |
269 int position = _position - 1; | |
270 _nextPosition = _position; | |
271 int codeUnit = _string.charCodeAt(position); | |
272 if ((codeUnit & 0xFC00) == 0xDC00 && position > 0) { | |
273 int prevCodeUnit = _string.charCodeAt(position - 1); | |
274 if ((prevCodeUnit & 0xFC00) == 0xD800) { | |
275 _position = position - 1; | |
276 _currentCodePoint = | |
277 0x10000 + ((prevCodeUnit & 0x3FF) << 10) | (codeUnit & 0x3FF); | |
278 return true; | |
279 } | |
280 } | |
281 _position = position; | |
282 _currentCodePoint = codeUnit; | |
283 return true; | |
284 } | |
285 } | |
OLD | NEW |