From f98d159959437375734d38ef673fb2caeece6234 Mon Sep 17 00:00:00 2001 From: John Kerl Date: Wed, 14 Oct 2015 23:12:05 -0400 Subject: [PATCH] sub/gsub capture-group iterate --- c/lib/mlrutil.c | 27 ++++++--------------------- c/lib/mlrutil.h | 7 ++++--- c/mapping/mlr_val.c | 6 ++++-- c/todo.txt | 6 ++++-- 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/c/lib/mlrutil.c b/c/lib/mlrutil.c index b0d818c20..eee076ce2 100644 --- a/c/lib/mlrutil.c +++ b/c/lib/mlrutil.c @@ -463,31 +463,14 @@ int regmatch_or_die(const regex_t* pregex, const char* restrict match_string, // allocated. If not, input is returned. So in either case, the caller should // free the return value, and it is assumed that the input has been dynamically // allocated. -char* regex_sub(char* input, regex_t* pregex, string_builder_t* psb, char* replacement) { +char* regex_sub(char* input, regex_t* pregex, string_builder_t* psb, char* replacement, int *pall_captured) { const size_t nmatch = 10; // Capture-groups \1 through \9 supported, along with entire-string match regmatch_t matches[nmatch]; + *pall_captured = TRUE; int matched = regmatch_or_die(pregex, input, nmatch, matches); if (!matched) { return input; - } else if (matches[1].rm_so == -1) { // No capture groups: only a replacement string - int so = matches[0].rm_so; - int eo = matches[0].rm_eo; - - int len1 = so; - int olen2 = eo - so; - int nlen2 = strlen(replacement); - int len3 = strlen(&input[len1 + olen2]); - int len4 = len1 + nlen2 + len3; - - char* output = mlr_malloc_or_die(len4 + 1); - strncpy(&output[0], input, len1); - strncpy(&output[len1], replacement, nlen2); - strncpy(&output[len1+nlen2], &input[len1+olen2], len3); - output[len4] = 0; - - free(input); - return output; } else { // sed: // $ echo '<>'|sed 's/ab\(.\)d\(..\)g/AYEBEE\1DEE\2GEE/' @@ -504,6 +487,7 @@ char* regex_sub(char* input, regex_t* pregex, string_builder_t* psb, char* repla int idx = p[1] - '0'; regmatch_t* pmatch = &matches[idx]; if (pmatch->rm_so == -1) { + *pall_captured = FALSE; sb_append_chars(psb, p, 0, 1); } else { sb_append_chars(psb, input, matches[idx].rm_so, matches[idx].rm_eo-1); @@ -520,9 +504,10 @@ char* regex_sub(char* input, regex_t* pregex, string_builder_t* psb, char* repla } } -char* regex_gsub(char* input, regex_t* pregex, string_builder_t* psb, char* replacement) { - const size_t nmatch = 1; // xxx temp: parameterize after adding capture-group support +char* regex_gsub(char* input, regex_t* pregex, string_builder_t* psb, char* replacement, int* pall_captured) { + const size_t nmatch = 10; regmatch_t pmatch[nmatch]; + *pall_captured = TRUE; int match_start = 0; char* current_input = input; diff --git a/c/lib/mlrutil.h b/c/lib/mlrutil.h index 60ee9359d..9dd1bea53 100644 --- a/c/lib/mlrutil.h +++ b/c/lib/mlrutil.h @@ -134,8 +134,9 @@ int regmatch_or_die(const regex_t* pregex, const char* restrict match_string, // If there is a match, input is freed and return value is dynamically // allocated. If not, input is returned. So in either case, the caller should // free the return value, and it is assumed that the input has been dynamically -// allocated. -char* regex_sub(char* input, regex_t* pregex, string_builder_t* psb, char* replacement); -char* regex_gsub(char* input, regex_t* pregex, string_builder_t* psb, char* replacement); +// allocated. The by-reference all-captured flag is true on return if all \1, +// etc. were satisfiable by parenthesized capture groups. +char* regex_sub(char* input, regex_t* pregex, string_builder_t* psb, char* replacement, int* pall_captured); +char* regex_gsub(char* input, regex_t* pregex, string_builder_t* psb, char* replacement, int* pall_captured); #endif // MLRUTIL_H diff --git a/c/mapping/mlr_val.c b/c/mapping/mlr_val.c index a5336d40a..1c4d83f21 100644 --- a/c/mapping/mlr_val.c +++ b/c/mapping/mlr_val.c @@ -203,8 +203,9 @@ mv_t sub_no_precomp_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) { // * len4 = 6 = 2+3+1 mv_t sub_precomp_func(mv_t* pval1, regex_t* pregex, string_builder_t* psb, mv_t* pval3) { + int all_captured = FALSE; char* input = pval1->u.strv; - char* output = regex_sub(input, pregex, psb, pval3->u.strv); + char* output = regex_sub(input, pregex, psb, pval3->u.strv, &all_captured); free(pval3->u.strv); pval1->u.strv = NULL; @@ -234,8 +235,9 @@ mv_t gsub_no_precomp_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) { } mv_t gsub_precomp_func(mv_t* pval1, regex_t* pregex, string_builder_t* psb, mv_t* pval3) { + int all_captured = FALSE; char* input = pval1->u.strv; - char* output = regex_gsub(input, pregex, psb, pval3->u.strv); + char* output = regex_gsub(input, pregex, psb, pval3->u.strv, &all_captured); free(pval3->u.strv); pval1->u.strv = NULL; diff --git a/c/todo.txt b/c/todo.txt index 2d81fb044..1c116558d 100644 --- a/c/todo.txt +++ b/c/todo.txt @@ -14,7 +14,7 @@ release notes: * check minor incompatibilities * what else ... -! brew version?!? +! brew version bump?!? ---------------------------------------------------------------- MINOR: sampler UTs (w/ spec rand seed) @@ -27,11 +27,13 @@ MAJOR: regex - sub($name, "a.*b(c.*d)e(f)g", "hij") - sub($name, "a.*b(c.*d)e(f)g", "h\1i\2j") +* mlr --regex-help; xrefs from put/filter/et al. -h's; into mld?? + ! finish gsub with capture groups -! check so==-1 @ idx fetch ! UTs x all x thorough ! free-the-input flag. or, don't free inside regex_[g]sub ! captured-all flag for gsub so caller can abend + -> check perl/ruby/etc for prior expected behavior ... * regex field names in rename: mlr rename '(.*)in(.*),\1foo\2' -> requires capture groups 1st