# gosub(regexp, replacement [, target]) # Aka global original sub # Behaves like gsub, however doesn't try regexp on previoud replacements # and returns the result string, rather than doing it inplace. function gosub(regexp, replacement, target) { if (!length(target)) { target = $0; } result = ""; matched = ""; while (match(target, regexp)) { result = result substr(target, 1, RSTART - 1); matched = substr(target, RSTART, RLENGTH); target = substr(target, RSTART + RLENGTH); sub(regexp, replacement, matched); result = result matched; } return result target; } # gesub(regexp, exregexp, replacement [, target]) # Aka global excluding sub # Behaves like gsub, however substitutes only where exregexp doesn't match # and returns the result string, rather than doing it inplace. function gesub(regexp, exregexp, replacement, target) { if (!length(target)) { target = $0; } result = ""; while (match(target, exregexp)) { beg = substr(target, 1, RSTART - 1); exclude = substr(target, RSTART, RLENGTH); target = substr(target, RSTART + RLENGTH); gsub(regexp, replacement, beg); result = result beg exclude; } gsub(regexp, replacement, target); return result target; } # glsub(lbregexp, regexp, largexp, replacement [, target]) # Aka global sub with non-capturing look-around (lookbehind and lookahead) # Behaves kind of like gsub, however substitution of regexp with replacement # only happens, when regexp is preceded by lbregexp and succeeded by laregexp. # Only regexp get's replaced, the matches of lbregexp and laregexp are left # as-is. Overlapping of the lookahead and lookbehind substrings is supported, # but any sort of overlapping which includes regexp isn't. # This function is quite slow, try to use as little as possible. # Returns the result string, rather than doing it inplace. function glsub(lbregexp, regexp, laregexp, replacement, target) { if (!length(target)) { target = $0; } result = "" while (match(target, lbregexp regexp)) { result = result substr(target, 1, RSTART - 1); matched = substr(target, RSTART, RLENGTH); target = substr(target, RSTART + RLENGTH); match(target, laregexp); if (RSTART == 1) { match(matched, regexp); result = result substr(matched, 1, RSTART - 1); matched = substr(matched, RSTART); sub(/.*/, replacement, matched); } result = result matched; } return result target; } # gbsub(lbrace, rbrace, replacement [, target ]) # Aka global brace sub # Properly substitutes recursive braced expressions, i.e. # for "((1+2) * (3/(4-9)))", substitution is done first # on "(1+2)", then on "(4-9)", afterwards on "(3/SOMETHING)" # (where "(4-9)" turns into "SOMETHING" after substitution), # and finally, the whole equation (with it's inner stuff # substituted) is substituted. # This is useful when one of the braces can exist as-is, but # can also be paired with a special (opening/closing) brace. # For example, in bash parameter expansion is specified with # "${...}", however "}" can also be the closing brace of a function. function gbsub(lbrace, rbrace, replacement, target) { if (!length(target)) { target = $0; } result = substr(target, 1, match(target, lbrace) - 1); depth = 1; LLN = 0; while (!(LLN == -1 && depth == 1)) { match(target, lbrace); LST = RSTART; LLN = RLENGTH; match(target, rbrace); # rbrace, pop stack if (depth > 1 && (LST == 0 || LST > RSTART)) { depth--; level[depth] = level[depth] substr(target, 1, RSTART + RLENGTH - 1); sub(/.*/, replacement, level[depth]); if (depth > 1) { level[depth - 1] = level[depth - 1] level[depth]; } else { result = result level[1]; level[1] = ""; } target = substr(target, RSTART + RLENGTH); } # lbrace, push stack else if (LST > 0 && LST < RSTART) { if (depth > 1) prev = depth - 1; else prev = depth; level[prev] = level[prev] substr(target, 1, LST - 1); level[depth++] = substr(target, LST, LLN); target = substr(target, LST + LLN); } } return result target; }