这是我对此的看法。在 FreeBSD 中测试,所以我希望它几乎可以在任何地方工作......
#!/usr/bin/awk -f
BEGIN {
depth=1;
}
$1 ~ /^#(\.#)*\)$/ {
thisdepth=split($1, _, ".");
if (thisdepth < depth) {
# end of subsection, back out to current depth by deleting array values
for (; depth>thisdepth; depth--) {
delete value[depth];
}
}
depth=thisdepth;
# Increment value of last member
value[depth]++;
# And substitute it into the current line.
for (i=1; i<=depth; i++) {
sub(/#/, value[i], $0);
}
}
1
基本思想是我们维护value[]
嵌套章节值的数组 ()。根据需要更新数组后,我们逐步遍历这些值,每次都将第一次出现的 octothorpe ( #
) 替换为数组该位置的当前值。
这将处理任何级别的嵌套,正如我上面提到的,它应该在 GNU(Linux)和非 GNU(FreeBSD、OSX 等)版本的 awk 中工作。
当然,如果你喜欢单线,这可以被压缩:
awk -vd=1 '$1~/^#(\.#)*\)$/{t=split($1,_,".");if(t<d)for(;d>t;d--)delete v[d];d=t;v[d]++;for(i=1;i<=d;i++)sub(/#/,v[i],$0)}1'
为了便于阅读,也可以这样表达:
awk -vd=1 '$1~/^#(\.#)*\)$/{ # match only the lines we care about
t=split($1,_,"."); # this line has 't' levels
if (t<d) for(;d>t;d--) delete v[d]; # if levels decrease, trim the array
d=t; v[d]++; # reset our depth, increment last number
for (i=1;i<=d;i++) sub(/#/,v[i],$0) # replace hash characters one by one
} 1' # and print.
更新
在考虑了一会儿之后,我意识到这可以进一步缩小。循环包含自己的for
条件,无需将其放在if
. 和
awk '{
t=split($1,_,"."); # get current depth
v[t]++; # increment counter for depth
for(;d>t;d--) delete v[d]; # delete record for previous deeper counters
d=t; # record current depth for next round
for (i=1;i<=d;i++) sub(/#/,v[i],$0) # replace hashes as required.
} 1'
这当然会缩小成这样的一个衬里:
awk '{t=split($1,_,".");v[t]++;for(;d>t;d--)delete v[d];d=t;for(i=1;i<=d;i++)sub(/#/,v[i],$0)}1' file
显然,如果需要,您可以添加初始匹配条件,以便只处理看起来像标题的行。
尽管长了几个字符,但我相信这个版本的运行速度比 karakfa 的类似解决方案略快,可能是因为它避免了循环if
每次迭代的额外内容for
。
更新#2
我包括这个是因为我发现它很有趣。您可以单独在 bash 中执行此操作,无需 awk。就代码而言,它的时间并不长。
#!/usr/bin/env bash
while read word line; do
if [[ $word =~ [#](\.#)*\) ]]; then
IFS=. read -ra a <<<"$word"
t=${#a[@]}
((v[t]++))
for (( ; d > t ; d-- )); do unset v[$d]; done
d=t
for (( i=1 ; i <= t ; i++ )); do
word=${word/[#]/${v[i]}}
done
fi
echo "$word $line"
done < input.txt
这遵循与上面的 awk 脚本相同的逻辑,但完全在 bash 中使用参数扩展来替换#
字符。它遭受的一个缺陷是它不会在每行的第一个单词周围保留空格,因此您会丢失任何缩进。通过一些工作,这也可以得到缓解。
享受。