re2 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +32 -8
- data/ext/re2/extconf.rb +27 -0
- data/ext/re2/re2.cc +103 -29
- data/test/re2_test.rb +34 -0
- metadata +31 -50
- data/test/leak.rb +0 -32
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
re2
|
1
|
+
re2 [![Build Status](https://secure.travis-ci.org/mudge/re2.png?branch=master)](http://travis-ci.org/mudge/re2)
|
2
2
|
===
|
3
3
|
|
4
4
|
A Ruby binding to [re2][], an "efficient, principled regular expression library".
|
@@ -6,7 +6,13 @@ A Ruby binding to [re2][], an "efficient, principled regular expression library"
|
|
6
6
|
Installation
|
7
7
|
------------
|
8
8
|
|
9
|
-
You will need [re2][] installed as well as a C++ compiler such as [gcc][] (on Debian and Ubuntu, this is provided by the [build-essential][] package).
|
9
|
+
You will need [re2][] installed as well as a C++ compiler such as [gcc][] (on Debian and Ubuntu, this is provided by the [build-essential][] package). If you are using Mac OS X, I recommend installing re2 with [Homebrew][] by running the following:
|
10
|
+
|
11
|
+
$ brew install --HEAD re2
|
12
|
+
|
13
|
+
If you are using Debian, you can install the [libre2-dev][] package like so:
|
14
|
+
|
15
|
+
$ sudo apt-get install libre2-dev
|
10
16
|
|
11
17
|
If you are using a packaged Ruby distribution, make sure you also have the Ruby header files installed such as those provided by the [ruby-dev][] package on Debian and Ubuntu.
|
12
18
|
|
@@ -15,7 +21,9 @@ You can then install the library via RubyGems with `gem install re2` or `gem ins
|
|
15
21
|
Documentation
|
16
22
|
-------------
|
17
23
|
|
18
|
-
Full documentation automatically generated from the latest version is available at <http://
|
24
|
+
Full documentation automatically generated from the latest version is available at <http://rubydoc.info/github/mudge/re2>.
|
25
|
+
|
26
|
+
Bear in mind that re2's regular expression syntax differs from PCRE, see the [official syntax page][] for more details.
|
19
27
|
|
20
28
|
Usage
|
21
29
|
-----
|
@@ -39,20 +47,33 @@ You can use re2 as a mostly drop-in replacement for Ruby's own [Regexp][] and [M
|
|
39
47
|
> r.match("bob")
|
40
48
|
=> nil
|
41
49
|
|
50
|
+
As of 0.3.0, you can use named groups:
|
51
|
+
|
52
|
+
> r = RE2::Regexp.compile('(?P<name>\w+) (?P<age>\d+)')
|
53
|
+
=> #<RE2::Regexp /(?P<name>\w+) (?P<age>\d+)/>
|
54
|
+
> m = r.match("Bob 40")
|
55
|
+
=> #<RE2::MatchData "Bob 40" 1:"Bob" 2:"40">
|
56
|
+
> m[:name]
|
57
|
+
=> "Bob"
|
58
|
+
> m["age"]
|
59
|
+
=> "40"
|
60
|
+
|
42
61
|
Features
|
43
62
|
--------
|
44
63
|
|
45
64
|
* Pre-compiling regular expressions with [`RE2::Regexp.new(re)`](http://code.google.com/p/re2/source/browse/re2/re2.h#96), `RE2::Regexp.compile(re)` or `RE2(re)` (including specifying options, e.g. `RE2::Regexp.new("pattern", :case_sensitive => false)`
|
46
65
|
|
47
|
-
|
66
|
+
* Extracting matches with `re2.match(text)` (and an exact number of matches with `re2.match(text, number_of_matches)` such as `re2.match("123-234", 2)`)
|
67
|
+
|
68
|
+
* Extracting matches by name (both with strings and symbols)
|
48
69
|
|
49
|
-
|
70
|
+
* Checking for matches with `re2 =~ text`, `re2 === text` (for use in `case` statements) and `re2 !~ text`
|
50
71
|
|
51
|
-
|
72
|
+
* Checking regular expression compilation with `re2.ok?`, `re2.error` and `re2.error_arg`
|
52
73
|
|
53
|
-
|
74
|
+
* Checking regular expression "cost" with `re2.program_size`
|
54
75
|
|
55
|
-
|
76
|
+
* Checking the options for an expression with `re2.options` or individually with `re2.case_sensitive?`
|
56
77
|
|
57
78
|
* Performing in-place replacement with [`RE2::Replace(str, pattern, replace)`](http://code.google.com/p/re2/source/browse/re2/re2.h#335)
|
58
79
|
|
@@ -71,3 +92,6 @@ All feedback should go to the mailing list: <mailto:ruby.re2@librelist.com>
|
|
71
92
|
[build-essential]: http://packages.debian.org/build-essential
|
72
93
|
[Regexp]: http://ruby-doc.org/core/classes/Regexp.html
|
73
94
|
[MatchData]: http://ruby-doc.org/core/classes/MatchData.html
|
95
|
+
[Homebrew]: http://mxcl.github.com/homebrew
|
96
|
+
[libre2-dev]: http://packages.debian.org/search?keywords=libre2-dev
|
97
|
+
[official syntax page]: http://code.google.com/p/re2/wiki/Syntax
|
data/ext/re2/extconf.rb
CHANGED
@@ -12,6 +12,33 @@ $CFLAGS << " -Wall -Wextra -funroll-loops"
|
|
12
12
|
|
13
13
|
have_library("stdc++")
|
14
14
|
if have_library("re2")
|
15
|
+
|
16
|
+
# Determine which version of re2 the user has installed.
|
17
|
+
# Revision d9f8806c004d added an `endpos` argument to the
|
18
|
+
# generic Match() function.
|
19
|
+
#
|
20
|
+
# To test for this, try to compile a simple program that uses
|
21
|
+
# the newer form of Match() and set a flag if it is successful.
|
22
|
+
checking_for("RE2::Match() with endpos argument") do
|
23
|
+
test_re2_match_signature = <<SRC
|
24
|
+
#include <re2/re2.h>
|
25
|
+
|
26
|
+
int main() {
|
27
|
+
RE2 pattern("test");
|
28
|
+
re2::StringPiece *match;
|
29
|
+
pattern.Match("test", 0, 0, RE2::UNANCHORED, match, 0);
|
30
|
+
|
31
|
+
return 0;
|
32
|
+
}
|
33
|
+
SRC
|
34
|
+
|
35
|
+
# Pass -x c++ to force gcc to compile the test program
|
36
|
+
# as C++ (as it will end in .c by default).
|
37
|
+
if try_compile(test_re2_match_signature, "-x c++")
|
38
|
+
$defs.push("-DHAVE_ENDPOS_ARGUMENT")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
15
42
|
create_makefile("re2")
|
16
43
|
else
|
17
44
|
abort "You must have re2 installed and specified with --with-re2-dir, please see http://code.google.com/p/re2/wiki/Install"
|
data/ext/re2/re2.cc
CHANGED
@@ -7,6 +7,8 @@
|
|
7
7
|
*/
|
8
8
|
|
9
9
|
#include <re2/re2.h>
|
10
|
+
#include <string>
|
11
|
+
using namespace std;
|
10
12
|
|
11
13
|
extern "C" {
|
12
14
|
|
@@ -30,7 +32,7 @@ extern "C" {
|
|
30
32
|
typedef struct {
|
31
33
|
re2::StringPiece *matches;
|
32
34
|
int number_of_matches;
|
33
|
-
VALUE regexp,
|
35
|
+
VALUE regexp, text;
|
34
36
|
} re2_matchdata;
|
35
37
|
|
36
38
|
VALUE re2_mRE2, re2_cRegexp, re2_cMatchData;
|
@@ -43,7 +45,7 @@ extern "C" {
|
|
43
45
|
void re2_matchdata_mark(re2_matchdata* self)
|
44
46
|
{
|
45
47
|
rb_gc_mark(self->regexp);
|
46
|
-
rb_gc_mark(self->
|
48
|
+
rb_gc_mark(self->text);
|
47
49
|
}
|
48
50
|
|
49
51
|
void re2_matchdata_free(re2_matchdata* self)
|
@@ -84,7 +86,7 @@ extern "C" {
|
|
84
86
|
re2_matchdata *m;
|
85
87
|
Data_Get_Struct(self, re2_matchdata, m);
|
86
88
|
|
87
|
-
return m->
|
89
|
+
return m->text;
|
88
90
|
}
|
89
91
|
|
90
92
|
/*
|
@@ -141,13 +143,16 @@ extern "C" {
|
|
141
143
|
{
|
142
144
|
int i;
|
143
145
|
re2_matchdata *m;
|
146
|
+
re2::StringPiece match;
|
147
|
+
|
144
148
|
Data_Get_Struct(self, re2_matchdata, m);
|
145
149
|
VALUE array = rb_ary_new2(m->number_of_matches);
|
146
150
|
for (i = 0; i < m->number_of_matches; i++) {
|
147
151
|
if (m->matches[i].empty()) {
|
148
152
|
rb_ary_push(array, Qnil);
|
149
153
|
} else {
|
150
|
-
|
154
|
+
match = m->matches[i];
|
155
|
+
rb_ary_push(array, rb_str_new(match.data(), match.size()));
|
151
156
|
}
|
152
157
|
}
|
153
158
|
return array;
|
@@ -157,17 +162,42 @@ extern "C" {
|
|
157
162
|
re2_matchdata_nth_match(int nth, VALUE self)
|
158
163
|
{
|
159
164
|
re2_matchdata *m;
|
165
|
+
re2::StringPiece match;
|
166
|
+
|
160
167
|
Data_Get_Struct(self, re2_matchdata, m);
|
168
|
+
match = m->matches[nth];
|
161
169
|
|
162
|
-
if (nth >= m->number_of_matches ||
|
170
|
+
if (nth >= m->number_of_matches || match.empty()) {
|
163
171
|
return Qnil;
|
164
172
|
} else {
|
165
|
-
return rb_str_new(
|
173
|
+
return rb_str_new(match.data(), match.size());
|
174
|
+
}
|
175
|
+
}
|
176
|
+
|
177
|
+
static VALUE
|
178
|
+
re2_matchdata_named_match(const char* name, VALUE self)
|
179
|
+
{
|
180
|
+
int idx;
|
181
|
+
re2_matchdata *m;
|
182
|
+
re2_pattern *p;
|
183
|
+
map<string, int> groups;
|
184
|
+
string name_as_string(name);
|
185
|
+
|
186
|
+
Data_Get_Struct(self, re2_matchdata, m);
|
187
|
+
Data_Get_Struct(m->regexp, re2_pattern, p);
|
188
|
+
|
189
|
+
groups = p->pattern->NamedCapturingGroups();
|
190
|
+
|
191
|
+
if (groups.count(name_as_string) == 1) {
|
192
|
+
idx = groups[name_as_string];
|
193
|
+
return re2_matchdata_nth_match(idx, self);
|
194
|
+
} else {
|
195
|
+
return Qnil;
|
166
196
|
}
|
167
197
|
}
|
168
198
|
|
169
199
|
/*
|
170
|
-
* Retrieve zero, one or more matches by index.
|
200
|
+
* Retrieve zero, one or more matches by index or name.
|
171
201
|
*
|
172
202
|
* @return [Array<String, nil>, String, Boolean]
|
173
203
|
*
|
@@ -198,6 +228,16 @@ extern "C" {
|
|
198
228
|
* @example
|
199
229
|
* m = RE2('(\d+)').match("bob 123")
|
200
230
|
* m[0..1] #=> "[123", "123"]
|
231
|
+
*
|
232
|
+
* @overload [](name)
|
233
|
+
* Access a particular match by name.
|
234
|
+
*
|
235
|
+
* @param [String, Symbol] name the name of the match to fetch
|
236
|
+
* @return [String, nil] the specific match
|
237
|
+
* @example
|
238
|
+
* m = RE2('(?P<number>\d+)').match("bob 123")
|
239
|
+
* m["number"] #=> "123"
|
240
|
+
* m[:number] #=> "123"
|
201
241
|
*/
|
202
242
|
static VALUE
|
203
243
|
re2_matchdata_aref(int argc, VALUE *argv, VALUE self)
|
@@ -205,7 +245,11 @@ extern "C" {
|
|
205
245
|
VALUE idx, rest;
|
206
246
|
rb_scan_args(argc, argv, "11", &idx, &rest);
|
207
247
|
|
208
|
-
if (
|
248
|
+
if (TYPE(idx) == T_STRING) {
|
249
|
+
return re2_matchdata_named_match(StringValuePtr(idx), self);
|
250
|
+
} else if (TYPE(idx) == T_SYMBOL) {
|
251
|
+
return re2_matchdata_named_match(rb_id2name(SYM2ID(idx)), self);
|
252
|
+
} else if (!NIL_P(rest) || !FIXNUM_P(idx) || FIX2INT(idx) < 0) {
|
209
253
|
return rb_ary_aref(argc, argv, re2_matchdata_to_a(self));
|
210
254
|
} else {
|
211
255
|
return re2_matchdata_nth_match(FIX2INT(idx), self);
|
@@ -391,9 +435,9 @@ extern "C" {
|
|
391
435
|
re2_options.set_one_line(RTEST(one_line));
|
392
436
|
}
|
393
437
|
|
394
|
-
p->pattern = new (
|
438
|
+
p->pattern = new (nothrow) RE2(StringValuePtr(pattern), re2_options);
|
395
439
|
} else {
|
396
|
-
p->pattern = new (
|
440
|
+
p->pattern = new (nothrow) RE2(StringValuePtr(pattern));
|
397
441
|
}
|
398
442
|
|
399
443
|
if (p->pattern == 0) {
|
@@ -773,6 +817,32 @@ extern "C" {
|
|
773
817
|
return INT2FIX(p->pattern->NumberOfCapturingGroups());
|
774
818
|
}
|
775
819
|
|
820
|
+
/*
|
821
|
+
* Returns a hash of names to capturing indices of groups.
|
822
|
+
*
|
823
|
+
* @return [Hash] a hash of names to capturing indices
|
824
|
+
*/
|
825
|
+
static VALUE
|
826
|
+
re2_regexp_named_capturing_groups(VALUE self)
|
827
|
+
{
|
828
|
+
VALUE capturing_groups;
|
829
|
+
re2_pattern *p;
|
830
|
+
map<string, int> groups;
|
831
|
+
map<string, int>::iterator iterator;
|
832
|
+
|
833
|
+
Data_Get_Struct(self, re2_pattern, p);
|
834
|
+
groups = p->pattern->NamedCapturingGroups();
|
835
|
+
capturing_groups = rb_hash_new();
|
836
|
+
|
837
|
+
for (iterator = groups.begin(); iterator != groups.end(); iterator++) {
|
838
|
+
rb_hash_aset(capturing_groups,
|
839
|
+
rb_str_new(iterator->first.data(), iterator->first.size()),
|
840
|
+
INT2FIX(iterator->second));
|
841
|
+
}
|
842
|
+
|
843
|
+
return capturing_groups;
|
844
|
+
}
|
845
|
+
|
776
846
|
/*
|
777
847
|
* Match the pattern against the given +text+ and return either
|
778
848
|
* a boolean (if no submatches are required) or a {RE2::MatchData}
|
@@ -836,10 +906,12 @@ extern "C" {
|
|
836
906
|
n = p->pattern->NumberOfCapturingGroups();
|
837
907
|
}
|
838
908
|
|
839
|
-
re2::StringPiece text_as_string_piece(StringValuePtr(text));
|
840
|
-
|
841
909
|
if (n == 0) {
|
842
|
-
|
910
|
+
#if defined(HAVE_ENDPOS_ARGUMENT)
|
911
|
+
matched = p->pattern->Match(StringValuePtr(text), 0, (int)RSTRING_LEN(text), RE2::UNANCHORED, 0, 0);
|
912
|
+
#else
|
913
|
+
matched = p->pattern->Match(StringValuePtr(text), 0, RE2::UNANCHORED, 0, 0);
|
914
|
+
#endif
|
843
915
|
return BOOL2RUBY(matched);
|
844
916
|
} else {
|
845
917
|
|
@@ -848,10 +920,10 @@ extern "C" {
|
|
848
920
|
|
849
921
|
matchdata = rb_class_new_instance(0, 0, re2_cMatchData);
|
850
922
|
Data_Get_Struct(matchdata, re2_matchdata, m);
|
851
|
-
m->matches = new (
|
923
|
+
m->matches = new (nothrow) re2::StringPiece[n];
|
852
924
|
m->regexp = self;
|
853
|
-
m->
|
854
|
-
rb_str_freeze(m->
|
925
|
+
m->text = rb_str_dup(text);
|
926
|
+
rb_str_freeze(m->text);
|
855
927
|
|
856
928
|
if (m->matches == 0) {
|
857
929
|
rb_raise(rb_eNoMemError, "not enough memory to allocate StringPieces for matches");
|
@@ -859,7 +931,11 @@ extern "C" {
|
|
859
931
|
|
860
932
|
m->number_of_matches = n;
|
861
933
|
|
862
|
-
|
934
|
+
#if defined(HAVE_ENDPOS_ARGUMENT)
|
935
|
+
matched = p->pattern->Match(StringValuePtr(text), 0, (int)RSTRING_LEN(text), RE2::UNANCHORED, m->matches, n);
|
936
|
+
#else
|
937
|
+
matched = p->pattern->Match(StringValuePtr(text), 0, RE2::UNANCHORED, m->matches, n);
|
938
|
+
#endif
|
863
939
|
|
864
940
|
if (matched) {
|
865
941
|
return matchdata;
|
@@ -912,19 +988,18 @@ extern "C" {
|
|
912
988
|
re2_pattern *p;
|
913
989
|
|
914
990
|
/* Convert all the inputs to be pumped into RE2::Replace. */
|
915
|
-
|
916
|
-
re2::StringPiece rewrite_as_string_piece(StringValuePtr(rewrite));
|
991
|
+
string str_as_string(StringValuePtr(str));
|
917
992
|
|
918
993
|
/* Do the replacement. */
|
919
994
|
if (rb_obj_is_kind_of(pattern, re2_cRegexp)) {
|
920
995
|
Data_Get_Struct(pattern, re2_pattern, p);
|
921
|
-
RE2::Replace(&str_as_string, *p->pattern,
|
996
|
+
RE2::Replace(&str_as_string, *p->pattern, StringValuePtr(rewrite));
|
922
997
|
} else {
|
923
|
-
RE2::Replace(&str_as_string, StringValuePtr(pattern),
|
998
|
+
RE2::Replace(&str_as_string, StringValuePtr(pattern), StringValuePtr(rewrite));
|
924
999
|
}
|
925
1000
|
|
926
1001
|
/* Save the replacement as a VALUE. */
|
927
|
-
repl = rb_str_new(str_as_string.
|
1002
|
+
repl = rb_str_new(str_as_string.data(), str_as_string.size());
|
928
1003
|
|
929
1004
|
/* Replace the original string with the replacement. */
|
930
1005
|
if (RSTRING_LEN(str) != RSTRING_LEN(repl)) {
|
@@ -961,20 +1036,19 @@ extern "C" {
|
|
961
1036
|
|
962
1037
|
/* Convert all the inputs to be pumped into RE2::GlobalReplace. */
|
963
1038
|
re2_pattern *p;
|
964
|
-
|
965
|
-
re2::StringPiece rewrite_as_string_piece(StringValuePtr(rewrite));
|
1039
|
+
string str_as_string(StringValuePtr(str));
|
966
1040
|
VALUE repl;
|
967
1041
|
|
968
1042
|
/* Do the replacement. */
|
969
1043
|
if (rb_obj_is_kind_of(pattern, re2_cRegexp)) {
|
970
1044
|
Data_Get_Struct(pattern, re2_pattern, p);
|
971
|
-
RE2::GlobalReplace(&str_as_string, *p->pattern,
|
1045
|
+
RE2::GlobalReplace(&str_as_string, *p->pattern, StringValuePtr(rewrite));
|
972
1046
|
} else {
|
973
|
-
RE2::GlobalReplace(&str_as_string, StringValuePtr(pattern),
|
1047
|
+
RE2::GlobalReplace(&str_as_string, StringValuePtr(pattern), StringValuePtr(rewrite));
|
974
1048
|
}
|
975
1049
|
|
976
1050
|
/* Save the replacement as a VALUE. */
|
977
|
-
repl = rb_str_new(str_as_string.
|
1051
|
+
repl = rb_str_new(str_as_string.data(), str_as_string.size());
|
978
1052
|
|
979
1053
|
/* Replace the original string with the replacement. */
|
980
1054
|
if (RSTRING_LEN(str) != RSTRING_LEN(repl)) {
|
@@ -999,8 +1073,7 @@ extern "C" {
|
|
999
1073
|
re2_QuoteMeta(VALUE self, VALUE unquoted)
|
1000
1074
|
{
|
1001
1075
|
UNUSED(self);
|
1002
|
-
|
1003
|
-
std::string quoted_string = RE2::QuoteMeta(unquoted_as_string_piece);
|
1076
|
+
string quoted_string = RE2::QuoteMeta(StringValuePtr(unquoted));
|
1004
1077
|
return rb_str_new(quoted_string.data(), quoted_string.size());
|
1005
1078
|
}
|
1006
1079
|
|
@@ -1030,6 +1103,7 @@ extern "C" {
|
|
1030
1103
|
rb_define_method(re2_cRegexp, "program_size", RUBY_METHOD_FUNC(re2_regexp_program_size), 0);
|
1031
1104
|
rb_define_method(re2_cRegexp, "options", RUBY_METHOD_FUNC(re2_regexp_options), 0);
|
1032
1105
|
rb_define_method(re2_cRegexp, "number_of_capturing_groups", RUBY_METHOD_FUNC(re2_regexp_number_of_capturing_groups), 0);
|
1106
|
+
rb_define_method(re2_cRegexp, "named_capturing_groups", RUBY_METHOD_FUNC(re2_regexp_named_capturing_groups), 0);
|
1033
1107
|
rb_define_method(re2_cRegexp, "match", RUBY_METHOD_FUNC(re2_regexp_match), -1);
|
1034
1108
|
rb_define_method(re2_cRegexp, "match?", RUBY_METHOD_FUNC(re2_regexp_match_query), 1);
|
1035
1109
|
rb_define_method(re2_cRegexp, "=~", RUBY_METHOD_FUNC(re2_regexp_match_query), 1);
|
data/test/re2_test.rb
CHANGED
@@ -121,11 +121,44 @@ class RE2Test < Test::Unit::TestCase
|
|
121
121
|
assert_equal 2, RE2('a((b)c)').number_of_capturing_groups
|
122
122
|
end
|
123
123
|
|
124
|
+
def test_named_capturing_groups
|
125
|
+
assert_equal(1, RE2('(?P<bob>a)').named_capturing_groups["bob"])
|
126
|
+
assert_equal(1, RE2('(?P<bob>a)(o)(?P<rob>e)').named_capturing_groups["bob"])
|
127
|
+
assert_equal(3, RE2('(?P<bob>a)(o)(?P<rob>e)').named_capturing_groups["rob"])
|
128
|
+
end
|
129
|
+
|
124
130
|
def test_matching_all_subpatterns
|
125
131
|
assert_equal ["woo", "o", "o"], RE2('w(o)(o)').match('woo').to_a
|
126
132
|
assert_equal ["ab", nil, "a", "b"], RE2('(\d?)(a)(b)').match('ab').to_a
|
127
133
|
end
|
128
134
|
|
135
|
+
def test_fetching_matchdata_out_of_range
|
136
|
+
matchdata = RE2('(\d+)').match('bob 123')
|
137
|
+
assert_nil matchdata[2]
|
138
|
+
assert_nil matchdata[3]
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_accessing_matches_by_name
|
142
|
+
matchdata = RE2('(?P<numbers>\d+)').match("bob 123")
|
143
|
+
assert_equal "123", matchdata["numbers"]
|
144
|
+
assert_equal "123", matchdata[:numbers]
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_accessing_matches_by_name_with_multiple_groups
|
148
|
+
matchdata = RE2('(?P<name>\w+)(\s*)(?P<numbers>\d+)').match("bob 123")
|
149
|
+
assert_equal "bob", matchdata["name"]
|
150
|
+
assert_equal "bob", matchdata[:name]
|
151
|
+
assert_equal " ", matchdata[2]
|
152
|
+
assert_equal "123", matchdata["numbers"]
|
153
|
+
assert_equal "123", matchdata[:numbers]
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_accessing_matches_by_incorrect_names
|
157
|
+
matchdata = RE2('(?P<numbers>\d+)').match("bob 123")
|
158
|
+
assert_nil matchdata["missing"]
|
159
|
+
assert_nil matchdata[:missing]
|
160
|
+
end
|
161
|
+
|
129
162
|
def test_matchdata
|
130
163
|
r = RE2('(\d+)')
|
131
164
|
text = "bob 123"
|
@@ -146,6 +179,7 @@ class RE2Test < Test::Unit::TestCase
|
|
146
179
|
assert_equal "123", m.to_s
|
147
180
|
assert_equal "123", m[0]
|
148
181
|
assert_equal "123", m[1]
|
182
|
+
assert_nil m[4]
|
149
183
|
assert_equal ["123"], m[0, 1]
|
150
184
|
assert_equal ["123", "123"], m[0, 2]
|
151
185
|
assert_equal ["123"], m[0...1]
|
metadata
CHANGED
@@ -1,83 +1,64 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: re2
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 2
|
8
|
-
- 0
|
9
|
-
version: 0.2.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Paul Mucur
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2012-02-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: rake-compiler
|
22
|
-
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &70320711075760 !ruby/object:Gem::Requirement
|
24
17
|
none: false
|
25
|
-
requirements:
|
26
|
-
- -
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
- 0
|
30
|
-
version: "0"
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
31
22
|
type: :development
|
32
|
-
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70320711075760
|
33
25
|
description: Ruby bindings to re2, "an efficient, principled regular expression library".
|
34
26
|
email: ruby.re2@librelist.com
|
35
27
|
executables: []
|
36
|
-
|
37
|
-
extensions:
|
28
|
+
extensions:
|
38
29
|
- ext/re2/extconf.rb
|
39
30
|
extra_rdoc_files: []
|
40
|
-
|
41
|
-
files:
|
31
|
+
files:
|
42
32
|
- ext/re2/extconf.rb
|
43
33
|
- ext/re2/re2.cc
|
44
34
|
- LICENSE.txt
|
45
35
|
- README.md
|
46
36
|
- Rakefile
|
47
37
|
- test/re2_test.rb
|
48
|
-
- test/leak.rb
|
49
|
-
has_rdoc: true
|
50
38
|
homepage: http://github.com/mudge/re2
|
51
39
|
licenses: []
|
52
|
-
|
53
40
|
post_install_message:
|
54
41
|
rdoc_options: []
|
55
|
-
|
56
|
-
require_paths:
|
42
|
+
require_paths:
|
57
43
|
- lib
|
58
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
45
|
none: false
|
60
|
-
requirements:
|
61
|
-
- -
|
62
|
-
- !ruby/object:Gem::Version
|
63
|
-
|
64
|
-
|
65
|
-
version: "0"
|
66
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
51
|
none: false
|
68
|
-
requirements:
|
69
|
-
- -
|
70
|
-
- !ruby/object:Gem::Version
|
71
|
-
|
72
|
-
- 0
|
73
|
-
version: "0"
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
74
56
|
requirements: []
|
75
|
-
|
76
57
|
rubyforge_project:
|
77
|
-
rubygems_version: 1.
|
58
|
+
rubygems_version: 1.8.11
|
78
59
|
signing_key:
|
79
60
|
specification_version: 3
|
80
61
|
summary: Ruby bindings to re2.
|
81
|
-
test_files:
|
62
|
+
test_files:
|
82
63
|
- test/re2_test.rb
|
83
|
-
|
64
|
+
has_rdoc:
|
data/test/leak.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
-
require 're2'
|
3
|
-
|
4
|
-
loops = if ENV["LOOPS"]
|
5
|
-
ENV["LOOPS"].to_i
|
6
|
-
else
|
7
|
-
150
|
8
|
-
end
|
9
|
-
|
10
|
-
puts "Looping #{loops} times..."
|
11
|
-
|
12
|
-
loops.times do
|
13
|
-
r = RE2::Regexp.new('woo(oo)(o+)(\d*)')
|
14
|
-
r.ok?
|
15
|
-
r.match('wooo')
|
16
|
-
r.match('wooo', 0)
|
17
|
-
r.match('wooo', 1)
|
18
|
-
r.match('wooo', 2)
|
19
|
-
r =~ 'woooo'
|
20
|
-
r =~ 'bob'
|
21
|
-
RE2::Replace("woo", "woo", "bob")
|
22
|
-
RE2::GlobalReplace("woo", "woo", "bob")
|
23
|
-
m = r.match('woooooo1234')
|
24
|
-
m[0]
|
25
|
-
m[1]
|
26
|
-
m[0,2]
|
27
|
-
m[1..-1]
|
28
|
-
m.string
|
29
|
-
m.regexp
|
30
|
-
m.inspect
|
31
|
-
sleep 0.1
|
32
|
-
end
|