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
|
require_relative '../../spec_helper'
require_relative '../fixtures/classes'
describe "Regexps with repetition" do
it "supports * (0 or more of previous subexpression)" do
/a*/.match("aaa").to_a.should == ["aaa"]
/a*/.match("bbb").to_a.should == [""]
/<.*>/.match("<a>foo</a>").to_a.should == ["<a>foo</a>"] # it is greedy
end
it "supports *? (0 or more of previous subexpression - lazy)" do
/a*?/.match("aaa").to_a.should == [""]
/<.*?>/.match("<a>foo</a>").to_a.should == ["<a>"]
end
it "supports + (1 or more of previous subexpression)" do
/a+/.match("aaa").to_a.should == ["aaa"]
/a+/.match("bbb").should be_nil
/<.+>/.match("<a>foo</a>").to_a.should == ["<a>foo</a>"] # it is greedy
end
it "supports +? (0 or more of previous subexpression - lazy)" do
/a+?/.match("aaa").to_a.should == ["a"]
/<.+?>/.match("<a>foo</a>").to_a.should == ["<a>"]
end
it "supports {m,n} (m to n of previous subexpression)" do
/a{2,4}/.match("aaaaaa").to_a.should == ["aaaa"]
/<.{1,}>/.match("<a>foo</a>").to_a.should == ["<a>foo</a>"] # it is greedy
end
it "supports {m,n}? (m to n of previous subexpression) - lazy)" do
/<.{1,}?>/.match("<a>foo</a>").to_a.should == ["<a>"]
/.([0-9]){3,5}?foo/.match("9876543210foo").to_a.should == ["543210foo", "0"]
end
it "does not treat {m,n}+ as possessive" do
-> {
@regexp = eval "/foo(A{0,1}+)Abar/"
}.should complain(/nested repeat operator/)
@regexp.match("fooAAAbar").to_a.should == ["fooAAAbar", "AA"]
end
it "supports ? (0 or 1 of previous subexpression)" do
/a?/.match("aaa").to_a.should == ["a"]
/a?/.match("bbb").to_a.should == [""]
end
it "handles incomplete range quantifiers" do
/a{}/.match("a{}")[0].should == "a{}"
/a{,}/.match("a{,}")[0].should == "a{,}"
/a{1/.match("a{1")[0].should == "a{1"
/a{1,2/.match("a{1,2")[0].should == "a{1,2"
/a{,5}/.match("aaa")[0].should == "aaa"
end
it "lets us use quantifiers on assertions" do
/a^?b/.match("ab")[0].should == "ab"
/a$?b/.match("ab")[0].should == "ab"
/a\A?b/.match("ab")[0].should == "ab"
/a\Z?b/.match("ab")[0].should == "ab"
/a\z?b/.match("ab")[0].should == "ab"
/a\G?b/.match("ab")[0].should == "ab"
/a\b?b/.match("ab")[0].should == "ab"
/a\B?b/.match("ab")[0].should == "ab"
/a(?=c)?b/.match("ab")[0].should == "ab"
/a(?!=b)?b/.match("ab")[0].should == "ab"
/a(?<=c)?b/.match("ab")[0].should == "ab"
/a(?<!a)?b/.match("ab")[0].should == "ab"
end
it "does not delete optional assertions" do
/(?=(a))?/.match("a").to_a.should == [ "", "a" ]
end
it "supports nested quantifiers" do
suppress_warning do
eval <<-RUBY
/a***/.match("aaa")[0].should == "aaa"
# a+?* should not be reduced, it should be equivalent to (a+?)*
# NB: the capture group prevents regex engines from reducing the two quantifiers
# https://bugs.ruby-lang.org/issues/17341
/a+?*/.match("")[0].should == ""
/(a+?)*/.match("")[0].should == ""
/a+?*/.match("a")[0].should == "a"
/(a+?)*/.match("a")[0].should == "a"
/a+?*/.match("aa")[0].should == "aa"
/(a+?)*/.match("aa")[0].should == "aa"
# a+?+ should not be reduced, it should be equivalent to (a+?)+
# https://bugs.ruby-lang.org/issues/17341
/a+?+/.match("").should == nil
/(a+?)+/.match("").should == nil
/a+?+/.match("a")[0].should == "a"
/(a+?)+/.match("a")[0].should == "a"
/a+?+/.match("aa")[0].should == "aa"
/(a+?)+/.match("aa")[0].should == "aa"
# both a**? and a+*? should be equivalent to (a+)??
# this quantifier would rather match nothing, but if that's not possible,
# it will greedily take everything
/a**?/.match("")[0].should == ""
/(a*)*?/.match("")[0].should == ""
/a+*?/.match("")[0].should == ""
/(a+)*?/.match("")[0].should == ""
/(a+)??/.match("")[0].should == ""
/a**?/.match("aaa")[0].should == ""
/(a*)*?/.match("aaa")[0].should == ""
/a+*?/.match("aaa")[0].should == ""
/(a+)*?/.match("aaa")[0].should == ""
/(a+)??/.match("aaa")[0].should == ""
/b.**?b/.match("baaabaaab")[0].should == "baaabaaab"
/b(.*)*?b/.match("baaabaaab")[0].should == "baaabaaab"
/b.+*?b/.match("baaabaaab")[0].should == "baaabaaab"
/b(.+)*?b/.match("baaabaaab")[0].should == "baaabaaab"
/b(.+)??b/.match("baaabaaab")[0].should == "baaabaaab"
RUBY
end
end
it "treats ? after {n} quantifier as another quantifier, not as non-greedy marker" do
/a{2}?/.match("").to_a.should == [""]
end
it "matches zero-width capture groups in optional iterations of loops" do
/()?/.match("").to_a.should == ["", ""]
/(a*)?/.match("").to_a.should == ["", ""]
/(a*)*/.match("").to_a.should == ["", ""]
/(?:a|()){500,1000}/.match("a" * 500).to_a.should == ["a" * 500, ""]
end
end
|