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    ffi, translate::*, GStr, GStringPtr, MatchInfo, PtrSlice, Regex, RegexCompileFlags,
9    RegexMatchFlags,
10};
11use std::{mem, ptr};
12
13impl Regex {
14    #[doc(alias = "g_regex_get_string_number")]
15    #[doc(alias = "get_string_number")]
16    pub fn string_number(&self, name: impl IntoGStr) -> i32 {
17        name.run_with_gstr(|name| unsafe {
18            ffi::g_regex_get_string_number(self.to_glib_none().0, name.to_glib_none().0)
19        })
20    }
21
22    #[doc(alias = "g_regex_escape_nul")]
23    pub fn escape_nul(string: impl IntoGStr) -> crate::GString {
24        unsafe {
25            string.run_with_gstr(|string| {
26                from_glib_full(ffi::g_regex_escape_nul(
27                    string.to_glib_none().0,
28                    string.len() as _,
29                ))
30            })
31        }
32    }
33
34    #[doc(alias = "g_regex_escape_string")]
35    pub fn escape_string(string: impl IntoGStr) -> crate::GString {
36        unsafe {
37            string.run_with_gstr(|string| {
38                from_glib_full(ffi::g_regex_escape_string(
39                    string.to_glib_none().0,
40                    string.len() as _,
41                ))
42            })
43        }
44    }
45
46    #[doc(alias = "g_regex_check_replacement")]
47    pub fn check_replacement(replacement: impl IntoGStr) -> Result<bool, crate::Error> {
48        replacement.run_with_gstr(|replacement| unsafe {
49            let mut has_references = mem::MaybeUninit::uninit();
50            let mut error = ptr::null_mut();
51            let is_ok = ffi::g_regex_check_replacement(
52                replacement.to_glib_none().0,
53                has_references.as_mut_ptr(),
54                &mut error,
55            );
56            debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null());
57            if error.is_null() {
58                Ok(from_glib(has_references.assume_init()))
59            } else {
60                Err(from_glib_full(error))
61            }
62        })
63    }
64
65    #[doc(alias = "g_regex_match_simple")]
66    pub fn match_simple(
67        pattern: impl IntoGStr,
68        string: impl IntoGStr,
69        compile_options: RegexCompileFlags,
70        match_options: RegexMatchFlags,
71    ) -> bool {
72        pattern.run_with_gstr(|pattern| {
73            string.run_with_gstr(|string| unsafe {
74                from_glib(ffi::g_regex_match_simple(
75                    pattern.to_glib_none().0,
76                    string.to_glib_none().0,
77                    compile_options.into_glib(),
78                    match_options.into_glib(),
79                ))
80            })
81        })
82    }
83
84    #[doc(alias = "g_regex_replace")]
85    pub fn replace(
86        &self,
87        string: impl IntoGStr,
88        start_position: i32,
89        replacement: impl IntoGStr,
90        match_options: RegexMatchFlags,
91    ) -> Result<crate::GString, crate::Error> {
92        unsafe {
93            string.run_with_gstr(|string| {
94                replacement.run_with_gstr(|replacement| {
95                    let mut error = ptr::null_mut();
96                    let ret = ffi::g_regex_replace(
97                        self.to_glib_none().0,
98                        string.as_ptr() as *const _,
99                        string.len() as _,
100                        start_position,
101                        replacement.to_glib_none().0,
102                        match_options.into_glib(),
103                        &mut error,
104                    );
105                    debug_assert_eq!(ret.is_null(), !error.is_null());
106                    if error.is_null() {
107                        Ok(from_glib_full(ret))
108                    } else {
109                        Err(from_glib_full(error))
110                    }
111                })
112            })
113        }
114    }
115
116    #[doc(alias = "g_regex_match_all")]
117    pub fn match_all<'input>(
118        &self,
119        string: &'input GStr,
120        match_options: RegexMatchFlags,
121    ) -> Result<MatchInfo<'input>, crate::Error> {
122        self.match_all_full(string, 0, match_options)
123    }
124
125    #[doc(alias = "g_regex_match_all_full")]
126    pub fn match_all_full<'input>(
127        &self,
128        string: &'input GStr,
129        start_position: i32,
130        match_options: RegexMatchFlags,
131    ) -> Result<MatchInfo<'input>, crate::Error> {
132        unsafe {
133            let mut match_info = ptr::null_mut();
134            let mut error = ptr::null_mut();
135            let res = ffi::g_regex_match_all_full(
136                self.to_glib_none().0,
137                string.to_glib_none().0,
138                string.len() as _,
139                start_position,
140                match_options.into_glib(),
141                &mut match_info,
142                &mut error,
143            );
144            if error.is_null() {
145                let match_info = MatchInfo::from_glib_full(match_info);
146                debug_assert_eq!(match_info.matches(), from_glib(res));
147                Ok(match_info)
148            } else {
149                debug_assert!(match_info.is_null());
150                Err(from_glib_full(error))
151            }
152        }
153    }
154
155    #[doc(alias = "g_regex_match")]
156    pub fn match_<'input>(
157        &self,
158        string: &'input GStr,
159        match_options: RegexMatchFlags,
160    ) -> Result<MatchInfo<'input>, crate::Error> {
161        self.match_full(string, 0, match_options)
162    }
163
164    #[doc(alias = "g_regex_match_full")]
165    pub fn match_full<'input>(
166        &self,
167        string: &'input GStr,
168        start_position: i32,
169        match_options: RegexMatchFlags,
170    ) -> Result<MatchInfo<'input>, crate::Error> {
171        unsafe {
172            let mut match_info = ptr::null_mut();
173            let mut error = ptr::null_mut();
174            let res = ffi::g_regex_match_full(
175                self.to_glib_none().0,
176                string.to_glib_none().0,
177                string.len() as _,
178                start_position,
179                match_options.into_glib(),
180                &mut match_info,
181                &mut error,
182            );
183            if error.is_null() {
184                let match_info = MatchInfo::from_glib_full(match_info);
185                debug_assert_eq!(match_info.matches(), from_glib(res));
186                Ok(match_info)
187            } else {
188                debug_assert!(match_info.is_null());
189                Err(from_glib_full(error))
190            }
191        }
192    }
193
194    #[doc(alias = "g_regex_replace_literal")]
195    pub fn replace_literal(
196        &self,
197        string: impl IntoGStr,
198        start_position: i32,
199        replacement: impl IntoGStr,
200        match_options: RegexMatchFlags,
201    ) -> Result<crate::GString, crate::Error> {
202        unsafe {
203            string.run_with_gstr(|string| {
204                replacement.run_with_gstr(|replacement| {
205                    let mut error = ptr::null_mut();
206                    let ret = ffi::g_regex_replace_literal(
207                        self.to_glib_none().0,
208                        string.to_glib_none().0,
209                        string.len() as _,
210                        start_position,
211                        replacement.to_glib_none().0,
212                        match_options.into_glib(),
213                        &mut error,
214                    );
215                    debug_assert_eq!(ret.is_null(), !error.is_null());
216                    if error.is_null() {
217                        Ok(from_glib_full(ret))
218                    } else {
219                        Err(from_glib_full(error))
220                    }
221                })
222            })
223        }
224    }
225
226    #[doc(alias = "g_regex_split")]
227    pub fn split(
228        &self,
229        string: impl IntoGStr,
230        match_options: RegexMatchFlags,
231    ) -> PtrSlice<GStringPtr> {
232        self.split_full(string, 0, match_options, 0)
233            .unwrap_or_default()
234    }
235
236    #[doc(alias = "g_regex_split_full")]
237    pub fn split_full(
238        &self,
239        string: impl IntoGStr,
240        start_position: i32,
241        match_options: RegexMatchFlags,
242        max_tokens: i32,
243    ) -> Result<PtrSlice<GStringPtr>, crate::Error> {
244        unsafe {
245            let mut error = ptr::null_mut();
246            string.run_with_gstr(|string| {
247                let ret = ffi::g_regex_split_full(
248                    self.to_glib_none().0,
249                    string.to_glib_none().0,
250                    string.len() as _,
251                    start_position,
252                    match_options.into_glib(),
253                    max_tokens,
254                    &mut error,
255                );
256                debug_assert_eq!(ret.is_null(), !error.is_null());
257                if error.is_null() {
258                    Ok(FromGlibPtrContainer::from_glib_full(ret))
259                } else {
260                    Err(from_glib_full(error))
261                }
262            })
263        }
264    }
265
266    #[doc(alias = "g_regex_split_simple")]
267    pub fn split_simple(
268        pattern: impl IntoGStr,
269        string: impl IntoGStr,
270        compile_options: RegexCompileFlags,
271        match_options: RegexMatchFlags,
272    ) -> PtrSlice<GStringPtr> {
273        pattern.run_with_gstr(|pattern| {
274            string.run_with_gstr(|string| unsafe {
275                FromGlibPtrContainer::from_glib_full(ffi::g_regex_split_simple(
276                    pattern.to_glib_none().0,
277                    string.to_glib_none().0,
278                    compile_options.into_glib(),
279                    match_options.into_glib(),
280                ))
281            })
282        })
283    }
284}
285
286#[cfg(test)]
287mod tests {
288    use super::*;
289
290    #[test]
291    fn test_replace_literal() {
292        let regex = Regex::new(
293            "s[ai]mple",
294            RegexCompileFlags::OPTIMIZE,
295            RegexMatchFlags::DEFAULT,
296        )
297        .expect("Regex new")
298        .expect("Null regex");
299
300        let quote = "This is a simple sample.";
301        let result = regex
302            .replace_literal(quote, 0, "XXX", RegexMatchFlags::DEFAULT)
303            .expect("regex replace");
304
305        assert_eq!(result, "This is a XXX XXX.");
306    }
307
308    #[test]
309    fn test_split() {
310        let regex = Regex::new(
311            "s[ai]mple",
312            RegexCompileFlags::OPTIMIZE,
313            RegexMatchFlags::DEFAULT,
314        )
315        .expect("Regex new")
316        .expect("Null regex");
317
318        let quote = "This is a simple sample.";
319        let result = regex.split(quote, RegexMatchFlags::DEFAULT);
320
321        assert_eq!(result.len(), 3);
322        assert_eq!(result[0], "This is a ");
323        assert_eq!(result[1], " ");
324        assert_eq!(result[2], ".");
325    }
326
327    #[test]
328    fn test_match() {
329        let regex = Regex::new(r"\d", RegexCompileFlags::DEFAULT, RegexMatchFlags::DEFAULT)
330            .expect("Regex new")
331            .expect("Null regex");
332
333        let input = crate::GString::from("87");
334        let m = regex.match_(input.as_gstr(), RegexMatchFlags::DEFAULT);
335        let m = m.unwrap();
336        assert!(m.matches());
337        assert_eq!(m.match_count(), 1);
338        assert_eq!(m.fetch(0).as_deref(), Some("8"));
339        assert!(m.next().unwrap());
340        assert_eq!(m.fetch(0).as_deref(), Some("7"));
341        assert!(!m.next().unwrap());
342        assert!(m.fetch(0).is_none());
343
344        let input = crate::GString::from("a");
345        let m = regex.match_(input.as_gstr(), RegexMatchFlags::DEFAULT);
346        let m = m.unwrap();
347        assert!(!m.matches());
348        assert_eq!(m.match_count(), 0);
349        assert!(m.fetch(0).is_none());
350    }
351}