sub/gsub capture-group iterate

This commit is contained in:
John Kerl 2015-10-14 23:12:05 -04:00
parent f5d5d8be12
commit f98d159959
4 changed files with 18 additions and 28 deletions

View file

@ -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 '<<abcdefg>>'|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;

View file

@ -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

View file

@ -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;

View file

@ -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