the_Foundation [master]

String: Added replaceRegExp() method

=> 11e7a3bdbb4b40ea4417518dac9eba7ad55748d3

diff --git a/include/the_Foundation/string.h b/include/the_Foundation/string.h
index e158fe2..a09cf1c 100644
--- a/include/the_Foundation/string.h
+++ b/include/the_Foundation/string.h
@@ -85,6 +85,10 @@ iDeclareType(StringList)
 iDeclareType(StringComparison)
 iDeclareType(MultibyteChar)
 iDeclareType(Stream)
+#if defined (iHaveRegExp)
+    iDeclareType(RegExp)
+    iDeclareType(RegExpMatch)
+#endif
 
 struct Impl_StringComparison {
     int     (*cmp)      (const char *, const char *);
@@ -264,6 +268,28 @@ iString *       trimmed_String      (const iString *);
 void            replace_String      (iString *, const char *src, const char *dst);
 void            normalize_String    (iString *); /* NFC */
 
+#if defined (iHaveRegExp)
+/**
+ * Replace all matches of a regular expression in the string.
+ *
+ * @param regexp        Regular expression to search for.
+ * @param replacement   String to substitute at each match. Use the `\1` syntax to refer
+ *                      to a capture group. `\0` refers to the entire match.
+ *                      Backslashes must be escaped: `\\`. Must not be NULL.
+ * @param matchHandler  In addition to replacing with @a replacement, call this callback
+ *                      for each match. Do not modify the String in the callback.
+ *                      Can be NULL.
+ * @param context       User-provided pointer to pass as the first argument of
+ *                      @a matchHandler
+ *
+ * @return Number of replaced matches.
+ */
+int             replaceRegExp_String    (iString *, const iRegExp *regexp,
+                                         const char *replacement,
+                                         void (*matchHandler)(void *, const iRegExpMatch *),
+                                         void *context);
+#endif
+
 int             toInt_String    (const iString *);
 float           toFloat_String  (const iString *);
 double          toDouble_String (const iString *);
diff --git a/src/string.c b/src/string.c
index fc7a377..7db513e 100644
--- a/src/string.c
+++ b/src/string.c
@@ -30,6 +30,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "the_Foundation/range.h"
 #include "the_Foundation/stdthreads.h"
 
+#if defined (iHaveRegExp)
+#   include "the_Foundation/regexp.h"
+#endif
+
 #include 
 #include 
 #include 
@@ -374,6 +378,46 @@ void replace_String(iString *d, const char *src, const char *dst) {
     }
 }
 
+#if defined (iHaveRegExp)
+int replaceRegExp_String(iString *d, const iRegExp *regexp, const char *replacement,
+                         void (*matchHandler)(void *, const iRegExpMatch *),
+                         void *context) {
+    iRegExpMatch m;
+    iString      result;
+    int          numMatches = 0;
+    const char  *pos        = constBegin_String(d);
+    init_RegExpMatch(&m);
+    init_String(&result);
+    while (matchString_RegExp(regexp, d, &m)) {
+        appendRange_String(&result, (iRangecc){ pos, begin_RegExpMatch(&m) });
+        /* Replace any capture group back-references. */
+        for (const char *ch = replacement; *ch; ch++) {
+            if (*ch == '\\') {
+                ch++;
+                if (*ch == '\\') {
+                    appendCStr_String(&result, "\\");
+                }
+                else if (*ch >= '0' && *ch <= '9') {
+                    appendRange_String(&result, capturedRange_RegExpMatch(&m, *ch - '0'));
+                }
+            }
+            else {
+                appendData_Block(&result.chars, ch, 1);
+            }
+        }
+        if (matchHandler) {
+            matchHandler(context, &m);
+        }
+        pos = end_RegExpMatch(&m);
+        numMatches++;
+    }
+    appendRange_String(&result, (iRangecc){ pos, constEnd_String(d) });
+    set_String(d, &result);
+    deinit_String(&result);
+    return numMatches;
+}
+#endif
+
 void normalize_String(iString *d) {
     size_t len = 0;
     uint8_t *nfc =
@@ -498,7 +542,7 @@ iString *urlEncode_String(const iString *d) {
 }
 
 iString *maybeUrlEncodeExclude_String(const iString *d, const char *excluded) {
-    /* TODO: Return NULL if nothing to encode. */    
+    /* TODO: Return NULL if nothing to encode. */
     iString *encoded = new_String();
     /* Note: Any UTF-8 code points are encoded as multiple %NN sequences. */
     for (const char *i = constBegin_String(d), *end = constEnd_String(d); i != end; ++i) {
@@ -514,7 +558,7 @@ iString *maybeUrlEncodeExclude_String(const iString *d, const char *excluded) {
             appendCStrN_String(encoded, escaped, 3);
         }
     }
-    return encoded;    
+    return encoded;
 }
 
 static int fromHex_(char ch) {
@@ -547,7 +591,7 @@ iString *maybeUrlDecodeExclude_String(const iString *d, const char *excluded) {
         }
         appendData_Block(&decoded->chars, i, 1);
     }
-    return decoded;    
+    return decoded;
 }
 
 iString *urlDecodeExclude_String(const iString *d, const char *excluded) {
Proxy Information
Original URL
gemini://git.skyjake.fi/the_Foundation/master/cdiff/11e7a3bdbb4b40ea4417518dac9eba7ad55748d3
Status Code
Success (20)
Meta
text/gemini; charset=utf-8
Capsule Response Time
30.179423 milliseconds
Gemini-to-HTML Time
0.439096 milliseconds

This content has been proxied by September (ba2dc).