From 30bb21429755436b44952919bcbffd04b7547095 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 d92b548273..4ba3c4adf8 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 3edb07dff0..5b6dab6a36 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)!") "’"