-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrb_u_string_scan.c
More file actions
109 lines (92 loc) · 3.45 KB
/
Copy pathrb_u_string_scan.c
File metadata and controls
109 lines (92 loc) · 3.45 KB
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
#include "rb_includes.h"
#include "rb_u_re.h"
static VALUE
rb_u_string_scan_once(VALUE string, VALUE pattern, long *start, long *last)
{
if (rb_reg_search(pattern, string, *start, false) < 0) {
if (*last >= 0)
rb_reg_search(pattern, string, *last, false);
return Qnil;
}
*last = *start;
VALUE match = rb_backref_get();
struct re_registers *registers = RMATCH_REGS(match);
if (registers->beg[0] == registers->end[0]) {
if (RSTRING_LEN(string) > registers->end[0])
*start = registers->end[0] +
(u_next(RSTRING_PTR(string) + registers->end[0]) -
(RSTRING_PTR(string) + registers->end[0]));
else
*start = registers->end[0] + 1;
} else {
*start = registers->end[0];
}
if (registers->num_regs == 1)
return rb_u_string_new_rb(rb_reg_nth_match(0, match));
VALUE result = rb_ary_new2(registers->num_regs);
for (int i = 1; i < registers->num_regs; i++)
rb_ary_push(result, rb_u_string_new_rb(rb_reg_nth_match(i, match)));
return result;
}
static VALUE
rb_u_string_scan_block(VALUE self, VALUE string, VALUE pattern)
{
VALUE result;
long start = 0;
long last = -1;
while (!NIL_P(result = rb_u_string_scan_once(string, pattern, &start, &last)))
rb_yield(result);
return self;
}
static VALUE
rb_u_string_scan_array(VALUE string, VALUE pattern)
{
VALUE result;
long start = 0;
long last = -1;
VALUE array = rb_ary_new();
while (!NIL_P(result = rb_u_string_scan_once(string, pattern, &start, &last)))
rb_ary_push(array, result);
return array;
}
/* @overload scan(pattern)
* @param [Regexp] pattern
* @return [Array<U::String>, Array<Array<U::String>>] All matches – or
* sub-matches, if they exist – of matches of PATTERN in the receiver, each
* inheriting any taint and untrust from both the receiver and from PATTERN
* @note The Regexp special variables `$&`, `$'`, <code>$\`</code>, `$1`,
* `$2`, …, `$`_n_ are updated accordingly.
*
* @overload scan(pattern)
* @param [#to_str] pattern
* @return [Array<U::String>] All matches of PATTERN in the receiver, each
* inheriting any taint and untrust from the receiver
*
* @overload scan(pattern){ |*submatches| … }
*
* Enumerates the sub-matches of matches of PATTERN in the receiver, each
* inheriting any taint and untrust from both the receiver and from PATTERN.
*
* @param [Regexp] pattern
* @yieldparam [Array<U::String>] submatches
* @return [self]
* @note The Regexp special variables `$&`, `$'`, <code>$\`</code>, `$1`,
* `$2`, …, `$`_n_ are updated accordingly.
*
* @overload scan(pattern){ |match| … }
*
* Enumerates the matches of PATTERN in the receiver, each inheriting any
* taint and untrust from the receiver.
*
* @param [#to_str] pattern
* @yieldparam [U::String] match
* @return [self] */
VALUE
rb_u_string_scan(VALUE self, VALUE pattern)
{
pattern = rb_u_pattern_argument(pattern, true);
VALUE string = rb_str_to_str(self);
if (rb_block_given_p())
return rb_u_string_scan_block(self, string, pattern);
return rb_u_string_scan_array(string, pattern);
}