re2 1.18.2 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +1 -1
- package/README.md +3 -0
- package/lib/accessors.cc +17 -1
- package/lib/addon.cc +3 -2
- package/lib/exec.cc +57 -10
- package/lib/match.cc +70 -7
- package/lib/new.cc +7 -1
- package/lib/replace.cc +23 -5
- package/lib/wrapped_re2.h +4 -2
- package/package.json +1 -1
- package/tests/test_exec.js +91 -9
- package/tests/test_match.js +119 -95
- package/tests/test_replace.js +58 -4
package/.prettierrc
CHANGED
package/README.md
CHANGED
|
@@ -58,6 +58,7 @@ Supported properties:
|
|
|
58
58
|
* [`re2.unicode`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode)
|
|
59
59
|
* `RE2` engine always works in the Unicode mode. See details below.
|
|
60
60
|
* [`re2.sticky`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/sticky)
|
|
61
|
+
* *Since 1.19.0*: [`re2.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices)
|
|
61
62
|
* [`re2.source`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/source)
|
|
62
63
|
* [`re2.flags`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags)
|
|
63
64
|
|
|
@@ -352,6 +353,8 @@ console.log('re2_res : ' + re2_res); // prints: re2_res : abc,a,b,c
|
|
|
352
353
|
|
|
353
354
|
## Release history
|
|
354
355
|
|
|
356
|
+
- 1.19.0 *Added `hasIndices` AKA the `d` flag. Thx, [teebu](https://github.com/teebu).*
|
|
357
|
+
- 1.18.3 *Fixed bug with non-matched groups. Thx, [Dan Setterquist](https://github.com/dset).*
|
|
355
358
|
- 1.18.2 *Reference to the binary module by its full name.*
|
|
356
359
|
- 1.18.1 *Support for Node 16, 18, 20 + Darwin arm64 precompiled binaries.*
|
|
357
360
|
- 1.18.0 *Modified TS bindings, added a type test (thx, [Kenichi Kamiya](https://github.com/kachick) and [Jamie Magee](https://github.com/JamieMagee)).*
|
package/lib/accessors.cc
CHANGED
|
@@ -39,9 +39,13 @@ NAN_GETTER(WrappedRE2::GetFlags)
|
|
|
39
39
|
auto re2 = Nan::ObjectWrap::Unwrap<WrappedRE2>(info.This());
|
|
40
40
|
|
|
41
41
|
std::string flags;
|
|
42
|
+
if (re2->hasIndices)
|
|
43
|
+
{
|
|
44
|
+
flags = "d";
|
|
45
|
+
}
|
|
42
46
|
if (re2->global)
|
|
43
47
|
{
|
|
44
|
-
flags
|
|
48
|
+
flags += "g";
|
|
45
49
|
}
|
|
46
50
|
if (re2->ignoreCase)
|
|
47
51
|
{
|
|
@@ -135,6 +139,18 @@ NAN_GETTER(WrappedRE2::GetSticky)
|
|
|
135
139
|
info.GetReturnValue().Set(re2->sticky);
|
|
136
140
|
}
|
|
137
141
|
|
|
142
|
+
NAN_GETTER(WrappedRE2::GetHasIndices)
|
|
143
|
+
{
|
|
144
|
+
if (!WrappedRE2::HasInstance(info.This()))
|
|
145
|
+
{
|
|
146
|
+
info.GetReturnValue().SetUndefined();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
auto re2 = Nan::ObjectWrap::Unwrap<WrappedRE2>(info.This());
|
|
151
|
+
info.GetReturnValue().Set(re2->hasIndices);
|
|
152
|
+
}
|
|
153
|
+
|
|
138
154
|
NAN_GETTER(WrappedRE2::GetLastIndex)
|
|
139
155
|
{
|
|
140
156
|
if (!WrappedRE2::HasInstance(info.This()))
|
package/lib/addon.cc
CHANGED
|
@@ -23,9 +23,9 @@ static NAN_METHOD(GetUtf16Length)
|
|
|
23
23
|
info.GetReturnValue().Set(-1);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
static void cleanup(void*
|
|
26
|
+
static void cleanup(void *p)
|
|
27
27
|
{
|
|
28
|
-
v8::Isolate*
|
|
28
|
+
v8::Isolate *isolate = static_cast<v8::Isolate *>(p);
|
|
29
29
|
auto p_tpl = Nan::GetIsolateData<Nan::Persistent<v8::FunctionTemplate>>(isolate);
|
|
30
30
|
delete p_tpl;
|
|
31
31
|
}
|
|
@@ -71,6 +71,7 @@ v8::Local<v8::Function> WrappedRE2::Init()
|
|
|
71
71
|
Nan::SetAccessor(instanceTemplate, Nan::New("dotAll").ToLocalChecked(), GetDotAll);
|
|
72
72
|
Nan::SetAccessor(instanceTemplate, Nan::New("unicode").ToLocalChecked(), GetUnicode);
|
|
73
73
|
Nan::SetAccessor(instanceTemplate, Nan::New("sticky").ToLocalChecked(), GetSticky);
|
|
74
|
+
Nan::SetAccessor(instanceTemplate, Nan::New("hasIndices").ToLocalChecked(), GetHasIndices);
|
|
74
75
|
Nan::SetAccessor(instanceTemplate, Nan::New("lastIndex").ToLocalChecked(), GetLastIndex, SetLastIndex);
|
|
75
76
|
Nan::SetAccessor(instanceTemplate, Nan::New("internalSource").ToLocalChecked(), GetInternalSource);
|
|
76
77
|
|
package/lib/exec.cc
CHANGED
|
@@ -52,8 +52,9 @@ NAN_METHOD(WrappedRE2::Exec)
|
|
|
52
52
|
{
|
|
53
53
|
size_t s = getUtf8CharSize(str.data[lastIndex]);
|
|
54
54
|
lastIndex += s;
|
|
55
|
-
if (s == 4 && n >= 2)
|
|
56
|
-
|
|
55
|
+
if (s == 4 && n >= 2)
|
|
56
|
+
--n; // this utf8 character will take two utf16 characters
|
|
57
|
+
// the decrement above is protected to avoid an overflow of an unsigned integer
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
}
|
|
@@ -74,7 +75,7 @@ NAN_METHOD(WrappedRE2::Exec)
|
|
|
74
75
|
|
|
75
76
|
// form a result
|
|
76
77
|
|
|
77
|
-
auto result = Nan::New<v8::Array>();
|
|
78
|
+
auto result = Nan::New<v8::Array>(), indices = Nan::New<v8::Array>();
|
|
78
79
|
int indexOffset = re2->global || re2->sticky ? re2->lastIndex : 0;
|
|
79
80
|
|
|
80
81
|
if (str.isBuffer)
|
|
@@ -82,13 +83,24 @@ NAN_METHOD(WrappedRE2::Exec)
|
|
|
82
83
|
for (size_t i = 0, n = groups.size(); i < n; ++i)
|
|
83
84
|
{
|
|
84
85
|
const auto &item = groups[i];
|
|
85
|
-
|
|
86
|
+
const auto data = item.data();
|
|
87
|
+
if (data)
|
|
86
88
|
{
|
|
87
|
-
Nan::Set(result, i, Nan::CopyBuffer(
|
|
89
|
+
Nan::Set(result, i, Nan::CopyBuffer(data, item.size()).ToLocalChecked());
|
|
90
|
+
if (re2->hasIndices) {
|
|
91
|
+
auto pair = Nan::New<v8::Array>();
|
|
92
|
+
auto offset = data - str.data;
|
|
93
|
+
Nan::Set(pair, 0, Nan::New<v8::Integer>(static_cast<int>(offset)));
|
|
94
|
+
Nan::Set(pair, 1, Nan::New<v8::Integer>(static_cast<int>(offset + item.size())));
|
|
95
|
+
Nan::Set(indices, i, pair);
|
|
96
|
+
}
|
|
88
97
|
}
|
|
89
98
|
else
|
|
90
99
|
{
|
|
91
100
|
Nan::Set(result, i, Nan::Undefined());
|
|
101
|
+
if (re2->hasIndices) {
|
|
102
|
+
Nan::Set(indices, i, Nan::Undefined());
|
|
103
|
+
}
|
|
92
104
|
}
|
|
93
105
|
}
|
|
94
106
|
Nan::Set(result, Nan::New("index").ToLocalChecked(), Nan::New<v8::Integer>(indexOffset + static_cast<int>(groups[0].data() - str.data)));
|
|
@@ -98,18 +110,35 @@ NAN_METHOD(WrappedRE2::Exec)
|
|
|
98
110
|
for (size_t i = 0, n = groups.size(); i < n; ++i)
|
|
99
111
|
{
|
|
100
112
|
const auto &item = groups[i];
|
|
101
|
-
|
|
113
|
+
const auto data = item.data();
|
|
114
|
+
if (data)
|
|
102
115
|
{
|
|
103
|
-
Nan::Set(result, i, Nan::New(
|
|
116
|
+
Nan::Set(result, i, Nan::New(data, item.size()).ToLocalChecked());
|
|
117
|
+
if (re2->hasIndices) {
|
|
118
|
+
auto pair = Nan::New<v8::Array>();
|
|
119
|
+
auto offset = getUtf16Length(str.data + lastIndex, data);
|
|
120
|
+
auto length = getUtf16Length(data, data + item.size());
|
|
121
|
+
Nan::Set(pair, 0, Nan::New<v8::Integer>(static_cast<int>(offset)));
|
|
122
|
+
Nan::Set(pair, 1, Nan::New<v8::Integer>(static_cast<int>(offset + length)));
|
|
123
|
+
Nan::Set(indices, i, pair);
|
|
124
|
+
}
|
|
104
125
|
}
|
|
105
126
|
else
|
|
106
127
|
{
|
|
107
128
|
Nan::Set(result, i, Nan::Undefined());
|
|
129
|
+
if (re2->hasIndices) {
|
|
130
|
+
Nan::Set(indices, i, Nan::Undefined());
|
|
131
|
+
}
|
|
108
132
|
}
|
|
109
133
|
}
|
|
110
134
|
Nan::Set(result, Nan::New("index").ToLocalChecked(), Nan::New<v8::Integer>(indexOffset + static_cast<int>(getUtf16Length(str.data + lastIndex, groups[0].data()))));
|
|
111
135
|
}
|
|
112
136
|
|
|
137
|
+
if (re2->global || re2->sticky)
|
|
138
|
+
{
|
|
139
|
+
re2->lastIndex += str.isBuffer ? groups[0].data() - str.data + groups[0].size() - lastIndex : getUtf16Length(str.data + lastIndex, groups[0].data() + groups[0].size());
|
|
140
|
+
}
|
|
141
|
+
|
|
113
142
|
Nan::Set(result, Nan::New("input").ToLocalChecked(), info[0]);
|
|
114
143
|
|
|
115
144
|
const auto &groupNames = re2->regexp.CapturingGroupNames();
|
|
@@ -128,15 +157,33 @@ NAN_METHOD(WrappedRE2::Exec)
|
|
|
128
157
|
}
|
|
129
158
|
|
|
130
159
|
Nan::Set(result, Nan::New("groups").ToLocalChecked(), groups);
|
|
160
|
+
|
|
161
|
+
if (re2->hasIndices) {
|
|
162
|
+
auto indexGroups = Nan::New<v8::Object>();
|
|
163
|
+
Nan::SetPrototype(indexGroups, Nan::Null());
|
|
164
|
+
|
|
165
|
+
for (auto group : groupNames)
|
|
166
|
+
{
|
|
167
|
+
auto value = Nan::Get(indices, group.first);
|
|
168
|
+
if (!value.IsEmpty())
|
|
169
|
+
{
|
|
170
|
+
Nan::Set(indexGroups, Nan::New(group.second).ToLocalChecked(), value.ToLocalChecked());
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
Nan::Set(indices, Nan::New("groups").ToLocalChecked(), indexGroups);
|
|
175
|
+
}
|
|
131
176
|
}
|
|
132
177
|
else
|
|
133
178
|
{
|
|
134
179
|
Nan::Set(result, Nan::New("groups").ToLocalChecked(), Nan::Undefined());
|
|
180
|
+
if (re2->hasIndices) {
|
|
181
|
+
Nan::Set(indices, Nan::New("groups").ToLocalChecked(), Nan::Undefined());
|
|
182
|
+
}
|
|
135
183
|
}
|
|
136
184
|
|
|
137
|
-
if (re2->
|
|
138
|
-
|
|
139
|
-
re2->lastIndex += str.isBuffer ? groups[0].data() - str.data + groups[0].size() - lastIndex : getUtf16Length(str.data + lastIndex, groups[0].data() + groups[0].size());
|
|
185
|
+
if (re2->hasIndices) {
|
|
186
|
+
Nan::Set(result, Nan::New("indices").ToLocalChecked(), indices);
|
|
140
187
|
}
|
|
141
188
|
|
|
142
189
|
info.GetReturnValue().Set(result);
|
package/lib/match.cc
CHANGED
|
@@ -61,8 +61,9 @@ NAN_METHOD(WrappedRE2::Match)
|
|
|
61
61
|
{
|
|
62
62
|
size_t s = getUtf8CharSize(a.data[lastIndex]);
|
|
63
63
|
lastIndex += s;
|
|
64
|
-
if (s == 4 && n >= 2)
|
|
65
|
-
|
|
64
|
+
if (s == 4 && n >= 2)
|
|
65
|
+
--n; // this utf8 character will take two utf16 characters
|
|
66
|
+
// the decrement above is protected to avoid an overflow of an unsigned integer
|
|
66
67
|
}
|
|
67
68
|
anchor = RE2::ANCHOR_START;
|
|
68
69
|
}
|
|
@@ -81,16 +82,34 @@ NAN_METHOD(WrappedRE2::Match)
|
|
|
81
82
|
|
|
82
83
|
// form a result
|
|
83
84
|
|
|
84
|
-
auto result = Nan::New<v8::Array>();
|
|
85
|
+
auto result = Nan::New<v8::Array>(), indices = Nan::New<v8::Array>();
|
|
85
86
|
|
|
86
87
|
if (a.isBuffer)
|
|
87
88
|
{
|
|
88
89
|
for (size_t i = 0, n = groups.size(); i < n; ++i)
|
|
89
90
|
{
|
|
90
91
|
const auto &item = groups[i];
|
|
91
|
-
|
|
92
|
+
const auto data = item.data();
|
|
93
|
+
if (data)
|
|
92
94
|
{
|
|
93
|
-
Nan::Set(result, i, Nan::CopyBuffer(
|
|
95
|
+
Nan::Set(result, i, Nan::CopyBuffer(data, item.size()).ToLocalChecked());
|
|
96
|
+
if (!re2->global && re2->hasIndices)
|
|
97
|
+
{
|
|
98
|
+
auto pair = Nan::New<v8::Array>();
|
|
99
|
+
auto offset = getUtf16Length(a.data + lastIndex, data);
|
|
100
|
+
auto length = getUtf16Length(data, data + item.size());
|
|
101
|
+
Nan::Set(pair, 0, Nan::New<v8::Integer>(static_cast<int>(offset)));
|
|
102
|
+
Nan::Set(pair, 1, Nan::New<v8::Integer>(static_cast<int>(offset + length)));
|
|
103
|
+
Nan::Set(indices, i, pair);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else
|
|
107
|
+
{
|
|
108
|
+
Nan::Set(result, i, Nan::Undefined());
|
|
109
|
+
if (!re2->global && re2->hasIndices)
|
|
110
|
+
{
|
|
111
|
+
Nan::Set(indices, i, Nan::Undefined());
|
|
112
|
+
}
|
|
94
113
|
}
|
|
95
114
|
}
|
|
96
115
|
if (!re2->global)
|
|
@@ -104,9 +123,27 @@ NAN_METHOD(WrappedRE2::Match)
|
|
|
104
123
|
for (size_t i = 0, n = groups.size(); i < n; ++i)
|
|
105
124
|
{
|
|
106
125
|
const auto &item = groups[i];
|
|
107
|
-
|
|
126
|
+
const auto data = item.data();
|
|
127
|
+
if (data)
|
|
108
128
|
{
|
|
109
|
-
Nan::Set(result, i, Nan::New(
|
|
129
|
+
Nan::Set(result, i, Nan::New(data, item.size()).ToLocalChecked());
|
|
130
|
+
if (!re2->global && re2->hasIndices)
|
|
131
|
+
{
|
|
132
|
+
auto pair = Nan::New<v8::Array>();
|
|
133
|
+
auto offset = getUtf16Length(a.data + lastIndex, data);
|
|
134
|
+
auto length = getUtf16Length(data, data + item.size());
|
|
135
|
+
Nan::Set(pair, 0, Nan::New<v8::Integer>(static_cast<int>(offset)));
|
|
136
|
+
Nan::Set(pair, 1, Nan::New<v8::Integer>(static_cast<int>(offset + length)));
|
|
137
|
+
Nan::Set(indices, i, pair);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else
|
|
141
|
+
{
|
|
142
|
+
Nan::Set(result, i, Nan::Undefined());
|
|
143
|
+
if (!re2->global && re2->hasIndices)
|
|
144
|
+
{
|
|
145
|
+
Nan::Set(indices, i, Nan::Undefined());
|
|
146
|
+
}
|
|
110
147
|
}
|
|
111
148
|
}
|
|
112
149
|
if (!re2->global)
|
|
@@ -143,12 +180,38 @@ NAN_METHOD(WrappedRE2::Match)
|
|
|
143
180
|
}
|
|
144
181
|
|
|
145
182
|
Nan::Set(result, Nan::New("groups").ToLocalChecked(), groups);
|
|
183
|
+
|
|
184
|
+
if (re2->hasIndices)
|
|
185
|
+
{
|
|
186
|
+
auto indexGroups = Nan::New<v8::Object>();
|
|
187
|
+
Nan::SetPrototype(indexGroups, Nan::Null());
|
|
188
|
+
|
|
189
|
+
for (auto group : groupNames)
|
|
190
|
+
{
|
|
191
|
+
auto value = Nan::Get(indices, group.first);
|
|
192
|
+
if (!value.IsEmpty())
|
|
193
|
+
{
|
|
194
|
+
Nan::Set(indexGroups, Nan::New(group.second).ToLocalChecked(), value.ToLocalChecked());
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
Nan::Set(indices, Nan::New("groups").ToLocalChecked(), indexGroups);
|
|
199
|
+
}
|
|
146
200
|
}
|
|
147
201
|
else
|
|
148
202
|
{
|
|
149
203
|
Nan::Set(result, Nan::New("groups").ToLocalChecked(), Nan::Undefined());
|
|
204
|
+
if (re2->hasIndices)
|
|
205
|
+
{
|
|
206
|
+
Nan::Set(indices, Nan::New("groups").ToLocalChecked(), Nan::Undefined());
|
|
207
|
+
}
|
|
150
208
|
}
|
|
151
209
|
}
|
|
152
210
|
|
|
211
|
+
if (re2->hasIndices)
|
|
212
|
+
{
|
|
213
|
+
Nan::Set(result, Nan::New("indices").ToLocalChecked(), indices);
|
|
214
|
+
}
|
|
215
|
+
|
|
153
216
|
info.GetReturnValue().Set(result);
|
|
154
217
|
}
|
package/lib/new.cc
CHANGED
|
@@ -232,6 +232,7 @@ NAN_METHOD(WrappedRE2::New)
|
|
|
232
232
|
bool dotAll = false;
|
|
233
233
|
bool unicode = false;
|
|
234
234
|
bool sticky = false;
|
|
235
|
+
bool hasIndices = false;
|
|
235
236
|
|
|
236
237
|
auto context = Nan::GetCurrentContext();
|
|
237
238
|
|
|
@@ -272,6 +273,9 @@ NAN_METHOD(WrappedRE2::New)
|
|
|
272
273
|
case 'y':
|
|
273
274
|
sticky = true;
|
|
274
275
|
break;
|
|
276
|
+
case 'd':
|
|
277
|
+
hasIndices = true;
|
|
278
|
+
break;
|
|
275
279
|
}
|
|
276
280
|
}
|
|
277
281
|
size = 0;
|
|
@@ -306,6 +310,7 @@ NAN_METHOD(WrappedRE2::New)
|
|
|
306
310
|
dotAll = bool(flags & v8::RegExp::kDotAll);
|
|
307
311
|
unicode = bool(flags & v8::RegExp::kUnicode);
|
|
308
312
|
sticky = bool(flags & v8::RegExp::kSticky);
|
|
313
|
+
hasIndices = bool(flags & v8::RegExp::kHasIndices);
|
|
309
314
|
}
|
|
310
315
|
else if (info[0]->IsObject() && !info[0]->IsString())
|
|
311
316
|
{
|
|
@@ -332,6 +337,7 @@ NAN_METHOD(WrappedRE2::New)
|
|
|
332
337
|
dotAll = re2->dotAll;
|
|
333
338
|
unicode = true;
|
|
334
339
|
sticky = re2->sticky;
|
|
340
|
+
hasIndices = re2->hasIndices;
|
|
335
341
|
}
|
|
336
342
|
}
|
|
337
343
|
else if (info[0]->IsString())
|
|
@@ -385,7 +391,7 @@ NAN_METHOD(WrappedRE2::New)
|
|
|
385
391
|
options.set_dot_nl(dotAll);
|
|
386
392
|
options.set_log_errors(false); // inappropriate when embedding
|
|
387
393
|
|
|
388
|
-
std::unique_ptr<WrappedRE2> re2(new WrappedRE2(re2::StringPiece(data, size), options, source, global, ignoreCase, multiline, dotAll, sticky));
|
|
394
|
+
std::unique_ptr<WrappedRE2> re2(new WrappedRE2(re2::StringPiece(data, size), options, source, global, ignoreCase, multiline, dotAll, sticky, hasIndices));
|
|
389
395
|
if (!re2->regexp.ok())
|
|
390
396
|
{
|
|
391
397
|
return Nan::ThrowSyntaxError(re2->regexp.error().c_str());
|
package/lib/replace.cc
CHANGED
|
@@ -228,7 +228,8 @@ static Nan::Maybe<std::string> replace(WrappedRE2 *re2, const StrVal &replacee,
|
|
|
228
228
|
{
|
|
229
229
|
size_t s = getUtf8CharSize(data[lastIndex]);
|
|
230
230
|
lastIndex += s;
|
|
231
|
-
if (s == 4 && n >= 2)
|
|
231
|
+
if (s == 4 && n >= 2)
|
|
232
|
+
{
|
|
232
233
|
--n; // this utf8 character will take two utf16 characters
|
|
233
234
|
}
|
|
234
235
|
// the decrement above is protected to avoid an overflow of an unsigned integer
|
|
@@ -299,7 +300,7 @@ static Nan::Maybe<std::string> replace(WrappedRE2 *re2, const StrVal &replacee,
|
|
|
299
300
|
|
|
300
301
|
inline Nan::Maybe<std::string> replace(const Nan::Callback *replacer, const std::vector<re2::StringPiece> &groups, const re2::StringPiece &str, const v8::Local<v8::Value> &input, bool useBuffers, const std::map<std::string, int> &namedGroups)
|
|
301
302
|
{
|
|
302
|
-
std::vector<v8::Local<v8::Value
|
|
303
|
+
std::vector<v8::Local<v8::Value>> argv;
|
|
303
304
|
|
|
304
305
|
auto context = Nan::GetCurrentContext();
|
|
305
306
|
|
|
@@ -308,7 +309,15 @@ inline Nan::Maybe<std::string> replace(const Nan::Callback *replacer, const std:
|
|
|
308
309
|
for (size_t i = 0, n = groups.size(); i < n; ++i)
|
|
309
310
|
{
|
|
310
311
|
const auto &item = groups[i];
|
|
311
|
-
|
|
312
|
+
const auto data = item.data();
|
|
313
|
+
if (data)
|
|
314
|
+
{
|
|
315
|
+
argv.push_back(Nan::CopyBuffer(data, item.size()).ToLocalChecked());
|
|
316
|
+
}
|
|
317
|
+
else
|
|
318
|
+
{
|
|
319
|
+
argv.push_back(Nan::Undefined());
|
|
320
|
+
}
|
|
312
321
|
}
|
|
313
322
|
argv.push_back(Nan::New(static_cast<int>(groups[0].data() - str.data())));
|
|
314
323
|
}
|
|
@@ -317,7 +326,15 @@ inline Nan::Maybe<std::string> replace(const Nan::Callback *replacer, const std:
|
|
|
317
326
|
for (size_t i = 0, n = groups.size(); i < n; ++i)
|
|
318
327
|
{
|
|
319
328
|
const auto &item = groups[i];
|
|
320
|
-
|
|
329
|
+
const auto data = item.data();
|
|
330
|
+
if (data)
|
|
331
|
+
{
|
|
332
|
+
argv.push_back(Nan::New(data, item.size()).ToLocalChecked());
|
|
333
|
+
}
|
|
334
|
+
else
|
|
335
|
+
{
|
|
336
|
+
argv.push_back(Nan::Undefined());
|
|
337
|
+
}
|
|
321
338
|
}
|
|
322
339
|
argv.push_back(Nan::New(static_cast<int>(getUtf16Length(str.data(), groups[0].data()))));
|
|
323
340
|
}
|
|
@@ -381,7 +398,8 @@ static Nan::Maybe<std::string> replace(WrappedRE2 *re2, const StrVal &replacee,
|
|
|
381
398
|
{
|
|
382
399
|
size_t s = getUtf8CharSize(data[lastIndex]);
|
|
383
400
|
lastIndex += s;
|
|
384
|
-
if (s == 4 && n >= 2)
|
|
401
|
+
if (s == 4 && n >= 2)
|
|
402
|
+
{
|
|
385
403
|
--n; // this utf8 character will take two utf16 characters
|
|
386
404
|
}
|
|
387
405
|
// the decrement above is protected to avoid an overflow of an unsigned integer
|
package/lib/wrapped_re2.h
CHANGED
|
@@ -11,8 +11,8 @@ class WrappedRE2 : public Nan::ObjectWrap
|
|
|
11
11
|
{
|
|
12
12
|
private:
|
|
13
13
|
WrappedRE2(const re2::StringPiece &pattern, const re2::RE2::Options &options, const std::string &src,
|
|
14
|
-
const bool &g, const bool &i, const bool &m, const bool &s, const bool &y) : regexp(pattern, options),
|
|
15
|
-
|
|
14
|
+
const bool &g, const bool &i, const bool &m, const bool &s, const bool &y, const bool &d) : regexp(pattern, options),
|
|
15
|
+
source(src), global(g), ignoreCase(i), multiline(m), dotAll(s), sticky(y), hasIndices(d), lastIndex(0) {}
|
|
16
16
|
|
|
17
17
|
static NAN_METHOD(New);
|
|
18
18
|
static NAN_METHOD(ToString);
|
|
@@ -25,6 +25,7 @@ private:
|
|
|
25
25
|
static NAN_GETTER(GetDotAll);
|
|
26
26
|
static NAN_GETTER(GetUnicode);
|
|
27
27
|
static NAN_GETTER(GetSticky);
|
|
28
|
+
static NAN_GETTER(GetHasIndices);
|
|
28
29
|
static NAN_GETTER(GetLastIndex);
|
|
29
30
|
static NAN_SETTER(SetLastIndex);
|
|
30
31
|
static NAN_GETTER(GetInternalSource);
|
|
@@ -70,6 +71,7 @@ public:
|
|
|
70
71
|
bool multiline;
|
|
71
72
|
bool dotAll;
|
|
72
73
|
bool sticky;
|
|
74
|
+
bool hasIndices;
|
|
73
75
|
size_t lastIndex;
|
|
74
76
|
};
|
|
75
77
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "re2",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.19.0",
|
|
4
4
|
"description": "Bindings for RE2: fast, safe alternative to backtracking regular expression engines.",
|
|
5
5
|
"homepage": "https://github.com/uhop/node-re2",
|
|
6
6
|
"bugs": "https://github.com/uhop/node-re2/issues",
|
package/tests/test_exec.js
CHANGED
|
@@ -21,9 +21,13 @@ unit.add(module, [
|
|
|
21
21
|
|
|
22
22
|
var result = re.exec('The Quick Brown Fox Jumps Over The Lazy Dog');
|
|
23
23
|
|
|
24
|
-
eval(
|
|
24
|
+
eval(
|
|
25
|
+
t.TEST("t.unify(result, ['Quick Brown Fox Jumps', 'Brown', 'Jumps'])")
|
|
26
|
+
);
|
|
25
27
|
eval(t.TEST('result.index === 4'));
|
|
26
|
-
eval(
|
|
28
|
+
eval(
|
|
29
|
+
t.TEST("result.input === 'The Quick Brown Fox Jumps Over The Lazy Dog'")
|
|
30
|
+
);
|
|
27
31
|
eval(t.TEST('re.lastIndex === 25'));
|
|
28
32
|
},
|
|
29
33
|
function test_execSucc(t) {
|
|
@@ -148,12 +152,20 @@ unit.add(module, [
|
|
|
148
152
|
|
|
149
153
|
var result = re.exec('Каждый Охотник Желает Знать Где Сидит Фазан');
|
|
150
154
|
|
|
151
|
-
eval(
|
|
155
|
+
eval(
|
|
156
|
+
t.TEST("t.unify(result, ['Охотник Желает Знать Где', 'Желает', 'Где'])")
|
|
157
|
+
);
|
|
152
158
|
eval(t.TEST('result.index === 7'));
|
|
153
|
-
eval(
|
|
159
|
+
eval(
|
|
160
|
+
t.TEST("result.input === 'Каждый Охотник Желает Знать Где Сидит Фазан'")
|
|
161
|
+
);
|
|
154
162
|
eval(t.TEST('re.lastIndex === 31'));
|
|
155
163
|
|
|
156
|
-
eval(
|
|
164
|
+
eval(
|
|
165
|
+
t.TEST(
|
|
166
|
+
"result.input.substr(result.index) === 'Охотник Желает Знать Где Сидит Фазан'"
|
|
167
|
+
)
|
|
168
|
+
);
|
|
157
169
|
eval(t.TEST("result.input.substr(re.lastIndex) === ' Сидит Фазан'"));
|
|
158
170
|
},
|
|
159
171
|
function test_execUnicodeSubsequent(t) {
|
|
@@ -248,11 +260,21 @@ unit.add(module, [
|
|
|
248
260
|
|
|
249
261
|
eval(t.TEST('result.index === 13'));
|
|
250
262
|
eval(t.TEST('result.input instanceof Buffer'));
|
|
251
|
-
eval(
|
|
263
|
+
eval(
|
|
264
|
+
t.TEST(
|
|
265
|
+
"result.input.toString() === 'Каждый Охотник Желает Знать Где Сидит Фазан'"
|
|
266
|
+
)
|
|
267
|
+
);
|
|
252
268
|
eval(t.TEST('re.lastIndex === 58'));
|
|
253
269
|
|
|
254
|
-
eval(
|
|
255
|
-
|
|
270
|
+
eval(
|
|
271
|
+
t.TEST(
|
|
272
|
+
"result.input.toString('utf8', result.index) === 'Охотник Желает Знать Где Сидит Фазан'"
|
|
273
|
+
)
|
|
274
|
+
);
|
|
275
|
+
eval(
|
|
276
|
+
t.TEST("result.input.toString('utf8', re.lastIndex) === ' Сидит Фазан'")
|
|
277
|
+
);
|
|
256
278
|
},
|
|
257
279
|
|
|
258
280
|
// Sticky tests
|
|
@@ -317,7 +339,9 @@ xy2 (at start of line)
|
|
|
317
339
|
eval(t.TEST("result[0] === 'xy'"));
|
|
318
340
|
eval(t.TEST('result.index > 3'));
|
|
319
341
|
eval(t.TEST('result.index < pattern.length - 4'));
|
|
320
|
-
eval(
|
|
342
|
+
eval(
|
|
343
|
+
t.TEST('result[0] === pattern.substr(result.index, result[0].length)')
|
|
344
|
+
);
|
|
321
345
|
},
|
|
322
346
|
|
|
323
347
|
// dotAll tests
|
|
@@ -332,5 +356,63 @@ xy2 (at start of line)
|
|
|
332
356
|
eval(t.TEST("new RE2('a.c', 's').test('abc')"));
|
|
333
357
|
eval(t.TEST("new RE2(/a.c/s).test('a c')"));
|
|
334
358
|
eval(t.TEST("new RE2(/a.c/s).test('a\\nc')"));
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
// hasIndices tests
|
|
362
|
+
|
|
363
|
+
function test_execHasIndices(t) {
|
|
364
|
+
'use strict';
|
|
365
|
+
|
|
366
|
+
eval(t.TEST("!new RE2('1').hasIndices"));
|
|
367
|
+
eval(t.TEST('!new RE2(/1/).hasIndices'));
|
|
368
|
+
|
|
369
|
+
var re = new RE2('(aa)(?<b>b)?(?<c>ccc)', 'd');
|
|
370
|
+
|
|
371
|
+
eval(t.TEST('re.hasIndices'));
|
|
372
|
+
|
|
373
|
+
var result = re.exec('1aabccc2');
|
|
374
|
+
|
|
375
|
+
eval(t.TEST('result.length === 4'));
|
|
376
|
+
eval(t.TEST("result.input === '1aabccc2'"));
|
|
377
|
+
eval(t.TEST('result.index === 1'));
|
|
378
|
+
eval(t.TEST('Object.keys(result.groups).length === 2'));
|
|
379
|
+
eval(t.TEST("result.groups.b === 'b'"));
|
|
380
|
+
eval(t.TEST("result.groups.c === 'ccc'"));
|
|
381
|
+
eval(t.TEST("result[0] === 'aabccc'"));
|
|
382
|
+
eval(t.TEST("result[1] === 'aa'"));
|
|
383
|
+
eval(t.TEST("result[2] === 'b'"));
|
|
384
|
+
eval(t.TEST("result[3] === 'ccc'"));
|
|
385
|
+
eval(t.TEST('result.indices.length === 4'));
|
|
386
|
+
eval(t.TEST('t.unify(result.indices, [[1, 7], [1, 3], [3, 4], [4, 7]])'));
|
|
387
|
+
eval(t.TEST('Object.keys(result.indices.groups).length === 2'));
|
|
388
|
+
eval(t.TEST('t.unify(result.indices.groups.b, [3, 4])'));
|
|
389
|
+
eval(t.TEST('t.unify(result.indices.groups.c, [4, 7])'));
|
|
390
|
+
|
|
391
|
+
result = re.exec('1aaccc2');
|
|
392
|
+
|
|
393
|
+
eval(t.TEST('result.length === 4'));
|
|
394
|
+
eval(t.TEST("result.input === '1aaccc2'"));
|
|
395
|
+
eval(t.TEST('result.index === 1'));
|
|
396
|
+
eval(t.TEST('Object.keys(result.groups).length === 2'));
|
|
397
|
+
eval(t.TEST('result.groups.b === undefined'));
|
|
398
|
+
eval(t.TEST("result.groups.c === 'ccc'"));
|
|
399
|
+
eval(t.TEST("result[0] === 'aaccc'"));
|
|
400
|
+
eval(t.TEST("result[1] === 'aa'"));
|
|
401
|
+
eval(t.TEST('result[2] === undefined'));
|
|
402
|
+
eval(t.TEST("result[3] === 'ccc'"));
|
|
403
|
+
eval(t.TEST('result.indices.length === 4'));
|
|
404
|
+
eval(
|
|
405
|
+
t.TEST('t.unify(result.indices, [[1, 6], [1, 3], undefined, [3, 6]])')
|
|
406
|
+
);
|
|
407
|
+
eval(t.TEST('Object.keys(result.indices.groups).length === 2'));
|
|
408
|
+
eval(t.TEST('t.unify(result.indices.groups.b, undefined)'));
|
|
409
|
+
eval(t.TEST('t.unify(result.indices.groups.c, [3, 6])'));
|
|
410
|
+
|
|
411
|
+
try {
|
|
412
|
+
re = new RE2(new RegExp('1', 'd'));
|
|
413
|
+
eval(t.TEST('re.hasIndices'));
|
|
414
|
+
} catch (e) {
|
|
415
|
+
// squelch
|
|
416
|
+
}
|
|
335
417
|
}
|
|
336
418
|
]);
|
package/tests/test_match.js
CHANGED
|
@@ -1,137 +1,161 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var unit = require("heya-unit");
|
|
5
|
-
var RE2 = require("../re2");
|
|
1
|
+
'use strict';
|
|
6
2
|
|
|
3
|
+
var unit = require('heya-unit');
|
|
4
|
+
var RE2 = require('../re2');
|
|
7
5
|
|
|
8
6
|
// tests
|
|
9
7
|
|
|
10
8
|
unit.add(module, [
|
|
9
|
+
// These tests are copied from MDN:
|
|
10
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match
|
|
11
|
+
|
|
12
|
+
function test_match(t) {
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
var str = 'For more information, see Chapter 3.4.5.1';
|
|
16
|
+
|
|
17
|
+
var re = new RE2(/(chapter \d+(\.\d)*)/i);
|
|
18
|
+
var result = re.match(str);
|
|
19
|
+
|
|
20
|
+
eval(t.TEST('result.input === str'));
|
|
21
|
+
eval(t.TEST('result.index === 26'));
|
|
22
|
+
eval(t.TEST('result.length === 3'));
|
|
23
|
+
eval(t.TEST("result[0] === 'Chapter 3.4.5.1'"));
|
|
24
|
+
eval(t.TEST("result[1] === 'Chapter 3.4.5.1'"));
|
|
25
|
+
eval(t.TEST("result[2] === '.1'"));
|
|
26
|
+
},
|
|
27
|
+
function test_matchGlobal(t) {
|
|
28
|
+
'use strict';
|
|
11
29
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"use strict";
|
|
30
|
+
var re = new RE2(/[A-E]/gi);
|
|
31
|
+
var result = re.match(
|
|
32
|
+
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
|
33
|
+
);
|
|
17
34
|
|
|
18
|
-
|
|
35
|
+
eval(
|
|
36
|
+
t.TEST(
|
|
37
|
+
"t.unify(result, ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e'])"
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
},
|
|
41
|
+
function test_matchFail(t) {
|
|
42
|
+
'use strict';
|
|
19
43
|
|
|
20
|
-
|
|
21
|
-
|
|
44
|
+
var re = new RE2('(a+)?(b+)?');
|
|
45
|
+
var result = re.match('aaabb');
|
|
22
46
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
eval(t.TEST("result.length === 3"));
|
|
26
|
-
eval(t.TEST("result[0] === 'Chapter 3.4.5.1'"));
|
|
27
|
-
eval(t.TEST("result[1] === 'Chapter 3.4.5.1'"));
|
|
28
|
-
eval(t.TEST("result[2] === '.1'"));
|
|
29
|
-
},
|
|
30
|
-
function test_matchGlobal(t) {
|
|
31
|
-
"use strict";
|
|
47
|
+
eval(t.TEST("result[1] === 'aaa'"));
|
|
48
|
+
eval(t.TEST("result[2] === 'bb'"));
|
|
32
49
|
|
|
33
|
-
|
|
34
|
-
var result = re.match("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
|
50
|
+
result = re.match('aaacbb');
|
|
35
51
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
52
|
+
eval(t.TEST("result[1] === 'aaa'"));
|
|
53
|
+
eval(t.TEST('result[2] === undefined'));
|
|
54
|
+
},
|
|
55
|
+
function test_matchInvalid(t) {
|
|
56
|
+
'use strict';
|
|
40
57
|
|
|
41
|
-
|
|
42
|
-
var result = re.match("aaabb");
|
|
58
|
+
var re = RE2('');
|
|
43
59
|
|
|
44
|
-
|
|
45
|
-
|
|
60
|
+
try {
|
|
61
|
+
re.match({
|
|
62
|
+
toString() {
|
|
63
|
+
throw 'corner';
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
t.test(false); // shouldn't be here
|
|
67
|
+
} catch (e) {
|
|
68
|
+
eval(t.TEST("e === 'corner'"));
|
|
69
|
+
}
|
|
70
|
+
},
|
|
46
71
|
|
|
47
|
-
|
|
72
|
+
// Unicode tests
|
|
48
73
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
},
|
|
52
|
-
function test_matchInvalid(t) {
|
|
53
|
-
"use strict";
|
|
74
|
+
function test_matchUnicode(t) {
|
|
75
|
+
'use strict';
|
|
54
76
|
|
|
55
|
-
|
|
77
|
+
var str = 'Это ГЛАВА 3.4.5.1';
|
|
56
78
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
t.test(false); // shouldn't be here
|
|
60
|
-
} catch(e) {
|
|
61
|
-
eval(t.TEST("e === 'corner'"));
|
|
62
|
-
}
|
|
63
|
-
},
|
|
79
|
+
var re = new RE2(/(глава \d+(\.\d)*)/i);
|
|
80
|
+
var result = re.match(str);
|
|
64
81
|
|
|
65
|
-
|
|
82
|
+
eval(t.TEST('result.input === str'));
|
|
83
|
+
eval(t.TEST('result.index === 4'));
|
|
84
|
+
eval(t.TEST('result.length === 3'));
|
|
85
|
+
eval(t.TEST("result[0] === 'ГЛАВА 3.4.5.1'"));
|
|
86
|
+
eval(t.TEST("result[1] === 'ГЛАВА 3.4.5.1'"));
|
|
87
|
+
eval(t.TEST("result[2] === '.1'"));
|
|
88
|
+
},
|
|
66
89
|
|
|
67
|
-
|
|
68
|
-
"use strict";
|
|
90
|
+
// Buffer tests
|
|
69
91
|
|
|
70
|
-
|
|
92
|
+
function test_matchBuffer(t) {
|
|
93
|
+
'use strict';
|
|
71
94
|
|
|
72
|
-
|
|
73
|
-
var result = re.match(str);
|
|
95
|
+
var buf = new Buffer('Это ГЛАВА 3.4.5.1');
|
|
74
96
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
eval(t.TEST("result.length === 3"));
|
|
78
|
-
eval(t.TEST("result[0] === 'ГЛАВА 3.4.5.1'"));
|
|
79
|
-
eval(t.TEST("result[1] === 'ГЛАВА 3.4.5.1'"));
|
|
80
|
-
eval(t.TEST("result[2] === '.1'"));
|
|
81
|
-
},
|
|
97
|
+
var re = new RE2(/(глава \d+(\.\d)*)/i);
|
|
98
|
+
var result = re.match(buf);
|
|
82
99
|
|
|
83
|
-
|
|
100
|
+
eval(t.TEST('result.input instanceof Buffer'));
|
|
101
|
+
eval(t.TEST('result.length === 3'));
|
|
102
|
+
eval(t.TEST('result[0] instanceof Buffer'));
|
|
103
|
+
eval(t.TEST('result[1] instanceof Buffer'));
|
|
104
|
+
eval(t.TEST('result[2] instanceof Buffer'));
|
|
84
105
|
|
|
85
|
-
|
|
86
|
-
|
|
106
|
+
eval(t.TEST('result.input === buf'));
|
|
107
|
+
eval(t.TEST('result.index === 7'));
|
|
108
|
+
eval(
|
|
109
|
+
t.TEST("result.input.toString('utf8', result.index) === 'ГЛАВА 3.4.5.1'")
|
|
110
|
+
);
|
|
111
|
+
eval(t.TEST("result[0].toString() === 'ГЛАВА 3.4.5.1'"));
|
|
112
|
+
eval(t.TEST("result[1].toString() === 'ГЛАВА 3.4.5.1'"));
|
|
113
|
+
eval(t.TEST("result[2].toString() === '.1'"));
|
|
114
|
+
},
|
|
87
115
|
|
|
88
|
-
|
|
116
|
+
// Sticky tests
|
|
89
117
|
|
|
90
|
-
|
|
91
|
-
|
|
118
|
+
function test_matchSticky(t) {
|
|
119
|
+
'use strict';
|
|
92
120
|
|
|
93
|
-
|
|
94
|
-
eval(t.TEST("result.length === 3"));
|
|
95
|
-
eval(t.TEST("result[0] instanceof Buffer"));
|
|
96
|
-
eval(t.TEST("result[1] instanceof Buffer"));
|
|
97
|
-
eval(t.TEST("result[2] instanceof Buffer"));
|
|
121
|
+
var re = new RE2('\\s+', 'y');
|
|
98
122
|
|
|
99
|
-
|
|
100
|
-
eval(t.TEST("result.index === 7"));
|
|
101
|
-
eval(t.TEST("result.input.toString('utf8', result.index) === 'ГЛАВА 3.4.5.1'"));
|
|
102
|
-
eval(t.TEST("result[0].toString() === 'ГЛАВА 3.4.5.1'"));
|
|
103
|
-
eval(t.TEST("result[1].toString() === 'ГЛАВА 3.4.5.1'"));
|
|
104
|
-
eval(t.TEST("result[2].toString() === '.1'"));
|
|
105
|
-
},
|
|
123
|
+
eval(t.TEST("re.match('Hello world, how are you?') === null"));
|
|
106
124
|
|
|
107
|
-
|
|
125
|
+
re.lastIndex = 5;
|
|
108
126
|
|
|
109
|
-
|
|
110
|
-
"use strict";
|
|
127
|
+
var result = re.match('Hello world, how are you?');
|
|
111
128
|
|
|
112
|
-
|
|
129
|
+
eval(t.TEST("t.unify(result, [' '])"));
|
|
130
|
+
eval(t.TEST('result.index === 5'));
|
|
131
|
+
eval(t.TEST('re.lastIndex === 6'));
|
|
113
132
|
|
|
114
|
-
|
|
133
|
+
var re2 = new RE2('\\s+', 'gy');
|
|
115
134
|
|
|
116
|
-
|
|
135
|
+
eval(t.TEST("re2.match('Hello world, how are you?') === null"));
|
|
117
136
|
|
|
118
|
-
|
|
137
|
+
re2.lastIndex = 5;
|
|
119
138
|
|
|
120
|
-
|
|
121
|
-
eval(t.TEST("result.index === 5"));
|
|
122
|
-
eval(t.TEST("re.lastIndex === 6"));
|
|
139
|
+
eval(t.TEST("re2.match('Hello world, how are you?') === null"));
|
|
123
140
|
|
|
124
|
-
|
|
141
|
+
var re3 = new RE2(/[A-E]/giy);
|
|
142
|
+
var result3 = re3.match(
|
|
143
|
+
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
|
144
|
+
);
|
|
125
145
|
|
|
126
|
-
|
|
146
|
+
eval(t.TEST("t.unify(result3, ['A', 'B', 'C', 'D', 'E'])"));
|
|
147
|
+
},
|
|
127
148
|
|
|
128
|
-
|
|
149
|
+
// hasIndices tests
|
|
129
150
|
|
|
130
|
-
|
|
151
|
+
function test_matchHasIndices(t) {
|
|
152
|
+
'use strict';
|
|
131
153
|
|
|
132
|
-
|
|
133
|
-
|
|
154
|
+
var re = new RE2('(aa)(?<b>b)?(?<c>ccc)', 'd'),
|
|
155
|
+
str1 = '1aabccc2',
|
|
156
|
+
str2 = '1aaccc2';
|
|
134
157
|
|
|
135
|
-
|
|
136
|
-
|
|
158
|
+
eval(t.TEST("t.unify(str1.match(re), re.exec(str1))"));
|
|
159
|
+
eval(t.TEST("t.unify(str2.match(re), re.exec(str2))"));
|
|
160
|
+
}
|
|
137
161
|
]);
|
package/tests/test_replace.js
CHANGED
|
@@ -13,7 +13,10 @@ unit.add(module, [
|
|
|
13
13
|
'use strict';
|
|
14
14
|
|
|
15
15
|
var re = new RE2(/apples/gi);
|
|
16
|
-
var result = re.replace(
|
|
16
|
+
var result = re.replace(
|
|
17
|
+
'Apples are round, and apples are juicy.',
|
|
18
|
+
'oranges'
|
|
19
|
+
);
|
|
17
20
|
eval(t.TEST("result === 'oranges are round, and oranges are juicy.'"));
|
|
18
21
|
|
|
19
22
|
re = new RE2(/xmas/i);
|
|
@@ -199,15 +202,24 @@ unit.add(module, [
|
|
|
199
202
|
'use strict';
|
|
200
203
|
|
|
201
204
|
var re = new RE2(/яблоки/gi);
|
|
202
|
-
var result = re.replace(
|
|
205
|
+
var result = re.replace(
|
|
206
|
+
new Buffer('Яблоки красны, яблоки сочны.'),
|
|
207
|
+
'апельсины'
|
|
208
|
+
);
|
|
203
209
|
eval(t.TEST('result instanceof Buffer'));
|
|
204
210
|
eval(t.TEST("result.toString() === 'апельсины красны, апельсины сочны.'"));
|
|
205
211
|
|
|
206
|
-
result = re.replace(
|
|
212
|
+
result = re.replace(
|
|
213
|
+
new Buffer('Яблоки красны, яблоки сочны.'),
|
|
214
|
+
new Buffer('апельсины')
|
|
215
|
+
);
|
|
207
216
|
eval(t.TEST('result instanceof Buffer'));
|
|
208
217
|
eval(t.TEST("result.toString() === 'апельсины красны, апельсины сочны.'"));
|
|
209
218
|
|
|
210
|
-
result = re.replace(
|
|
219
|
+
result = re.replace(
|
|
220
|
+
'Яблоки красны, яблоки сочны.',
|
|
221
|
+
new Buffer('апельсины')
|
|
222
|
+
);
|
|
211
223
|
eval(t.TEST("typeof result == 'string'"));
|
|
212
224
|
eval(t.TEST("result === 'апельсины красны, апельсины сочны.'"));
|
|
213
225
|
},
|
|
@@ -280,5 +292,47 @@ unit.add(module, [
|
|
|
280
292
|
|
|
281
293
|
eval(t.TEST("re2.replace('ABCDEFABCDEF', '!') === '!!!!!FABCDEF'"));
|
|
282
294
|
eval(t.TEST('re2.lastIndex === 0'));
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
// Non-matches
|
|
298
|
+
|
|
299
|
+
function test_replaceOneNonMatch(t) {
|
|
300
|
+
'use strict';
|
|
301
|
+
|
|
302
|
+
function replacer(match, capture, offset, string) {
|
|
303
|
+
t.test(typeof offset == 'number');
|
|
304
|
+
t.test(typeof match == 'string');
|
|
305
|
+
t.test(typeof string == 'string');
|
|
306
|
+
t.test(typeof capture == 'undefined');
|
|
307
|
+
t.test(offset === 0);
|
|
308
|
+
t.test(string === 'hello ');
|
|
309
|
+
return '';
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
var re = new RE2(/hello (world)?/);
|
|
313
|
+
re.replace('hello ', replacer);
|
|
314
|
+
},
|
|
315
|
+
function test_replaceTwoNonMatches(t) {
|
|
316
|
+
'use strict';
|
|
317
|
+
|
|
318
|
+
function replacer(match, capture1, capture2, offset, string, groups) {
|
|
319
|
+
t.test(typeof offset == 'number');
|
|
320
|
+
t.test(typeof match == 'string');
|
|
321
|
+
t.test(typeof string == 'string');
|
|
322
|
+
t.test(typeof capture1 == 'undefined');
|
|
323
|
+
t.test(typeof capture2 == 'undefined');
|
|
324
|
+
t.test(offset === 1);
|
|
325
|
+
t.test(match === 'b & y');
|
|
326
|
+
t.test(string === 'ab & yz');
|
|
327
|
+
t.test(typeof groups == 'object');
|
|
328
|
+
t.test(Object.keys(groups).length == 2);
|
|
329
|
+
t.test(groups.a === undefined);
|
|
330
|
+
t.test(groups.b == undefined);
|
|
331
|
+
return '';
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
var re = new RE2(/b(?<a>1)? & (?<b>2)?y/);
|
|
335
|
+
var result = re.replace('ab & yz', replacer);
|
|
336
|
+
eval(t.TEST("result === 'az'"));
|
|
283
337
|
}
|
|
284
338
|
]);
|