1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
# 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;
}
|