-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
regexp.dart
271 lines (257 loc) · 9.84 KB
/
regexp.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.core;
/// A regular expression pattern.
///
/// Regular expressions are [Pattern]s, and can as such be used to match strings
/// or parts of strings.
///
/// Dart regular expressions have the same syntax and semantics as
/// JavaScript regular expressions. See
/// <https://ecma-international.org/ecma-262/9.0/#sec-regexp-regular-expression-objects>
/// for the specification of JavaScript regular expressions.
///
/// The [firstMatch] method is the main implementation method
/// that applies a regular expression to a string
/// and returns the first [RegExpMatch].
/// All other methods in [RegExp] can be build from that.
///
/// The following example finds the first match of a regular expression in
/// a string.
/// ```dart
/// RegExp exp = RegExp(r'(\w+)');
/// String str = 'Parse my string';
/// RegExpMatch? match = exp.firstMatch(str);
/// print(match![0]); // "Parse"
/// ```
/// Use [allMatches] to look for all matches of a regular expression in
/// a string.
///
/// The following example finds all matches of a regular expression in
/// a string.
/// ```dart
/// RegExp exp = RegExp(r'(\w+)');
/// String str = 'Parse my string';
/// Iterable<RegExpMatch> matches = exp.allMatches(str);
/// for (final m in matches) {
/// print(m[0]);
/// }
/// ```
/// The output of the example is:
/// ```
/// Parse
/// my
/// string
/// ```
///
/// Note the use of a _raw string_ (a string prefixed with `r`)
/// in the example above. Use a raw string to treat each character in a string
/// as a literal character.
abstract class RegExp implements Pattern {
/// Constructs a regular expression.
///
/// Throws a [FormatException] if [source] is not valid regular
/// expression syntax.
///
/// If `multiLine` is enabled, then `^` and `$` will match the beginning and
/// end of a _line_, in addition to matching beginning and end of input,
/// respectively.
///
/// If `caseSensitive` is disabled, then case is ignored.
///
/// If `unicode` is enabled, then the pattern is treated as a Unicode
/// pattern as described by the ECMAScript standard.
///
/// If `dotAll` is enabled, then the `.` pattern will match _all_ characters,
/// including line terminators.
///
/// Example:
///
/// ```dart
/// final wordPattern = RegExp(r'(\w+)');
/// final digitPattern = RegExp(r'(\d+)');
/// ```
///
/// Notice the use of a _raw string_ in the first example, and a regular
/// string in the second. Because of the many escapes, like `\d`, used in
/// regular expressions, it is common to use a raw string here, unless string
/// interpolation is required.
external factory RegExp(String source,
{bool multiLine = false,
bool caseSensitive = true,
@Since("2.4") bool unicode = false,
@Since("2.4") bool dotAll = false});
/// Creates regular expression syntax that matches [text].
///
/// If [text] contains characters that are meaningful in regular expressions,
/// the resulting regular expression will match those characters literally.
/// If [text] contains no characters that have special meaning in a regular
/// expression, it is returned unmodified.
///
/// The characters that have special meaning in regular expressions are:
/// `(`, `)`, `[`, `]`, `{`, `}`, `*`, `+`, `?`, `.`, `^`, `$`, `|` and `\`.
///
/// This method is mainly used to create a pattern to be included in a
/// larger regular expression. Since a [String] is itself a [Pattern]
/// which matches itself, converting the string to a regular expression
/// isn't needed in order to search for just that string.
/// ```dart
/// print(RegExp.escape('dash@example.com')); // dash@example\.com
/// print(RegExp.escape('a+b')); // a\+b
/// print(RegExp.escape('a*b')); // a\*b
/// print(RegExp.escape('{a-b}')); // \{a-b\}
/// print(RegExp.escape('a?')); // a\?
/// ```
external static String escape(String text);
/// Finds the first match of the regular expression in the string [input].
///
/// Returns `null` if there is no match.
/// ```dart
/// final string = '[00:13.37] This is a chat message.';
/// final regExp = RegExp(r'c\w*');
/// final match = regExp.firstMatch(string)!;
/// print(match[0]); // chat
/// ```
RegExpMatch? firstMatch(String input);
Iterable<RegExpMatch> allMatches(String input, [int start = 0]);
/// Whether the regular expression has a match in the string [input].
/// ```dart
/// var string = 'Dash is a bird';
/// var regExp = RegExp(r'(humming)?bird');
/// var match = regExp.hasMatch(string); // true
///
/// regExp = RegExp(r'dog');
/// match = regExp.hasMatch(string); // false
/// ```
bool hasMatch(String input);
/// The substring of the first match of this regular expression in [input].
/// ```dart
/// var string = 'Dash is a bird';
/// var regExp = RegExp(r'(humming)?bird');
/// var match = regExp.stringMatch(string); // Match
///
/// regExp = RegExp(r'dog');
/// match = regExp.stringMatch(string); // No match
/// ```
String? stringMatch(String input);
/// The source regular expression string used to create this `RegExp`.
/// ```dart
/// final regExp = RegExp(r'\p{L}');
/// print(regExp.pattern); // \p{L}
/// ```
String get pattern;
/// Whether this regular expression matches multiple lines.
///
/// If the regexp does match multiple lines, the "^" and "$" characters
/// match the beginning and end of lines. If not, the characters match the
/// beginning and end of the input.
bool get isMultiLine;
/// Whether this regular expression is case sensitive.
///
/// If the regular expression is not case sensitive, it will match an input
/// letter with a pattern letter even if the two letters are different case
/// versions of the same letter.
/// ```dart
/// final str = 'Parse my string';
/// var regExp = RegExp(r'STRING', caseSensitive: false);
/// final hasMatch = regExp.hasMatch(str); // Has matches.
/// print(regExp.isCaseSensitive); // false
///
/// regExp = RegExp(r'STRING', caseSensitive: true);
/// final hasCaseSensitiveMatch = regExp.hasMatch(str); // No matches.
/// print(regExp.isCaseSensitive); // true
/// ```
bool get isCaseSensitive;
/// Whether this regular expression is in Unicode mode.
///
/// In Unicode mode, UTF-16 surrogate pairs in the original string will be
/// treated as a single code point and will not match separately. Otherwise,
/// the target string will be treated purely as a sequence of individual code
/// units and surrogates will not be treated specially.
///
/// In Unicode mode, the syntax of the RegExp pattern is more restricted, but
/// some pattern features, like Unicode property escapes, are only available in
/// this mode.
/// ```dart
/// var regExp = RegExp(r'^\p{L}$', unicode: true);
/// print(regExp.hasMatch('a')); // true
/// print(regExp.hasMatch('b')); // true
/// print(regExp.hasMatch('?')); // false
/// print(regExp.hasMatch(r'p{L}')); // false
///
/// regExp = RegExp(r'^\p{L}$', unicode: false);
/// print(regExp.hasMatch('a')); // false
/// print(regExp.hasMatch('b')); // false
/// print(regExp.hasMatch('?')); // false
/// print(regExp.hasMatch(r'p{L}')); // true
/// ```
@Since("2.4")
bool get isUnicode;
/// Whether "." in this regular expression matches line terminators.
///
/// When false, the "." character matches a single character, unless that
/// character is a line terminator. When true, then the "." character will
/// match any single character including line terminators.
///
/// This feature is distinct from [isMultiLine], as they affect the behavior
/// of different pattern characters, and so they can be used together or
/// separately.
@Since("2.4")
bool get isDotAll;
}
/// A regular expression match.
///
/// Regular expression matches are [Match]es, but also include the ability
/// to retrieve the names for any named capture groups and to retrieve
/// matches for named capture groups by name instead of their index.
///
/// Example:
/// ```dart
/// const pattern =
/// r'^\[(?<Time>\s*((?<hour>\d+)):((?<minute>\d+))\.((?<second>\d+)))\]'
/// r'\s(?<Message>\s*(.*)$)';
///
/// final regExp = RegExp(
/// pattern,
/// multiLine: true,
/// );
///
/// const multilineText = '[00:13.37] This is a first message.\n'
/// '[01:15.57] This is a second message.\n';
///
/// RegExpMatch regExpMatch = regExp.firstMatch(multilineText)!;
/// print(regExpMatch.groupNames.join('-')); // hour-minute-second-Time-Message.
/// final time = regExpMatch.namedGroup('Time'); // 00:13.37
/// final hour = regExpMatch.namedGroup('hour'); // 00
/// final minute = regExpMatch.namedGroup('minute'); // 13
/// final second = regExpMatch.namedGroup('second'); // 37
/// final message =
/// regExpMatch.namedGroup('Message'); // This is a first message.
/// final date = regExpMatch.namedGroup('Date'); // Undefined `Date`, throws.
///
/// Iterable<RegExpMatch> matches = regExp.allMatches(multilineText);
/// for (final m in matches) {
/// print(m.namedGroup('Time'));
/// print(m.namedGroup('Message'));
/// // 00:13.37
/// // This is a first message.
/// // 01:15.57
/// // This is a second message.
/// }
/// ```
@Since("2.3")
abstract class RegExpMatch implements Match {
/// The string matched by the group named [name].
///
/// Returns the string matched by the capture group named [name], or
/// `null` if no string was matched by that capture group as part of
/// this match.
///
/// The [name] must be the name of a named capture group in the regular
/// expression creating this match (that is, the name must be in
/// [groupNames]).
String? namedGroup(String name);
/// The names of the captured groups in the match.
Iterable<String> get groupNames;
}