| OLD | NEW |
| (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 _js_helper; | |
| 6 | |
| 7 stringIndexOfStringUnchecked(receiver, other, startIndex) { | |
| 8 return JS('int', '#.indexOf(#, #)', receiver, other, startIndex); | |
| 9 } | |
| 10 | |
| 11 substring1Unchecked(receiver, startIndex) { | |
| 12 return JS('String', '#.substring(#)', receiver, startIndex); | |
| 13 } | |
| 14 | |
| 15 substring2Unchecked(receiver, startIndex, endIndex) { | |
| 16 return JS('String', '#.substring(#, #)', receiver, startIndex, endIndex); | |
| 17 } | |
| 18 | |
| 19 stringContainsStringUnchecked(receiver, other, startIndex) { | |
| 20 return stringIndexOfStringUnchecked(receiver, other, startIndex) >= 0; | |
| 21 } | |
| 22 | |
| 23 class StringMatch implements Match { | |
| 24 const StringMatch(int this.start, | |
| 25 String this.input, | |
| 26 String this.pattern); | |
| 27 | |
| 28 int get end => start + pattern.length; | |
| 29 String operator[](int g) => group(g); | |
| 30 int get groupCount => 0; | |
| 31 | |
| 32 String group(int group_) { | |
| 33 if (group_ != 0) { | |
| 34 throw new RangeError.value(group_); | |
| 35 } | |
| 36 return pattern; | |
| 37 } | |
| 38 | |
| 39 List<String> groups(List<int> groups_) { | |
| 40 List<String> result = new List<String>(); | |
| 41 for (int g in groups_) { | |
| 42 result.add(group(g)); | |
| 43 } | |
| 44 return result; | |
| 45 } | |
| 46 | |
| 47 final int start; | |
| 48 final String input; | |
| 49 final String pattern; | |
| 50 } | |
| 51 | |
| 52 List<Match> allMatchesInStringUnchecked(String pattern, String string, | |
| 53 int startIndex) { | |
| 54 // Copied from StringBase.allMatches in | |
| 55 // /runtime/lib/string_base.dart | |
| 56 List<Match> result = new List<Match>(); | |
| 57 int length = string.length; | |
| 58 int patternLength = pattern.length; | |
| 59 while (true) { | |
| 60 int position = stringIndexOfStringUnchecked(string, pattern, startIndex); | |
| 61 if (position == -1) { | |
| 62 break; | |
| 63 } | |
| 64 result.add(new StringMatch(position, string, pattern)); | |
| 65 int endIndex = position + patternLength; | |
| 66 if (endIndex == length) { | |
| 67 break; | |
| 68 } else if (position == endIndex) { | |
| 69 ++startIndex; // empty match, advance and restart | |
| 70 } else { | |
| 71 startIndex = endIndex; | |
| 72 } | |
| 73 } | |
| 74 return result; | |
| 75 } | |
| 76 | |
| 77 stringContainsUnchecked(receiver, other, startIndex) { | |
| 78 if (other is String) { | |
| 79 return stringContainsStringUnchecked(receiver, other, startIndex); | |
| 80 } else if (other is JSSyntaxRegExp) { | |
| 81 return other.hasMatch(receiver.substring(startIndex)); | |
| 82 } else { | |
| 83 var substr = receiver.substring(startIndex); | |
| 84 return other.allMatches(substr).isNotEmpty; | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 stringReplaceJS(receiver, replacer, replacement) { | |
| 89 // The JavaScript String.replace method recognizes replacement | |
| 90 // patterns in the replacement string. Dart does not have that | |
| 91 // behavior. | |
| 92 replacement = JS('String', r'#.replace(/\$/g, "$$$$")', replacement); | |
| 93 return JS('String', r'#.replace(#, #)', receiver, replacer, replacement); | |
| 94 } | |
| 95 | |
| 96 stringReplaceFirstRE(receiver, regexp, replacement, startIndex) { | |
| 97 var match = regexp._execGlobal(receiver, startIndex); | |
| 98 if (match == null) return receiver; | |
| 99 var start = match.start; | |
| 100 var end = match.end; | |
| 101 return stringReplaceRangeUnchecked(receiver, start, end, replacement); | |
| 102 } | |
| 103 | |
| 104 const String ESCAPE_REGEXP = r'[[\]{}()*+?.\\^$|]'; | |
| 105 | |
| 106 stringReplaceAllUnchecked(receiver, pattern, replacement) { | |
| 107 checkString(replacement); | |
| 108 if (pattern is String) { | |
| 109 if (pattern == "") { | |
| 110 if (receiver == "") { | |
| 111 return replacement; | |
| 112 } else { | |
| 113 StringBuffer result = new StringBuffer(); | |
| 114 int length = receiver.length; | |
| 115 result.write(replacement); | |
| 116 for (int i = 0; i < length; i++) { | |
| 117 result.write(receiver[i]); | |
| 118 result.write(replacement); | |
| 119 } | |
| 120 return result.toString(); | |
| 121 } | |
| 122 } else { | |
| 123 var quoter = JS('', "new RegExp(#, 'g')", ESCAPE_REGEXP); | |
| 124 var quoted = JS('String', r'#.replace(#, "\\$&")', pattern, quoter); | |
| 125 var replacer = JS('', "new RegExp(#, 'g')", quoted); | |
| 126 return stringReplaceJS(receiver, replacer, replacement); | |
| 127 } | |
| 128 } else if (pattern is JSSyntaxRegExp) { | |
| 129 var re = regExpGetGlobalNative(pattern); | |
| 130 return stringReplaceJS(receiver, re, replacement); | |
| 131 } else { | |
| 132 checkNull(pattern); | |
| 133 // TODO(floitsch): implement generic String.replace (with patterns). | |
| 134 throw "String.replaceAll(Pattern) UNIMPLEMENTED"; | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 String _matchString(Match match) => match[0]; | |
| 139 String _stringIdentity(String string) => string; | |
| 140 | |
| 141 stringReplaceAllFuncUnchecked(receiver, pattern, onMatch, onNonMatch) { | |
| 142 if (onMatch == null) onMatch = _matchString; | |
| 143 if (onNonMatch == null) onNonMatch = _stringIdentity; | |
| 144 if (pattern is String) { | |
| 145 return stringReplaceAllStringFuncUnchecked(receiver, pattern, | |
| 146 onMatch, onNonMatch); | |
| 147 } | |
| 148 // Placing the Pattern test here is indistingishable from placing it at the | |
| 149 // top of the method but it saves an extra check on the `pattern is String` | |
| 150 // path. | |
| 151 if (pattern is! Pattern) { | |
| 152 throw new ArgumentError.value(pattern, 'pattern', 'is not a Pattern'); | |
| 153 } | |
| 154 StringBuffer buffer = new StringBuffer(); | |
| 155 int startIndex = 0; | |
| 156 for (Match match in pattern.allMatches(receiver)) { | |
| 157 buffer.write(onNonMatch(receiver.substring(startIndex, match.start))); | |
| 158 buffer.write(onMatch(match)); | |
| 159 startIndex = match.end; | |
| 160 } | |
| 161 buffer.write(onNonMatch(receiver.substring(startIndex))); | |
| 162 return buffer.toString(); | |
| 163 } | |
| 164 | |
| 165 stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch) { | |
| 166 // Pattern is the empty string. | |
| 167 StringBuffer buffer = new StringBuffer(); | |
| 168 int length = receiver.length; | |
| 169 int i = 0; | |
| 170 buffer.write(onNonMatch("")); | |
| 171 while (i < length) { | |
| 172 buffer.write(onMatch(new StringMatch(i, receiver, ""))); | |
| 173 // Special case to avoid splitting a surrogate pair. | |
| 174 int code = receiver.codeUnitAt(i); | |
| 175 if ((code & ~0x3FF) == 0xD800 && length > i + 1) { | |
| 176 // Leading surrogate; | |
| 177 code = receiver.codeUnitAt(i + 1); | |
| 178 if ((code & ~0x3FF) == 0xDC00) { | |
| 179 // Matching trailing surrogate. | |
| 180 buffer.write(onNonMatch(receiver.substring(i, i + 2))); | |
| 181 i += 2; | |
| 182 continue; | |
| 183 } | |
| 184 } | |
| 185 buffer.write(onNonMatch(receiver[i])); | |
| 186 i++; | |
| 187 } | |
| 188 buffer.write(onMatch(new StringMatch(i, receiver, ""))); | |
| 189 buffer.write(onNonMatch("")); | |
| 190 return buffer.toString(); | |
| 191 } | |
| 192 | |
| 193 stringReplaceAllStringFuncUnchecked(receiver, pattern, onMatch, onNonMatch) { | |
| 194 int patternLength = pattern.length; | |
| 195 if (patternLength == 0) { | |
| 196 return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch); | |
| 197 } | |
| 198 int length = receiver.length; | |
| 199 StringBuffer buffer = new StringBuffer(); | |
| 200 int startIndex = 0; | |
| 201 while (startIndex < length) { | |
| 202 int position = stringIndexOfStringUnchecked(receiver, pattern, startIndex); | |
| 203 if (position == -1) { | |
| 204 break; | |
| 205 } | |
| 206 buffer.write(onNonMatch(receiver.substring(startIndex, position))); | |
| 207 buffer.write(onMatch(new StringMatch(position, receiver, pattern))); | |
| 208 startIndex = position + patternLength; | |
| 209 } | |
| 210 buffer.write(onNonMatch(receiver.substring(startIndex))); | |
| 211 return buffer.toString(); | |
| 212 } | |
| 213 | |
| 214 | |
| 215 stringReplaceFirstUnchecked(receiver, pattern, replacement, int startIndex) { | |
| 216 if (pattern is String) { | |
| 217 int index = stringIndexOfStringUnchecked(receiver, pattern, startIndex); | |
| 218 if (index < 0) return receiver; | |
| 219 int end = index + pattern.length; | |
| 220 return stringReplaceRangeUnchecked(receiver, index, end, replacement); | |
| 221 } | |
| 222 if (pattern is JSSyntaxRegExp) { | |
| 223 return startIndex == 0 | |
| 224 ? stringReplaceJS(receiver, regExpGetNative(pattern), replacement) | |
| 225 : stringReplaceFirstRE(receiver, pattern, replacement, startIndex); | |
| 226 } | |
| 227 checkNull(pattern); | |
| 228 Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator; | |
| 229 if (!matches.moveNext()) return receiver; | |
| 230 Match match = matches.current; | |
| 231 return receiver.replaceRange(match.start, match.end, replacement); | |
| 232 } | |
| 233 | |
| 234 stringReplaceFirstMappedUnchecked(receiver, pattern, replace, | |
| 235 int startIndex) { | |
| 236 Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator; | |
| 237 if (!matches.moveNext()) return receiver; | |
| 238 Match match = matches.current; | |
| 239 String replacement = "${replace(match)}"; | |
| 240 return receiver.replaceRange(match.start, match.end, replacement); | |
| 241 } | |
| 242 | |
| 243 stringJoinUnchecked(array, separator) { | |
| 244 return JS('String', r'#.join(#)', array, separator); | |
| 245 } | |
| 246 | |
| 247 String stringReplaceRangeUnchecked(String receiver, | |
| 248 int start, int end, String replacement) { | |
| 249 var prefix = JS('String', '#.substring(0, #)', receiver, start); | |
| 250 var suffix = JS('String', '#.substring(#)', receiver, end); | |
| 251 return "$prefix$replacement$suffix"; | |
| 252 } | |
| OLD | NEW |