Skip to main content

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}