glib/regex.rs
1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! This module is inefficient and should not be used by Rust programs except for
5//! compatibility with GLib.Regex based APIs.
6
7use crate::{
8 GStr, GStringPtr, MatchInfo, PtrSlice, Regex, RegexCompileFlags, RegexMatchFlags, ffi,
9 translate::*,
10};
11use std::{mem, ptr};
12
13impl Regex {
14 /// Retrieves the number of the subexpression named @name.
15 /// ## `name`
16 /// name of the subexpression
17 ///
18 /// # Returns
19 ///
20 /// The number of the subexpression or -1 if @name
21 /// does not exists
22 #[doc(alias = "g_regex_get_string_number")]
23 #[doc(alias = "get_string_number")]
24 pub fn string_number(&self, name: impl IntoGStr) -> i32 {
25 name.run_with_gstr(|name| unsafe {
26 ffi::g_regex_get_string_number(self.to_glib_none().0, name.to_glib_none().0)
27 })
28 }
29
30 /// Escapes the nul characters in @string to "\x00". It can be used
31 /// to compile a regex with embedded nul characters.
32 ///
33 /// For completeness, @length can be -1 for a nul-terminated string.
34 /// In this case the output string will be of course equal to @string.
35 /// ## `string`
36 /// the string to escape
37 /// ## `length`
38 /// the length of @string
39 ///
40 /// # Returns
41 ///
42 /// a newly-allocated escaped string
43 #[doc(alias = "g_regex_escape_nul")]
44 pub fn escape_nul(string: impl IntoGStr) -> crate::GString {
45 unsafe {
46 string.run_with_gstr(|string| {
47 from_glib_full(ffi::g_regex_escape_nul(
48 string.to_glib_none().0,
49 string.len() as _,
50 ))
51 })
52 }
53 }
54
55 /// Escapes the special characters used for regular expressions
56 /// in @string, for instance "a.b*c" becomes "a\.b\*c". This
57 /// function is useful to dynamically generate regular expressions.
58 ///
59 /// @string can contain nul characters that are replaced with "\0",
60 /// in this case remember to specify the correct length of @string
61 /// in @length.
62 /// ## `string`
63 /// the string to escape
64 /// ## `length`
65 /// the length of @string, in bytes, or -1 if @string is nul-terminated
66 ///
67 /// # Returns
68 ///
69 /// a newly-allocated escaped string
70 #[doc(alias = "g_regex_escape_string")]
71 pub fn escape_string(string: impl IntoGStr) -> crate::GString {
72 unsafe {
73 string.run_with_gstr(|string| {
74 from_glib_full(ffi::g_regex_escape_string(
75 string.to_glib_none().0,
76 string.len() as _,
77 ))
78 })
79 }
80 }
81
82 /// Checks whether @replacement is a valid replacement string
83 /// (see g_regex_replace()), i.e. that all escape sequences in
84 /// it are valid.
85 ///
86 /// If @has_references is not [`None`] then @replacement is checked
87 /// for pattern references. For instance, replacement text 'foo\n'
88 /// does not contain references and may be evaluated without information
89 /// about actual match, but '\0\1' (whole match followed by first
90 /// subpattern) requires valid #GMatchInfo object.
91 /// ## `replacement`
92 /// the replacement string
93 ///
94 /// # Returns
95 ///
96 /// whether @replacement is a valid replacement string
97 ///
98 /// ## `has_references`
99 /// location to store information about
100 /// references in @replacement or [`None`]
101 #[doc(alias = "g_regex_check_replacement")]
102 pub fn check_replacement(replacement: impl IntoGStr) -> Result<bool, crate::Error> {
103 replacement.run_with_gstr(|replacement| unsafe {
104 let mut has_references = mem::MaybeUninit::uninit();
105 let mut error = ptr::null_mut();
106 let is_ok = ffi::g_regex_check_replacement(
107 replacement.to_glib_none().0,
108 has_references.as_mut_ptr(),
109 &mut error,
110 );
111 debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null());
112 if error.is_null() {
113 Ok(from_glib(has_references.assume_init()))
114 } else {
115 Err(from_glib_full(error))
116 }
117 })
118 }
119
120 /// Scans for a match in @string for @pattern.
121 ///
122 /// This function is equivalent to g_regex_match() but it does not
123 /// require to compile the pattern with g_regex_new(), avoiding some
124 /// lines of code when you need just to do a match without extracting
125 /// substrings, capture counts, and so on.
126 ///
127 /// If this function is to be called on the same @pattern more than
128 /// once, it's more efficient to compile the pattern once with
129 /// g_regex_new() and then use g_regex_match().
130 /// ## `pattern`
131 /// the regular expression
132 /// ## `string`
133 /// the string to scan for matches
134 /// ## `compile_options`
135 /// compile options for the regular expression, or 0
136 /// ## `match_options`
137 /// match options, or 0
138 ///
139 /// # Returns
140 ///
141 /// [`true`] if the string matched, [`false`] otherwise
142 #[doc(alias = "g_regex_match_simple")]
143 pub fn match_simple(
144 pattern: impl IntoGStr,
145 string: impl IntoGStr,
146 compile_options: RegexCompileFlags,
147 match_options: RegexMatchFlags,
148 ) -> bool {
149 pattern.run_with_gstr(|pattern| {
150 string.run_with_gstr(|string| unsafe {
151 from_glib(ffi::g_regex_match_simple(
152 pattern.to_glib_none().0,
153 string.to_glib_none().0,
154 compile_options.into_glib(),
155 match_options.into_glib(),
156 ))
157 })
158 })
159 }
160
161 /// ` refers
162 /// to the captured subexpression with the given name. `\0` refers
163 /// to the complete match, but `\0` followed by a number is the octal
164 /// representation of a character. To include a literal `\` in the
165 /// replacement, write `\\\\`.
166 ///
167 /// There are also escapes that changes the case of the following text:
168 ///
169 /// - `\l`: Convert to lower case the next character
170 /// - `\u`: Convert to upper case the next character
171 /// - `\L`: Convert to lower case until the next `\E`
172 /// - `\U`: Convert to upper case until the next `\E`
173 /// - `\E`: End case modification
174 ///
175 /// If you do not need to use backreferences use g_regex_replace_literal().
176 ///
177 /// The @replacement string must be UTF-8 encoded even if [`RegexCompileFlags::RAW`][crate::RegexCompileFlags::RAW] was
178 /// passed to g_regex_new(). If you want to use not UTF-8 encoded strings
179 /// you can use g_regex_replace_literal().
180 ///
181 /// Setting @start_position differs from just passing over a shortened
182 /// string and setting [`RegexMatchFlags::NOTBOL`][crate::RegexMatchFlags::NOTBOL] in the case of a pattern that
183 /// begins with any kind of lookbehind assertion, such as `"\b"`.
184 /// ## `string`
185 /// the string to perform matches against
186 /// ## `string_len`
187 /// the length of @string, in bytes, or -1 if @string is nul-terminated
188 /// ## `start_position`
189 /// starting index of the string to match, in bytes
190 /// ## `replacement`
191 /// text to replace each match with
192 /// ## `match_options`
193 /// options for the match
194 ///
195 /// # Returns
196 ///
197 /// a newly allocated string containing the replacements
198 #[doc(alias = "g_regex_replace")]
199 pub fn replace(
200 &self,
201 string: impl IntoGStr,
202 start_position: i32,
203 replacement: impl IntoGStr,
204 match_options: RegexMatchFlags,
205 ) -> Result<crate::GString, crate::Error> {
206 unsafe {
207 string.run_with_gstr(|string| {
208 replacement.run_with_gstr(|replacement| {
209 let mut error = ptr::null_mut();
210 let ret = ffi::g_regex_replace(
211 self.to_glib_none().0,
212 string.as_ptr() as *const _,
213 string.len() as _,
214 start_position,
215 replacement.to_glib_none().0,
216 match_options.into_glib(),
217 &mut error,
218 );
219 debug_assert_eq!(ret.is_null(), !error.is_null());
220 if error.is_null() {
221 Ok(from_glib_full(ret))
222 } else {
223 Err(from_glib_full(error))
224 }
225 })
226 })
227 }
228 }
229
230 /// Using the standard algorithm for regular expression matching only
231 /// the longest match in the string is retrieved. This function uses
232 /// a different algorithm so it can retrieve all the possible matches.
233 /// For more documentation see g_regex_match_all_full().
234 ///
235 /// A #GMatchInfo structure, used to get information on the match, is
236 /// stored in @match_info if not [`None`]. Note that if @match_info is
237 /// not [`None`] then it is created even if the function returns [`false`],
238 /// i.e. you must free it regardless if regular expression actually
239 /// matched.
240 ///
241 /// @string is not copied and is used in #GMatchInfo internally. If
242 /// you use any #GMatchInfo method (except g_match_info_free()) after
243 /// freeing or modifying @string then the behaviour is undefined.
244 /// ## `string`
245 /// the string to scan for matches
246 /// ## `match_options`
247 /// match options
248 ///
249 /// # Returns
250 ///
251 /// [`true`] is the string matched, [`false`] otherwise
252 ///
253 /// ## `match_info`
254 /// pointer to location where to store
255 /// the #GMatchInfo, or [`None`] if you do not need it
256 #[doc(alias = "g_regex_match_all")]
257 pub fn match_all<'input>(
258 &self,
259 string: &'input GStr,
260 match_options: RegexMatchFlags,
261 ) -> Result<MatchInfo<'input>, crate::Error> {
262 self.match_all_full(string, 0, match_options)
263 }
264
265 /// "`.
266 ///
267 /// The number of matched strings is retrieved using
268 /// g_match_info_get_match_count(). To obtain the matched strings and
269 /// their position you can use, respectively, g_match_info_fetch() and
270 /// g_match_info_fetch_pos(). Note that the strings are returned in
271 /// reverse order of length; that is, the longest matching string is
272 /// given first.
273 ///
274 /// Note that the DFA algorithm is slower than the standard one and it
275 /// is not able to capture substrings, so backreferences do not work.
276 ///
277 /// Setting @start_position differs from just passing over a shortened
278 /// string and setting [`RegexMatchFlags::NOTBOL`][crate::RegexMatchFlags::NOTBOL] in the case of a pattern
279 /// that begins with any kind of lookbehind assertion, such as "\b".
280 ///
281 /// Unless [`RegexCompileFlags::RAW`][crate::RegexCompileFlags::RAW] is specified in the options, @string must be valid UTF-8.
282 ///
283 /// A #GMatchInfo structure, used to get information on the match, is
284 /// stored in @match_info if not [`None`]. Note that if @match_info is
285 /// not [`None`] then it is created even if the function returns [`false`],
286 /// i.e. you must free it regardless if regular expression actually
287 /// matched.
288 ///
289 /// @string is not copied and is used in #GMatchInfo internally. If
290 /// you use any #GMatchInfo method (except g_match_info_free()) after
291 /// freeing or modifying @string then the behaviour is undefined.
292 /// ## `string`
293 /// the string to scan for matches
294 /// ## `string_len`
295 /// the length of @string, in bytes, or -1 if @string is nul-terminated
296 /// ## `start_position`
297 /// starting index of the string to match, in bytes
298 /// ## `match_options`
299 /// match options
300 ///
301 /// # Returns
302 ///
303 /// [`true`] is the string matched, [`false`] otherwise
304 ///
305 /// ## `match_info`
306 /// pointer to location where to store
307 /// the #GMatchInfo, or [`None`] if you do not need it
308 #[doc(alias = "g_regex_match_all_full")]
309 pub fn match_all_full<'input>(
310 &self,
311 string: &'input GStr,
312 start_position: i32,
313 match_options: RegexMatchFlags,
314 ) -> Result<MatchInfo<'input>, crate::Error> {
315 unsafe {
316 let mut match_info = ptr::null_mut();
317 let mut error = ptr::null_mut();
318 let res = ffi::g_regex_match_all_full(
319 self.to_glib_none().0,
320 string.to_glib_none().0,
321 string.len() as _,
322 start_position,
323 match_options.into_glib(),
324 &mut match_info,
325 &mut error,
326 );
327 if error.is_null() {
328 let match_info = MatchInfo::from_glib_full(match_info);
329 debug_assert_eq!(match_info.matches(), from_glib(res));
330 Ok(match_info)
331 } else {
332 debug_assert!(match_info.is_null());
333 Err(from_glib_full(error))
334 }
335 }
336 }
337
338 /// match_info);
339 /// while (g_match_info_matches (match_info))
340 /// {
341 /// gchar *word = g_match_info_fetch (match_info, 0);
342 /// g_print ("Found: `s`\n", word);
343 /// g_free (word);
344 /// g_match_info_next (match_info, NULL);
345 /// }
346 /// g_match_info_free (match_info);
347 /// g_regex_unref (regex);
348 /// }
349 /// ]|
350 ///
351 /// @string is not copied and is used in #GMatchInfo internally. If
352 /// you use any #GMatchInfo method (except g_match_info_free()) after
353 /// freeing or modifying @string then the behaviour is undefined.
354 /// ## `string`
355 /// the string to scan for matches
356 /// ## `match_options`
357 /// match options
358 ///
359 /// # Returns
360 ///
361 /// [`true`] is the string matched, [`false`] otherwise
362 ///
363 /// ## `match_info`
364 /// pointer to location where to store
365 /// the #GMatchInfo, or [`None`] if you do not need it
366 #[doc(alias = "g_regex_match")]
367 pub fn match_<'input>(
368 &self,
369 string: &'input GStr,
370 match_options: RegexMatchFlags,
371 ) -> Result<MatchInfo<'input>, crate::Error> {
372 self.match_full(string, 0, match_options)
373 }
374
375 /// message);
376 /// g_error_free (error);
377 /// }
378 /// }
379 /// ]|
380 /// ## `string`
381 /// the string to scan for matches
382 /// ## `string_len`
383 /// the length of @string, in bytes, or -1 if @string is nul-terminated
384 /// ## `start_position`
385 /// starting index of the string to match, in bytes
386 /// ## `match_options`
387 /// match options
388 ///
389 /// # Returns
390 ///
391 /// [`true`] is the string matched, [`false`] otherwise
392 ///
393 /// ## `match_info`
394 /// pointer to location where to store
395 /// the #GMatchInfo, or [`None`] if you do not need it
396 #[doc(alias = "g_regex_match_full")]
397 pub fn match_full<'input>(
398 &self,
399 string: &'input GStr,
400 start_position: i32,
401 match_options: RegexMatchFlags,
402 ) -> Result<MatchInfo<'input>, crate::Error> {
403 unsafe {
404 let mut match_info = ptr::null_mut();
405 let mut error = ptr::null_mut();
406 let res = ffi::g_regex_match_full(
407 self.to_glib_none().0,
408 string.to_glib_none().0,
409 string.len() as _,
410 start_position,
411 match_options.into_glib(),
412 &mut match_info,
413 &mut error,
414 );
415 if error.is_null() {
416 let match_info = MatchInfo::from_glib_full(match_info);
417 debug_assert_eq!(match_info.matches(), from_glib(res));
418 Ok(match_info)
419 } else {
420 debug_assert!(match_info.is_null());
421 Err(from_glib_full(error))
422 }
423 }
424 }
425
426 /// Replaces all occurrences of the pattern in @self with the
427 /// replacement text. @replacement is replaced literally, to
428 /// include backreferences use g_regex_replace().
429 ///
430 /// Setting @start_position differs from just passing over a
431 /// shortened string and setting [`RegexMatchFlags::NOTBOL`][crate::RegexMatchFlags::NOTBOL] in the
432 /// case of a pattern that begins with any kind of lookbehind
433 /// assertion, such as "\b".
434 /// ## `string`
435 /// the string to perform matches against
436 /// ## `string_len`
437 /// the length of @string, in bytes, or -1 if @string is nul-terminated
438 /// ## `start_position`
439 /// starting index of the string to match, in bytes
440 /// ## `replacement`
441 /// text to replace each match with
442 /// ## `match_options`
443 /// options for the match
444 ///
445 /// # Returns
446 ///
447 /// a newly allocated string containing the replacements
448 #[doc(alias = "g_regex_replace_literal")]
449 pub fn replace_literal(
450 &self,
451 string: impl IntoGStr,
452 start_position: i32,
453 replacement: impl IntoGStr,
454 match_options: RegexMatchFlags,
455 ) -> Result<crate::GString, crate::Error> {
456 unsafe {
457 string.run_with_gstr(|string| {
458 replacement.run_with_gstr(|replacement| {
459 let mut error = ptr::null_mut();
460 let ret = ffi::g_regex_replace_literal(
461 self.to_glib_none().0,
462 string.to_glib_none().0,
463 string.len() as _,
464 start_position,
465 replacement.to_glib_none().0,
466 match_options.into_glib(),
467 &mut error,
468 );
469 debug_assert_eq!(ret.is_null(), !error.is_null());
470 if error.is_null() {
471 Ok(from_glib_full(ret))
472 } else {
473 Err(from_glib_full(error))
474 }
475 })
476 })
477 }
478 }
479
480 /// Breaks the string on the pattern, and returns an array of the tokens.
481 /// If the pattern contains capturing parentheses, then the text for each
482 /// of the substrings will also be returned. If the pattern does not match
483 /// anywhere in the string, then the whole string is returned as the first
484 /// token.
485 ///
486 /// As a special case, the result of splitting the empty string "" is an
487 /// empty vector, not a vector containing a single string. The reason for
488 /// this special case is that being able to represent an empty vector is
489 /// typically more useful than consistent handling of empty elements. If
490 /// you do need to represent empty elements, you'll need to check for the
491 /// empty string before calling this function.
492 ///
493 /// A pattern that can match empty strings splits @string into separate
494 /// characters wherever it matches the empty string between characters.
495 /// For example splitting "ab c" using as a separator "\s*", you will get
496 /// "a", "b" and "c".
497 /// ## `string`
498 /// the string to split with the pattern
499 /// ## `match_options`
500 /// match time option flags
501 ///
502 /// # Returns
503 ///
504 /// a [`None`]-terminated gchar ** array. Free
505 /// it using g_strfreev()
506 #[doc(alias = "g_regex_split")]
507 pub fn split(
508 &self,
509 string: impl IntoGStr,
510 match_options: RegexMatchFlags,
511 ) -> PtrSlice<GStringPtr> {
512 self.split_full(string, 0, match_options, 0)
513 .unwrap_or_default()
514 }
515
516 /// Breaks the string on the pattern, and returns an array of the tokens.
517 /// If the pattern contains capturing parentheses, then the text for each
518 /// of the substrings will also be returned. If the pattern does not match
519 /// anywhere in the string, then the whole string is returned as the first
520 /// token.
521 ///
522 /// As a special case, the result of splitting the empty string "" is an
523 /// empty vector, not a vector containing a single string. The reason for
524 /// this special case is that being able to represent an empty vector is
525 /// typically more useful than consistent handling of empty elements. If
526 /// you do need to represent empty elements, you'll need to check for the
527 /// empty string before calling this function.
528 ///
529 /// A pattern that can match empty strings splits @string into separate
530 /// characters wherever it matches the empty string between characters.
531 /// For example splitting "ab c" using as a separator "\s*", you will get
532 /// "a", "b" and "c".
533 ///
534 /// Setting @start_position differs from just passing over a shortened
535 /// string and setting [`RegexMatchFlags::NOTBOL`][crate::RegexMatchFlags::NOTBOL] in the case of a pattern
536 /// that begins with any kind of lookbehind assertion, such as "\b".
537 /// ## `string`
538 /// the string to split with the pattern
539 /// ## `string_len`
540 /// the length of @string, in bytes, or -1 if @string is nul-terminated
541 /// ## `start_position`
542 /// starting index of the string to match, in bytes
543 /// ## `match_options`
544 /// match time option flags
545 /// ## `max_tokens`
546 /// the maximum number of tokens to split @string into.
547 /// If this is less than 1, the string is split completely
548 ///
549 /// # Returns
550 ///
551 /// a [`None`]-terminated gchar ** array. Free
552 /// it using g_strfreev()
553 #[doc(alias = "g_regex_split_full")]
554 pub fn split_full(
555 &self,
556 string: impl IntoGStr,
557 start_position: i32,
558 match_options: RegexMatchFlags,
559 max_tokens: i32,
560 ) -> Result<PtrSlice<GStringPtr>, crate::Error> {
561 unsafe {
562 let mut error = ptr::null_mut();
563 string.run_with_gstr(|string| {
564 let ret = ffi::g_regex_split_full(
565 self.to_glib_none().0,
566 string.to_glib_none().0,
567 string.len() as _,
568 start_position,
569 match_options.into_glib(),
570 max_tokens,
571 &mut error,
572 );
573 debug_assert_eq!(ret.is_null(), !error.is_null());
574 if error.is_null() {
575 Ok(FromGlibPtrContainer::from_glib_full(ret))
576 } else {
577 Err(from_glib_full(error))
578 }
579 })
580 }
581 }
582
583 /// Breaks the string on the pattern, and returns an array of
584 /// the tokens. If the pattern contains capturing parentheses,
585 /// then the text for each of the substrings will also be returned.
586 /// If the pattern does not match anywhere in the string, then the
587 /// whole string is returned as the first token.
588 ///
589 /// This function is equivalent to g_regex_split() but it does
590 /// not require to compile the pattern with g_regex_new(), avoiding
591 /// some lines of code when you need just to do a split without
592 /// extracting substrings, capture counts, and so on.
593 ///
594 /// If this function is to be called on the same @pattern more than
595 /// once, it's more efficient to compile the pattern once with
596 /// g_regex_new() and then use g_regex_split().
597 ///
598 /// As a special case, the result of splitting the empty string ""
599 /// is an empty vector, not a vector containing a single string.
600 /// The reason for this special case is that being able to represent
601 /// an empty vector is typically more useful than consistent handling
602 /// of empty elements. If you do need to represent empty elements,
603 /// you'll need to check for the empty string before calling this
604 /// function.
605 ///
606 /// A pattern that can match empty strings splits @string into
607 /// separate characters wherever it matches the empty string between
608 /// characters. For example splitting "ab c" using as a separator
609 /// "\s*", you will get "a", "b" and "c".
610 /// ## `pattern`
611 /// the regular expression
612 /// ## `string`
613 /// the string to scan for matches
614 /// ## `compile_options`
615 /// compile options for the regular expression, or 0
616 /// ## `match_options`
617 /// match options, or 0
618 ///
619 /// # Returns
620 ///
621 /// a [`None`]-terminated array of strings. Free
622 /// it using g_strfreev()
623 #[doc(alias = "g_regex_split_simple")]
624 pub fn split_simple(
625 pattern: impl IntoGStr,
626 string: impl IntoGStr,
627 compile_options: RegexCompileFlags,
628 match_options: RegexMatchFlags,
629 ) -> PtrSlice<GStringPtr> {
630 pattern.run_with_gstr(|pattern| {
631 string.run_with_gstr(|string| unsafe {
632 FromGlibPtrContainer::from_glib_full(ffi::g_regex_split_simple(
633 pattern.to_glib_none().0,
634 string.to_glib_none().0,
635 compile_options.into_glib(),
636 match_options.into_glib(),
637 ))
638 })
639 })
640 }
641}
642
643#[cfg(test)]
644mod tests {
645 use super::*;
646
647 #[test]
648 fn test_replace_literal() {
649 let regex = Regex::new(
650 "s[ai]mple",
651 RegexCompileFlags::OPTIMIZE,
652 RegexMatchFlags::DEFAULT,
653 )
654 .expect("Regex new")
655 .expect("Null regex");
656
657 let quote = "This is a simple sample.";
658 let result = regex
659 .replace_literal(quote, 0, "XXX", RegexMatchFlags::DEFAULT)
660 .expect("regex replace");
661
662 assert_eq!(result, "This is a XXX XXX.");
663 }
664
665 #[test]
666 fn test_split() {
667 let regex = Regex::new(
668 "s[ai]mple",
669 RegexCompileFlags::OPTIMIZE,
670 RegexMatchFlags::DEFAULT,
671 )
672 .expect("Regex new")
673 .expect("Null regex");
674
675 let quote = "This is a simple sample.";
676 let result = regex.split(quote, RegexMatchFlags::DEFAULT);
677
678 assert_eq!(result.len(), 3);
679 assert_eq!(result[0], "This is a ");
680 assert_eq!(result[1], " ");
681 assert_eq!(result[2], ".");
682 }
683
684 #[test]
685 fn test_match() {
686 let regex = Regex::new(r"\d", RegexCompileFlags::DEFAULT, RegexMatchFlags::DEFAULT)
687 .expect("Regex new")
688 .expect("Null regex");
689
690 let input = crate::GString::from("87");
691 let m = regex.match_(input.as_gstr(), RegexMatchFlags::DEFAULT);
692 let m = m.unwrap();
693 assert!(m.matches());
694 assert_eq!(m.match_count(), 1);
695 assert_eq!(m.fetch(0).as_deref(), Some("8"));
696 assert!(m.next().unwrap());
697 assert_eq!(m.fetch(0).as_deref(), Some("7"));
698 assert!(!m.next().unwrap());
699 assert!(m.fetch(0).is_none());
700
701 let input = crate::GString::from("a");
702 let m = regex.match_(input.as_gstr(), RegexMatchFlags::DEFAULT);
703 let m = m.unwrap();
704 assert!(!m.matches());
705 assert_eq!(m.match_count(), 0);
706 assert!(m.fetch(0).is_none());
707 }
708}