2.52
xs_regex.h
1/* copyright (c) 2022 - 2024 grunfink et al. / MIT license */
2
3#ifndef _XS_REGEX_H
4
5#define _XS_REGEX_H
6
7xs_list *xs_regex_split_n(const char *str, const char *rx, int count);
8#define xs_regex_split(str, rx) xs_regex_split_n(str, rx, XS_ALL)
9xs_list *xs_regex_select_n(const char *str, const char *rx, int count);
10#define xs_regex_select(str, rx) xs_regex_select_n(str, rx, XS_ALL)
11xs_list *xs_regex_replace_in(xs_str *str, const char *rx, const char *rep, int count);
12#define xs_regex_replace_i(str, rx, rep) xs_regex_replace_in(str, rx, rep, XS_ALL)
13#define xs_regex_replace_n(str, rx, rep, count) xs_regex_replace_in(xs_dup(str), rx, rep, count)
14#define xs_regex_replace(str, rx, rep) xs_regex_replace_in(xs_dup(str), rx, rep, XS_ALL)
15
16#ifdef XS_IMPLEMENTATION
17
18#include <regex.h>
19
20xs_list *xs_regex_split_n(const char *str, const char *rx, int count)
21/* splits str by regex */
22{
23 regex_t re;
24 regmatch_t rm;
25 int offset = 0;
26 xs_list *list = NULL;
27 const char *p;
28
29 if (regcomp(&re, rx, REG_EXTENDED))
30 return NULL;
31
32 list = xs_list_new();
33
34 while (count > 0 && !regexec(&re, (p = str + offset), 1, &rm, offset > 0 ? REG_NOTBOL : 0)) {
35 /* add first the leading part of the string */
36 xs *s1 = xs_str_new_sz(p, rm.rm_so);
37 list = xs_list_append(list, s1);
38
39 /* add now the matched text as the separator */
40 xs *s2 = xs_str_new_sz(p + rm.rm_so, rm.rm_eo - rm.rm_so);
41 list = xs_list_append(list, s2);
42
43 /* move forward */
44 offset += rm.rm_eo;
45
46 count--;
47 }
48
49 /* add the rest of the string */
50 list = xs_list_append(list, p);
51
52 regfree(&re);
53
54 return list;
55}
56
57
58xs_list *xs_regex_select_n(const char *str, const char *rx, int count)
59/* selects all matches and return them as a list */
60{
61 xs_list *list = xs_list_new();
62 xs *split = NULL;
63 xs_list *p;
64 xs_val *v;
65 int n = 0;
66
67 /* split */
68 split = xs_regex_split_n(str, rx, count);
69
70 /* now iterate to get only the 'separators' (odd ones) */
71 p = split;
72 while (xs_list_iter(&p, &v)) {
73 if (n & 0x1)
74 list = xs_list_append(list, v);
75
76 n++;
77 }
78
79 return list;
80}
81
82
83xs_list *xs_regex_replace_in(xs_str *str, const char *rx, const char *rep, int count)
84/* replaces all matches with the rep string. If it contains unescaped &,
85 they are replaced with the match */
86{
87 xs_str *s = xs_str_new(NULL);
88 xs *split = xs_regex_split_n(str, rx, count);
89 xs_list *p;
90 xs_val *v;
91 int n = 0;
92 int pholder = !!strchr(rep, '&');
93
94 p = split;
95 while (xs_list_iter(&p, &v)) {
96 if (n & 0x1) {
97 if (pholder) {
98 /* rep has a placeholder; process char by char */
99 const char *p = rep;
100
101 while (*p) {
102 if (*p == '&')
103 s = xs_str_cat(s, v);
104 else {
105 if (*p == '\\')
106 p++;
107
108 if (!*p)
109 break;
110
111 s = xs_append_m(s, p, 1);
112 }
113
114 p++;
115 }
116 }
117 else
118 s = xs_str_cat(s, rep);
119 }
120 else
121 s = xs_str_cat(s, v);
122
123 n++;
124 }
125
126 xs_free(str);
127
128 return s;
129}
130
131#endif /* XS_IMPLEMENTATION */
132
133#endif /* XS_REGEX_H */