From 01dfd8b86d1248e80d868523c63c87356bca9c6f Mon Sep 17 00:00:00 2001 From: Emanuele Torre Date: Tue, 18 Jul 2023 08:49:12 +0200 Subject: [PATCH] Populate captures also for zero-width matches Instead of just using {"captures":[]}. sub functions are use captures for replacement expressions. If we don't populate, captures for empty matches, the replacement expression is run with an empty object as input instead of an object containing the named captures with "" as value: * before: $ jq -n '"123foo456bar" | gsub("[^a-z]*(?[a-z]*)"; "Z\(.x)")' "ZfooZbarZnull" * after: $ jq -n '"123foo456bar" | gsub("[^a-z]*(?[a-z]*)"; "Z\(.x)")' "ZfooZbarZ" --- I also removed a redundant result = NULL; if (result) { ... } --- src/builtin.c | 14 +++++++++++--- tests/onig.test | 6 +++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/builtin.c b/src/builtin.c index d92b5482..4ba3c4ad 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -931,7 +931,17 @@ static jv f_match(jq_state *jq, jv input, jv regex, jv modifiers, jv testmode) { jv match = jv_object_set(jv_object(), jv_string("offset"), jv_number(idx)); match = jv_object_set(match, jv_string("length"), jv_number(0)); match = jv_object_set(match, jv_string("string"), jv_string("")); - match = jv_object_set(match, jv_string("captures"), jv_array()); + jv captures = jv_array(); + for (int i = 1; i < region->num_regs; ++i) { + jv cap = jv_object(); + cap = jv_object_set(cap, jv_string("offset"), jv_number(idx)); + cap = jv_object_set(cap, jv_string("string"), jv_string("")); + cap = jv_object_set(cap, jv_string("length"), jv_number(0)); + cap = jv_object_set(cap, jv_string("name"), jv_null()); + captures = jv_array_append(captures, cap); + } + onig_foreach_name(reg, f_match_name_iter, &captures); + match = jv_object_set(match, jv_string("captures"), captures); result = jv_array_append(result, match); // ensure '"qux" | match("(?=u)"; "g")' matches just once start = (const UChar*)(input_string+region->end[0]+1); @@ -1005,8 +1015,6 @@ static jv f_match(jq_state *jq, jv input, jv regex, jv modifiers, jv testmode) { } while (global && start <= end); onig_region_free(region,1); region = NULL; - if (region) - onig_region_free(region,1); onig_free(reg); jv_free(input); jv_free(regex); diff --git a/tests/onig.test b/tests/onig.test index 3edb07df..5b6dab6a 100644 --- a/tests/onig.test +++ b/tests/onig.test @@ -1,7 +1,7 @@ # match builtin [match("( )*"; "g")] "abc" -[{"offset":0, "length":0, "string":"", "captures":[]}, {"offset":1, "length":0, "string":"", "captures":[]}, {"offset":2, "length":0, "string":"", "captures":[]}, {"offset":3, "length":0, "string":"", "captures":[]}] +[{"offset":0,"length":0,"string":"","captures":[{"offset":0,"string":"","length":0,"name":null}]},{"offset":1,"length":0,"string":"","captures":[{"offset":1,"string":"","length":0,"name":null}]},{"offset":2,"length":0,"string":"","captures":[{"offset":2,"string":"","length":0,"name":null}]},{"offset":3,"length":0,"string":"","captures":[{"offset":3,"string":"","length":0,"name":null}]}] [match("( )*"; "gn")] "abc" @@ -145,6 +145,10 @@ gsub("\\b(?.)"; "\(.x|ascii_downcase)") "ABC DEF" "aBC dEF" +gsub("[^a-z]*(?[a-z]*)"; "Z\(.x)") +"123foo456bar" +"ZfooZbarZ" + # utf-8 sub("(?.)"; "\(.x)!") "’"