aboutsummaryrefslogtreecommitdiff
path: root/builtins/text.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-09-04 21:02:37 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-09-04 21:02:37 -0400
commit00543b4e876cf069d5be22c1f06427a4c8d5bed9 (patch)
treec77a2684fff4ce800939f833ff5d727e73607b26 /builtins/text.c
parent93140c2896004f6ab5536e64b6970e48bbc92336 (diff)
Add Text.map(pat, fn)
Diffstat (limited to 'builtins/text.c')
-rw-r--r--builtins/text.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/builtins/text.c b/builtins/text.c
index 59e12c64..97b50a40 100644
--- a/builtins/text.c
+++ b/builtins/text.c
@@ -1673,6 +1673,46 @@ public Text_t Text$replace(Text_t text, Pattern_t pattern, Text_t replacement, P
return ret;
}
+public Text_t Text$map(Text_t text, Pattern_t pattern, closure_t fn)
+{
+ Text_t ret = {.length=0};
+
+ int32_t first_grapheme = get_grapheme(pattern, 0);
+ bool find_first = (first_grapheme != '{'
+ && !uc_is_property(first_grapheme, UC_PROPERTY_QUOTATION_MARK)
+ && !uc_is_property(first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION));
+
+ iteration_state_t text_state = {0, 0};
+ int64_t nonmatching_pos = 0;
+
+ Text_t (*text_mapper)(Text_t, void*) = fn.fn;
+ for (int64_t pos = 0; pos < text.length; pos++) {
+ // Optimization: quickly skip ahead to first char in pattern:
+ if (find_first) {
+ while (pos < text.length && _next_grapheme(text, &text_state, pos) != first_grapheme)
+ ++pos;
+ }
+
+ int64_t match_len = match(text, pattern, pos, 0, NULL, 0);
+ if (match_len < 0) continue;
+
+ Text_t replacement = text_mapper(Text$slice(text, I(pos+1), I(pos+match_len)), fn.userdata);
+ if (pos > nonmatching_pos) {
+ Text_t before_slice = Text$slice(text, I(nonmatching_pos+1), I(pos));
+ ret = Text$concat(ret, before_slice, replacement);
+ } else {
+ ret = concat2(ret, replacement);
+ }
+ nonmatching_pos = pos + match_len;
+ pos += (match_len - 1);
+ }
+ if (nonmatching_pos < text.length) {
+ Text_t last_slice = Text$slice(text, I(nonmatching_pos+1), I(text.length));
+ ret = concat2(ret, last_slice);
+ }
+ return ret;
+}
+
public Text_t Text$replace_all(Text_t text, table_t replacements, Text_t backref_pat, bool recursive)
{
if (replacements.entries.length == 0) return text;