xs_regex.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /* copyright (c) 2022 - 2023 grunfink et al. / MIT license */
  2. #ifndef _XS_REGEX_H
  3. #define _XS_REGEX_H
  4. xs_list *xs_regex_split_n(const char *str, const char *rx, int count);
  5. #define xs_regex_split(str, rx) xs_regex_split_n(str, rx, XS_ALL)
  6. xs_list *xs_regex_match_n(const char *str, const char *rx, int count);
  7. #define xs_regex_match(str, rx) xs_regex_match_n(str, rx, XS_ALL)
  8. xs_list *xs_regex_replace_n(const char *str, const char *rx, const char *rep, int count);
  9. #define xs_regex_replace(str, rx, rep) xs_regex_replace_n(str, rx, rep, XS_ALL)
  10. #ifdef XS_IMPLEMENTATION
  11. #include <regex.h>
  12. xs_list *xs_regex_split_n(const char *str, const char *rx, int count)
  13. /* splits str by regex */
  14. {
  15. regex_t re;
  16. regmatch_t rm;
  17. int offset = 0;
  18. xs_list *list = NULL;
  19. const char *p;
  20. if (regcomp(&re, rx, REG_EXTENDED))
  21. return NULL;
  22. list = xs_list_new();
  23. while (count > 0 && !regexec(&re, (p = str + offset), 1, &rm, offset > 0 ? REG_NOTBOL : 0)) {
  24. /* add first the leading part of the string */
  25. list = xs_list_append_m(list, p, rm.rm_so);
  26. list = xs_insert_m(list, xs_size(list) - 1, "", 1);
  27. /* add now the matched text as the separator */
  28. list = xs_list_append_m(list, p + rm.rm_so, rm.rm_eo - rm.rm_so);
  29. list = xs_insert_m(list, xs_size(list) - 1, "", 1);
  30. /* move forward */
  31. offset += rm.rm_eo;
  32. count--;
  33. }
  34. /* add the rest of the string */
  35. list = xs_list_append(list, p);
  36. regfree(&re);
  37. return list;
  38. }
  39. xs_list *xs_regex_match_n(const char *str, const char *rx, int count)
  40. /* returns a list with upto count matches */
  41. {
  42. xs_list *list = xs_list_new();
  43. xs *split = NULL;
  44. xs_list *p;
  45. xs_val *v;
  46. int n = 0;
  47. /* split */
  48. split = xs_regex_split_n(str, rx, count);
  49. /* now iterate to get only the 'separators' (odd ones) */
  50. p = split;
  51. while (xs_list_iter(&p, &v)) {
  52. if (n & 0x1)
  53. list = xs_list_append(list, v);
  54. n++;
  55. }
  56. return list;
  57. }
  58. xs_list *xs_regex_replace_n(const char *str, const char *rx, const char *rep, int count)
  59. /* replaces all matches with the rep string. If it contains unescaped &,
  60. they are replaced with the match */
  61. {
  62. xs_str *s = xs_str_new(NULL);
  63. xs *split = xs_regex_split_n(str, rx, count);
  64. xs_list *p;
  65. xs_val *v;
  66. int n = 0;
  67. int pholder = !!strchr(rep, '&');
  68. p = split;
  69. while (xs_list_iter(&p, &v)) {
  70. if (n & 0x1) {
  71. if (pholder) {
  72. /* rep has a placeholder; process char by char */
  73. const char *p = rep;
  74. while (*p) {
  75. if (*p == '&')
  76. s = xs_str_cat(s, v);
  77. else {
  78. if (*p == '\\')
  79. p++;
  80. if (!*p)
  81. break;
  82. s = xs_append_m(s, p, 1);
  83. }
  84. p++;
  85. }
  86. }
  87. else
  88. s = xs_str_cat(s, rep);
  89. }
  90. else
  91. s = xs_str_cat(s, v);
  92. n++;
  93. }
  94. return s;
  95. }
  96. #endif /* XS_IMPLEMENTATION */
  97. #endif /* XS_REGEX_H */