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