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

Side by Side Diff: runtime/lib/string.dart

Issue 9689089: Improve the replaceFirst, replaceAll and split methods. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: propertly specify test exceptions Created 8 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « runtime/lib/regexp.dart ('k') | tests/co19/co19-runtime.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « runtime/lib/regexp.dart ('k') | tests/co19/co19-runtime.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698