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