2
2
//
3
3
// It provides the following Unicode aware functions:
4
4
// - regexp_like(),
5
+ // - regexp_count(),
6
+ // - regexp_instr(),
5
7
// - regexp_substr(),
6
8
// - regexp_replace(),
7
9
// - and a REGEXP operator.
@@ -24,8 +26,17 @@ func Register(db *sqlite3.Conn) error {
24
26
return errors .Join (
25
27
db .CreateFunction ("regexp" , 2 , flags , regex ),
26
28
db .CreateFunction ("regexp_like" , 2 , flags , regexLike ),
29
+ db .CreateFunction ("regexp_count" , 2 , flags , regexCount ),
30
+ db .CreateFunction ("regexp_count" , 3 , flags , regexCount ),
31
+ db .CreateFunction ("regexp_instr" , 2 , flags , regexInstr ),
32
+ db .CreateFunction ("regexp_instr" , 3 , flags , regexInstr ),
33
+ db .CreateFunction ("regexp_instr" , 4 , flags , regexInstr ),
34
+ db .CreateFunction ("regexp_instr" , 5 , flags , regexInstr ),
27
35
db .CreateFunction ("regexp_substr" , 2 , flags , regexSubstr ),
28
- db .CreateFunction ("regexp_replace" , 3 , flags , regexReplace ))
36
+ db .CreateFunction ("regexp_substr" , 3 , flags , regexSubstr ),
37
+ db .CreateFunction ("regexp_substr" , 4 , flags , regexSubstr ),
38
+ db .CreateFunction ("regexp_replace" , 3 , flags , regexReplace ),
39
+ db .CreateFunction ("regexp_replace" , 4 , flags , regexReplace ))
29
40
}
30
41
31
42
func load (ctx sqlite3.Context , i int , expr string ) (* regexp.Regexp , error ) {
@@ -44,35 +55,126 @@ func load(ctx sqlite3.Context, i int, expr string) (*regexp.Regexp, error) {
44
55
func regex (ctx sqlite3.Context , arg ... sqlite3.Value ) {
45
56
re , err := load (ctx , 0 , arg [0 ].Text ())
46
57
if err != nil {
47
- ctx .ResultError (err ) // notest
48
- } else {
49
- ctx .ResultBool (re .Match (arg [1 ].RawText ()))
58
+ ctx .ResultError (err )
59
+ return // notest
50
60
}
61
+ text := arg [1 ].RawText ()
62
+ ctx .ResultBool (re .Match (text ))
51
63
}
52
64
53
65
func regexLike (ctx sqlite3.Context , arg ... sqlite3.Value ) {
54
66
re , err := load (ctx , 1 , arg [1 ].Text ())
55
67
if err != nil {
56
- ctx .ResultError (err ) // notest
57
- } else {
58
- ctx .ResultBool (re .Match (arg [0 ].RawText ()))
68
+ ctx .ResultError (err )
69
+ return // notest
59
70
}
71
+ text := arg [0 ].RawText ()
72
+ ctx .ResultBool (re .Match (text ))
73
+ }
74
+
75
+ func regexCount (ctx sqlite3.Context , arg ... sqlite3.Value ) {
76
+ re , err := load (ctx , 1 , arg [1 ].Text ())
77
+ if err != nil {
78
+ ctx .ResultError (err )
79
+ return // notest
80
+ }
81
+ text := arg [0 ].RawText ()
82
+ if len (arg ) > 2 {
83
+ pos := arg [2 ].Int ()
84
+ _ , text = split (text , pos )
85
+ }
86
+ ctx .ResultInt (len (re .FindAll (text , - 1 )))
60
87
}
61
88
62
89
func regexSubstr (ctx sqlite3.Context , arg ... sqlite3.Value ) {
63
90
re , err := load (ctx , 1 , arg [1 ].Text ())
64
91
if err != nil {
65
- ctx .ResultError (err ) // notest
92
+ ctx .ResultError (err )
93
+ return // notest
94
+ }
95
+ text := arg [0 ].RawText ()
96
+ if len (arg ) > 2 {
97
+ pos := arg [2 ].Int ()
98
+ _ , text = split (text , pos )
99
+ }
100
+ n := 0
101
+ if len (arg ) > 3 {
102
+ n = arg [3 ].Int ()
103
+ }
104
+
105
+ var res []byte
106
+ if n <= 1 {
107
+ res = re .Find (text )
66
108
} else {
67
- ctx .ResultRawText (re .Find (arg [0 ].RawText ()))
109
+ all := re .FindAll (text , n )
110
+ if n <= len (all ) {
111
+ res = all [n - 1 ]
112
+ }
68
113
}
114
+ ctx .ResultRawText (res )
69
115
}
70
116
71
- func regexReplace (ctx sqlite3.Context , arg ... sqlite3.Value ) {
117
+ func regexInstr (ctx sqlite3.Context , arg ... sqlite3.Value ) {
72
118
re , err := load (ctx , 1 , arg [1 ].Text ())
73
119
if err != nil {
74
- ctx .ResultError (err ) // notest
120
+ ctx .ResultError (err )
121
+ return // notest
122
+ }
123
+ pos := 1
124
+ text := arg [0 ].RawText ()
125
+ if len (arg ) > 2 {
126
+ pos = arg [2 ].Int ()
127
+ _ , text = split (text , pos )
128
+ }
129
+ n := 0
130
+ if len (arg ) > 3 {
131
+ n = arg [3 ].Int ()
132
+ }
133
+
134
+ var loc []int
135
+ if n <= 1 {
136
+ loc = re .FindIndex (text )
75
137
} else {
76
- ctx .ResultRawText (re .ReplaceAll (arg [0 ].RawText (), arg [2 ].RawText ()))
138
+ all := re .FindAllIndex (text , n )
139
+ if n <= len (all ) {
140
+ loc = all [n - 1 ]
141
+ }
142
+ }
143
+ if loc == nil {
144
+ return
145
+ }
146
+
147
+ end := 0
148
+ if len (arg ) > 4 && arg [4 ].Bool () {
149
+ end = 1
150
+ }
151
+ ctx .ResultInt (pos + loc [end ])
152
+ }
153
+
154
+ func regexReplace (ctx sqlite3.Context , arg ... sqlite3.Value ) {
155
+ re , err := load (ctx , 1 , arg [1 ].Text ())
156
+ if err != nil {
157
+ ctx .ResultError (err )
158
+ return // notest
159
+ }
160
+ var head , tail []byte
161
+ tail = arg [0 ].RawText ()
162
+ if len (arg ) > 3 {
163
+ pos := arg [3 ].Int ()
164
+ head , tail = split (tail , pos )
165
+ }
166
+ tail = re .ReplaceAll (tail , arg [2 ].RawText ())
167
+ if head != nil {
168
+ tail = append (head , tail ... )
169
+ }
170
+ ctx .ResultRawText (tail )
171
+ }
172
+
173
+ func split (s []byte , i int ) (head , tail []byte ) {
174
+ for pos := range string (s ) {
175
+ if i -- ; i <= 0 {
176
+ return s [:pos :pos ], s [pos :]
177
+ }
77
178
}
179
+ return s , nil
78
180
}
0 commit comments