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 /// Replaces all occurrences of the pattern in @self with the
162 /// replacement text. Backreferences of the form `\number` or
163 /// `\g<number>` in the replacement text are interpolated by the
164 /// number-th captured subexpression of the match, `\g<name>` refers
165 /// to the captured subexpression with the given name. `\0` refers
166 /// to the complete match, but `\0` followed by a number is the octal
167 /// representation of a character. To include a literal `\` in the
168 /// replacement, write `\\\\`.
169 ///
170 /// There are also escapes that changes the case of the following text:
171 ///
172 /// - `\l`: Convert to lower case the next character
173 /// - `\u`: Convert to upper case the next character
174 /// - `\L`: Convert to lower case until the next `\E`
175 /// - `\U`: Convert to upper case until the next `\E`
176 /// - `\E`: End case modification
177 ///
178 /// If you do not need to use backreferences use g_regex_replace_literal().
179 ///
180 /// The @replacement string must be UTF-8 encoded even if [`RegexCompileFlags::RAW`][crate::RegexCompileFlags::RAW] was
181 /// passed to g_regex_new(). If you want to use not UTF-8 encoded strings
182 /// you can use g_regex_replace_literal().
183 ///
184 /// Setting @start_position differs from just passing over a shortened
185 /// string and setting [`RegexMatchFlags::NOTBOL`][crate::RegexMatchFlags::NOTBOL] in the case of a pattern that
186 /// begins with any kind of lookbehind assertion, such as `"\b"`.
187 /// ## `string`
188 /// the string to perform matches against
189 /// ## `string_len`
190 /// the length of @string, in bytes, or -1 if @string is nul-terminated
191 /// ## `start_position`
192 /// starting index of the string to match, in bytes
193 /// ## `replacement`
194 /// text to replace each match with
195 /// ## `match_options`
196 /// options for the match
197 ///
198 /// # Returns
199 ///
200 /// a newly allocated string containing the replacements
201 #[doc(alias = "g_regex_replace")]
202 pub fn replace(
203 &self,
204 string: impl IntoGStr,
205 start_position: i32,
206 replacement: impl IntoGStr,
207 match_options: RegexMatchFlags,
208 ) -> Result<crate::GString, crate::Error> {
209 unsafe {
210 string.run_with_gstr(|string| {
211 replacement.run_with_gstr(|replacement| {
212 let mut error = ptr::null_mut();
213 let ret = ffi::g_regex_replace(
214 self.to_glib_none().0,
215 string.as_ptr() as *const _,
216 string.len() as _,
217 start_position,
218 replacement.to_glib_none().0,
219 match_options.into_glib(),
220 &mut error,
221 );
222 debug_assert_eq!(ret.is_null(), !error.is_null());
223 if error.is_null() {
224 Ok(from_glib_full(ret))
225 } else {
226 Err(from_glib_full(error))
227 }
228 })
229 })
230 }
231 }
232
233 /// Using the standard algorithm for regular expression matching only
234 /// the longest match in the string is retrieved. This function uses
235 /// a different algorithm so it can retrieve all the possible matches.
236 /// For more documentation see g_regex_match_all_full().
237 ///
238 /// A #GMatchInfo structure, used to get information on the match, is
239 /// stored in @match_info if not [`None`]. Note that if @match_info is
240 /// not [`None`] then it is created even if the function returns [`false`],
241 /// i.e. you must free it regardless if regular expression actually
242 /// matched.
243 ///
244 /// @string is not copied and is used in #GMatchInfo internally. If
245 /// you use any #GMatchInfo method (except g_match_info_free()) after
246 /// freeing or modifying @string then the behaviour is undefined.
247 /// ## `string`
248 /// the string to scan for matches
249 /// ## `match_options`
250 /// match options
251 ///
252 /// # Returns
253 ///
254 /// [`true`] is the string matched, [`false`] otherwise
255 ///
256 /// ## `match_info`
257 /// pointer to location where to store
258 /// the #GMatchInfo, or [`None`] if you do not need it
259 #[doc(alias = "g_regex_match_all")]
260 pub fn match_all<'input>(
261 &self,
262 string: &'input GStr,
263 match_options: RegexMatchFlags,
264 ) -> Result<MatchInfo<'input>, crate::Error> {
265 self.match_all_full(string, 0, match_options)
266 }
267
268 /// Using the standard algorithm for regular expression matching only
269 /// the longest match in the @string is retrieved, it is not possible
270 /// to obtain all the available matches. For instance matching
271 /// `"<a> <b> <c>"` against the pattern `"<.*>"`
272 /// you get `"<a> <b> <c>"`.
273 ///
274 /// This function uses a different algorithm (called DFA, i.e. deterministic
275 /// finite automaton), so it can retrieve all the possible matches, all
276 /// starting at the same point in the string. For instance matching
277 /// `"<a> <b> <c>"` against the pattern `"<.*>"`
278 /// you would obtain three matches: `"<a> <b> <c>"`,
279 /// `"<a> <b>"` and `"<a>"`.
280 ///
281 /// The number of matched strings is retrieved using
282 /// g_match_info_get_match_count(). To obtain the matched strings and
283 /// their position you can use, respectively, g_match_info_fetch() and
284 /// g_match_info_fetch_pos(). Note that the strings are returned in
285 /// reverse order of length; that is, the longest matching string is
286 /// given first.
287 ///
288 /// Note that the DFA algorithm is slower than the standard one and it
289 /// is not able to capture substrings, so backreferences do not work.
290 ///
291 /// Setting @start_position differs from just passing over a shortened
292 /// string and setting [`RegexMatchFlags::NOTBOL`][crate::RegexMatchFlags::NOTBOL] in the case of a pattern
293 /// that begins with any kind of lookbehind assertion, such as "\b".
294 ///
295 /// Unless [`RegexCompileFlags::RAW`][crate::RegexCompileFlags::RAW] is specified in the options, @string must be valid UTF-8.
296 ///
297 /// A #GMatchInfo structure, used to get information on the match, is
298 /// stored in @match_info if not [`None`]. Note that if @match_info is
299 /// not [`None`] then it is created even if the function returns [`false`],
300 /// i.e. you must free it regardless if regular expression actually
301 /// matched.
302 ///
303 /// @string is not copied and is used in #GMatchInfo internally. If
304 /// you use any #GMatchInfo method (except g_match_info_free()) after
305 /// freeing or modifying @string then the behaviour is undefined.
306 /// ## `string`
307 /// the string to scan for matches
308 /// ## `string_len`
309 /// the length of @string, in bytes, or -1 if @string is nul-terminated
310 /// ## `start_position`
311 /// starting index of the string to match, in bytes
312 /// ## `match_options`
313 /// match options
314 ///
315 /// # Returns
316 ///
317 /// [`true`] is the string matched, [`false`] otherwise
318 ///
319 /// ## `match_info`
320 /// pointer to location where to store
321 /// the #GMatchInfo, or [`None`] if you do not need it
322 #[doc(alias = "g_regex_match_all_full")]
323 pub fn match_all_full<'input>(
324 &self,
325 string: &'input GStr,
326 start_position: i32,
327 match_options: RegexMatchFlags,
328 ) -> Result<MatchInfo<'input>, crate::Error> {
329 unsafe {
330 let mut match_info = ptr::null_mut();
331 let mut error = ptr::null_mut();
332 let res = ffi::g_regex_match_all_full(
333 self.to_glib_none().0,
334 string.to_glib_none().0,
335 string.len() as _,
336 start_position,
337 match_options.into_glib(),
338 &mut match_info,
339 &mut error,
340 );
341 if error.is_null() {
342 let match_info = MatchInfo::from_glib_full(match_info);
343 debug_assert_eq!(match_info.matches(), from_glib(res));
344 Ok(match_info)
345 } else {
346 debug_assert!(match_info.is_null());
347 Err(from_glib_full(error))
348 }
349 }
350 }
351
352 /// Scans for a match in @string for the pattern in @self.
353 /// The @match_options are combined with the match options specified
354 /// when the @self structure was created, letting you have more
355 /// flexibility in reusing #GRegex structures.
356 ///
357 /// Unless [`RegexCompileFlags::RAW`][crate::RegexCompileFlags::RAW] is specified in the options, @string must be valid UTF-8.
358 ///
359 /// A #GMatchInfo structure, used to get information on the match,
360 /// is stored in @match_info if not [`None`]. Note that if @match_info
361 /// is not [`None`] then it is created even if the function returns [`false`],
362 /// i.e. you must free it regardless if regular expression actually matched.
363 ///
364 /// To retrieve all the non-overlapping matches of the pattern in
365 /// string you can use g_match_info_next().
366 ///
367 ///
368 ///
369 /// **⚠️ The following code is in C ⚠️**
370 ///
371 /// ```C
372 /// static void
373 /// print_uppercase_words (const gchar *string)
374 /// {
375 /// // Print all uppercase-only words.
376 /// GRegex *regex;
377 /// GMatchInfo *match_info;
378 ///
379 /// regex = g_regex_new ("[A-Z]+", G_REGEX_DEFAULT, G_REGEX_MATCH_DEFAULT, NULL);
380 /// g_regex_match (regex, string, 0, &match_info);
381 /// while (g_match_info_matches (match_info))
382 /// {
383 /// gchar *word = g_match_info_fetch (match_info, 0);
384 /// g_print ("Found: %s\n", word);
385 /// g_free (word);
386 /// g_match_info_next (match_info, NULL);
387 /// }
388 /// g_match_info_free (match_info);
389 /// g_regex_unref (regex);
390 /// }
391 /// ```
392 ///
393 /// @string is not copied and is used in #GMatchInfo internally. If
394 /// you use any #GMatchInfo method (except g_match_info_free()) after
395 /// freeing or modifying @string then the behaviour is undefined.
396 /// ## `string`
397 /// the string to scan for matches
398 /// ## `match_options`
399 /// match options
400 ///
401 /// # Returns
402 ///
403 /// [`true`] is the string matched, [`false`] otherwise
404 ///
405 /// ## `match_info`
406 /// pointer to location where to store
407 /// the #GMatchInfo, or [`None`] if you do not need it
408 #[doc(alias = "g_regex_match")]
409 pub fn match_<'input>(
410 &self,
411 string: &'input GStr,
412 match_options: RegexMatchFlags,
413 ) -> Result<MatchInfo<'input>, crate::Error> {
414 self.match_full(string, 0, match_options)
415 }
416
417 /// Scans for a match in @string for the pattern in @self.
418 /// The @match_options are combined with the match options specified
419 /// when the @self structure was created, letting you have more
420 /// flexibility in reusing #GRegex structures.
421 ///
422 /// Setting @start_position differs from just passing over a shortened
423 /// string and setting [`RegexMatchFlags::NOTBOL`][crate::RegexMatchFlags::NOTBOL] in the case of a pattern
424 /// that begins with any kind of lookbehind assertion, such as "\b".
425 ///
426 /// Unless [`RegexCompileFlags::RAW`][crate::RegexCompileFlags::RAW] is specified in the options, @string must be valid UTF-8.
427 ///
428 /// A #GMatchInfo structure, used to get information on the match, is
429 /// stored in @match_info if not [`None`]. Note that if @match_info is
430 /// not [`None`] then it is created even if the function returns [`false`],
431 /// i.e. you must free it regardless if regular expression actually
432 /// matched.
433 ///
434 /// @string is not copied and is used in #GMatchInfo internally. If
435 /// you use any #GMatchInfo method (except g_match_info_free()) after
436 /// freeing or modifying @string then the behaviour is undefined.
437 ///
438 /// To retrieve all the non-overlapping matches of the pattern in
439 /// string you can use g_match_info_next().
440 ///
441 ///
442 ///
443 /// **⚠️ The following code is in C ⚠️**
444 ///
445 /// ```C
446 /// static void
447 /// print_uppercase_words (const gchar *string)
448 /// {
449 /// // Print all uppercase-only words.
450 /// GRegex *regex;
451 /// GMatchInfo *match_info;
452 /// GError *error = NULL;
453 ///
454 /// regex = g_regex_new ("[A-Z]+", G_REGEX_DEFAULT, G_REGEX_MATCH_DEFAULT, NULL);
455 /// g_regex_match_full (regex, string, -1, 0, 0, &match_info, &error);
456 /// while (g_match_info_matches (match_info))
457 /// {
458 /// gchar *word = g_match_info_fetch (match_info, 0);
459 /// g_print ("Found: %s\n", word);
460 /// g_free (word);
461 /// g_match_info_next (match_info, &error);
462 /// }
463 /// g_match_info_free (match_info);
464 /// g_regex_unref (regex);
465 /// if (error != NULL)
466 /// {
467 /// g_printerr ("Error while matching: %s\n", error->message);
468 /// g_error_free (error);
469 /// }
470 /// }
471 /// ```
472 /// ## `string`
473 /// the string to scan for matches
474 /// ## `string_len`
475 /// the length of @string, in bytes, or -1 if @string is nul-terminated
476 /// ## `start_position`
477 /// starting index of the string to match, in bytes
478 /// ## `match_options`
479 /// match options
480 ///
481 /// # Returns
482 ///
483 /// [`true`] is the string matched, [`false`] otherwise
484 ///
485 /// ## `match_info`
486 /// pointer to location where to store
487 /// the #GMatchInfo, or [`None`] if you do not need it
488 #[doc(alias = "g_regex_match_full")]
489 pub fn match_full<'input>(
490 &self,
491 string: &'input GStr,
492 start_position: i32,
493 match_options: RegexMatchFlags,
494 ) -> Result<MatchInfo<'input>, crate::Error> {
495 unsafe {
496 let mut match_info = ptr::null_mut();
497 let mut error = ptr::null_mut();
498 let res = ffi::g_regex_match_full(
499 self.to_glib_none().0,
500 string.to_glib_none().0,
501 string.len() as _,
502 start_position,
503 match_options.into_glib(),
504 &mut match_info,
505 &mut error,
506 );
507 if error.is_null() {
508 let match_info = MatchInfo::from_glib_full(match_info);
509 debug_assert_eq!(match_info.matches(), from_glib(res));
510 Ok(match_info)
511 } else {
512 debug_assert!(match_info.is_null());
513 Err(from_glib_full(error))
514 }
515 }
516 }
517
518 /// Replaces all occurrences of the pattern in @self with the
519 /// replacement text. @replacement is replaced literally, to
520 /// include backreferences use g_regex_replace().
521 ///
522 /// Setting @start_position differs from just passing over a
523 /// shortened string and setting [`RegexMatchFlags::NOTBOL`][crate::RegexMatchFlags::NOTBOL] in the
524 /// case of a pattern that begins with any kind of lookbehind
525 /// assertion, such as "\b".
526 /// ## `string`
527 /// the string to perform matches against
528 /// ## `string_len`
529 /// the length of @string, in bytes, or -1 if @string is nul-terminated
530 /// ## `start_position`
531 /// starting index of the string to match, in bytes
532 /// ## `replacement`
533 /// text to replace each match with
534 /// ## `match_options`
535 /// options for the match
536 ///
537 /// # Returns
538 ///
539 /// a newly allocated string containing the replacements
540 #[doc(alias = "g_regex_replace_literal")]
541 pub fn replace_literal(
542 &self,
543 string: impl IntoGStr,
544 start_position: i32,
545 replacement: impl IntoGStr,
546 match_options: RegexMatchFlags,
547 ) -> Result<crate::GString, crate::Error> {
548 unsafe {
549 string.run_with_gstr(|string| {
550 replacement.run_with_gstr(|replacement| {
551 let mut error = ptr::null_mut();
552 let ret = ffi::g_regex_replace_literal(
553 self.to_glib_none().0,
554 string.to_glib_none().0,
555 string.len() as _,
556 start_position,
557 replacement.to_glib_none().0,
558 match_options.into_glib(),
559 &mut error,
560 );
561 debug_assert_eq!(ret.is_null(), !error.is_null());
562 if error.is_null() {
563 Ok(from_glib_full(ret))
564 } else {
565 Err(from_glib_full(error))
566 }
567 })
568 })
569 }
570 }
571
572 /// Breaks the string on the pattern, and returns an array of the tokens.
573 /// If the pattern contains capturing parentheses, then the text for each
574 /// of the substrings will also be returned. If the pattern does not match
575 /// anywhere in the string, then the whole string is returned as the first
576 /// token.
577 ///
578 /// As a special case, the result of splitting the empty string "" is an
579 /// empty vector, not a vector containing a single string. The reason for
580 /// this special case is that being able to represent an empty vector is
581 /// typically more useful than consistent handling of empty elements. If
582 /// you do need to represent empty elements, you'll need to check for the
583 /// empty string before calling this function.
584 ///
585 /// A pattern that can match empty strings splits @string into separate
586 /// characters wherever it matches the empty string between characters.
587 /// For example splitting "ab c" using as a separator "\s*", you will get
588 /// "a", "b" and "c".
589 /// ## `string`
590 /// the string to split with the pattern
591 /// ## `match_options`
592 /// match time option flags
593 ///
594 /// # Returns
595 ///
596 /// a [`None`]-terminated gchar ** array. Free
597 /// it using g_strfreev()
598 #[doc(alias = "g_regex_split")]
599 pub fn split(
600 &self,
601 string: impl IntoGStr,
602 match_options: RegexMatchFlags,
603 ) -> PtrSlice<GStringPtr> {
604 self.split_full(string, 0, match_options, 0)
605 .unwrap_or_default()
606 }
607
608 /// Breaks the string on the pattern, and returns an array of the tokens.
609 /// If the pattern contains capturing parentheses, then the text for each
610 /// of the substrings will also be returned. If the pattern does not match
611 /// anywhere in the string, then the whole string is returned as the first
612 /// token.
613 ///
614 /// As a special case, the result of splitting the empty string "" is an
615 /// empty vector, not a vector containing a single string. The reason for
616 /// this special case is that being able to represent an empty vector is
617 /// typically more useful than consistent handling of empty elements. If
618 /// you do need to represent empty elements, you'll need to check for the
619 /// empty string before calling this function.
620 ///
621 /// A pattern that can match empty strings splits @string into separate
622 /// characters wherever it matches the empty string between characters.
623 /// For example splitting "ab c" using as a separator "\s*", you will get
624 /// "a", "b" and "c".
625 ///
626 /// Setting @start_position differs from just passing over a shortened
627 /// string and setting [`RegexMatchFlags::NOTBOL`][crate::RegexMatchFlags::NOTBOL] in the case of a pattern
628 /// that begins with any kind of lookbehind assertion, such as "\b".
629 /// ## `string`
630 /// the string to split with the pattern
631 /// ## `string_len`
632 /// the length of @string, in bytes, or -1 if @string is nul-terminated
633 /// ## `start_position`
634 /// starting index of the string to match, in bytes
635 /// ## `match_options`
636 /// match time option flags
637 /// ## `max_tokens`
638 /// the maximum number of tokens to split @string into.
639 /// If this is less than 1, the string is split completely
640 ///
641 /// # Returns
642 ///
643 /// a [`None`]-terminated gchar ** array. Free
644 /// it using g_strfreev()
645 #[doc(alias = "g_regex_split_full")]
646 pub fn split_full(
647 &self,
648 string: impl IntoGStr,
649 start_position: i32,
650 match_options: RegexMatchFlags,
651 max_tokens: i32,
652 ) -> Result<PtrSlice<GStringPtr>, crate::Error> {
653 unsafe {
654 let mut error = ptr::null_mut();
655 string.run_with_gstr(|string| {
656 let ret = ffi::g_regex_split_full(
657 self.to_glib_none().0,
658 string.to_glib_none().0,
659 string.len() as _,
660 start_position,
661 match_options.into_glib(),
662 max_tokens,
663 &mut error,
664 );
665 debug_assert_eq!(ret.is_null(), !error.is_null());
666 if error.is_null() {
667 Ok(FromGlibPtrContainer::from_glib_full(ret))
668 } else {
669 Err(from_glib_full(error))
670 }
671 })
672 }
673 }
674
675 /// Breaks the string on the pattern, and returns an array of
676 /// the tokens. If the pattern contains capturing parentheses,
677 /// then the text for each of the substrings will also be returned.
678 /// If the pattern does not match anywhere in the string, then the
679 /// whole string is returned as the first token.
680 ///
681 /// This function is equivalent to g_regex_split() but it does
682 /// not require to compile the pattern with g_regex_new(), avoiding
683 /// some lines of code when you need just to do a split without
684 /// extracting substrings, capture counts, and so on.
685 ///
686 /// If this function is to be called on the same @pattern more than
687 /// once, it's more efficient to compile the pattern once with
688 /// g_regex_new() and then use g_regex_split().
689 ///
690 /// As a special case, the result of splitting the empty string ""
691 /// is an empty vector, not a vector containing a single string.
692 /// The reason for this special case is that being able to represent
693 /// an empty vector is typically more useful than consistent handling
694 /// of empty elements. If you do need to represent empty elements,
695 /// you'll need to check for the empty string before calling this
696 /// function.
697 ///
698 /// A pattern that can match empty strings splits @string into
699 /// separate characters wherever it matches the empty string between
700 /// characters. For example splitting "ab c" using as a separator
701 /// "\s*", you will get "a", "b" and "c".
702 /// ## `pattern`
703 /// the regular expression
704 /// ## `string`
705 /// the string to scan for matches
706 /// ## `compile_options`
707 /// compile options for the regular expression, or 0
708 /// ## `match_options`
709 /// match options, or 0
710 ///
711 /// # Returns
712 ///
713 /// a [`None`]-terminated array of strings. Free
714 /// it using g_strfreev()
715 #[doc(alias = "g_regex_split_simple")]
716 pub fn split_simple(
717 pattern: impl IntoGStr,
718 string: impl IntoGStr,
719 compile_options: RegexCompileFlags,
720 match_options: RegexMatchFlags,
721 ) -> PtrSlice<GStringPtr> {
722 pattern.run_with_gstr(|pattern| {
723 string.run_with_gstr(|string| unsafe {
724 FromGlibPtrContainer::from_glib_full(ffi::g_regex_split_simple(
725 pattern.to_glib_none().0,
726 string.to_glib_none().0,
727 compile_options.into_glib(),
728 match_options.into_glib(),
729 ))
730 })
731 })
732 }
733}
734
735#[cfg(test)]
736mod tests {
737 use super::*;
738
739 #[test]
740 fn test_replace_literal() {
741 let regex = Regex::new(
742 "s[ai]mple",
743 RegexCompileFlags::OPTIMIZE,
744 RegexMatchFlags::DEFAULT,
745 )
746 .expect("Regex new")
747 .expect("Null regex");
748
749 let quote = "This is a simple sample.";
750 let result = regex
751 .replace_literal(quote, 0, "XXX", RegexMatchFlags::DEFAULT)
752 .expect("regex replace");
753
754 assert_eq!(result, "This is a XXX XXX.");
755 }
756
757 #[test]
758 fn test_split() {
759 let regex = Regex::new(
760 "s[ai]mple",
761 RegexCompileFlags::OPTIMIZE,
762 RegexMatchFlags::DEFAULT,
763 )
764 .expect("Regex new")
765 .expect("Null regex");
766
767 let quote = "This is a simple sample.";
768 let result = regex.split(quote, RegexMatchFlags::DEFAULT);
769
770 assert_eq!(result.len(), 3);
771 assert_eq!(result[0], "This is a ");
772 assert_eq!(result[1], " ");
773 assert_eq!(result[2], ".");
774 }
775
776 #[test]
777 fn test_match() {
778 let regex = Regex::new(r"\d", RegexCompileFlags::DEFAULT, RegexMatchFlags::DEFAULT)
779 .expect("Regex new")
780 .expect("Null regex");
781
782 let input = crate::GString::from("87");
783 let m = regex.match_(input.as_gstr(), RegexMatchFlags::DEFAULT);
784 let m = m.unwrap();
785 assert!(m.matches());
786 assert_eq!(m.match_count(), 1);
787 assert_eq!(m.fetch(0).as_deref(), Some("8"));
788 assert!(m.next().unwrap());
789 assert_eq!(m.fetch(0).as_deref(), Some("7"));
790 assert!(!m.next().unwrap());
791 assert!(m.fetch(0).is_none());
792
793 let input = crate::GString::from("a");
794 let m = regex.match_(input.as_gstr(), RegexMatchFlags::DEFAULT);
795 let m = m.unwrap();
796 assert!(!m.matches());
797 assert_eq!(m.match_count(), 0);
798 assert!(m.fetch(0).is_none());
799 }
800}