我有一个文件,该文件的文本范围由<BD>
开始和<ED>
结束定界符分隔,并允许嵌套。我希望更改这些定界符,以唯一地指示它们之间的每个文本范围。这些定界符可以是任意字符串。例如:
%{ # Begin delimiter <BD>
}% # End delimiter <ED>
我正在寻找用唯一编号的标记替换定界符:
<BM><UniqueNumber><BM> # <BD> is replaced by <BM>i<BM>
<EM><UniqueNumber><EM> # <ED> is replaced by <EM>i<EM>
<BM>
和<EM>
是任意长度的字符串,可以是二进制的,并且不存在于正在处理的文件中。例如,在大多数文本文件中,可以将$'\x01'
用作<BM>
,将$'\x02'
用作<EM>
。例如,文件包含定界的文本范围,包括嵌套范围:
A %{ B
C %{ D
E }% F %{ G }% H }% I
J %{ K }% L
字母A..L可以是任何文本。转换产生:
A <BM>0<BM> B
C <BM>1<BM> D
E <EM>1<EM> F <BM>2<BM> G <EM>2<EM> H <EM>0<EM> I
J <BM>3<BM> K <EM>3<EM> L
注意:我不是在寻找表示嵌套级别的编号。我正在寻找每个匹配的
<BM>i<BM>...<EM>i<EM>
文本范围,这些范围要用从0向上计数的唯一整数进行标记。而且,我希望能够存储为标记0..N-1生成的最大数量N。我在想象Bash函数:
ChangeMarkup()
{
local InputFile="$1"
local OutputFile="$2"
local BD="$3" # Begin delimiter
local ED="$4" # End delimiter
local BM="$5" # Begin unique numbered marker
local EM="$6" # End unique numbered marker
local -i N=0
# ... convert InputFile to OutputFile, incrementing N for each span
echo "$N" # Echo the number of spans
}
# Example invocation:
NSpans=$(ChangeMarkup infile outfile '%{' '}%' $'\x01' $'\x02')
我认为解决方案将是:
初始化
N=0
扫描
<BD>
并将N
推入堆栈。将<BD>
替换为<BM>$N<BM>
。递增N
。扫描
<ED>
并替换为<EM><pop stack><EM>
最后,回显
$N
我认为Bash脚本中的某些awk可能可以解决。我认为这超出了sed的能力。我也欢迎使用python或可以用Bash脚本编写的任何解决方案,仅限于使用CentOS 7 Minimal iso中可用的软件包。不幸的是,这意味着不能考虑perl。
最佳答案
如果可以,可以使用gnu-awk
和RT special variable
awk -v BD='%{' -v ED='}%' -v BM='<BM>' -v EM='<EM>' '
BEGIN{i=c=-1; RS=BD"|"ED}
RT==BD {++i; ++c; d[i]=c; tag=BM}
RT==ED {tag=EM}
{printf "%s%s%s%s",$0,tag,d[i],tag}
RT==ED{--i; if(i==-1) tag=""}
' file
你得到,
A <BM>0<BM> B
C <BM>1<BM> D
E <EM>1<EM> F <BM>2<BM> G <EM>2<EM> H <EM>0<EM> I
J <BM>3<BM> K <EM>3<EM> L
编辑:要求(2)
如果检测到不正确的嵌套,脚本可以返回错误代码吗?例如:%{A}%}%秒没有
awk -v BD='%{' -v ED='}%' -v BM='<BM>' -v EM='<EM>' '
BEGIN{i=c=-1; RS=BD"|"ED}
RT==BD {++i; ++c; d[i]=c; tag=BM}
RT==ED {tag=EM}
{
if(i<0 && tag!=""){
print "Error <ED> without opener" > "/dev/stderr"
exit 1
}
printf "%s%s%s%s",$0,tag,d[i],tag
}
RT==ED{--i; if(i==-1) tag=""}
END{
if(i!=-1){
print "Error <BD> without closer" > "/dev/stderr"
exit 1
}
}
' file
编辑:要求(1)
允许和逃脱?也就是说,如果这些定界符前面有反斜杠,则不会将它们视为定界符
和转义的例如是
\%{
和\}%
awk -v BD='%{' -v ED='}%' -v BM='<BM>' -v EM='<EM>' '
BEGIN{i=c=-1; RS="\\\\"BD"|\\\\"ED"|"BD"|"ED}
RT==BD {++i; ++c; d[i]=c; tag=BM}
RT==ED {tag=EM}
RT~/^\\/{printf "%s%s",$0,RT; next}
{
if(i<0 && tag!=""){
print "Error <ED> without opener" > "/dev/stderr"
exit 1
}
printf "%s%s%s%s",$0,tag,d[i],tag
}
RT==ED{--i; if(i==-1) tag=""}
END{
if(i!=-1){
print "Error <BD> without closer" > "/dev/stderr"
exit 1
}
}
' file
与输入文件
A %{ B
C %{ D
E }% F %{ G }% H }% I
J %{ K }% L\%{ M\}%O
你得到,
A <BM>0<BM> B
C <BM>1<BM> D
E <EM>1<EM> F <BM>2<BM> G <EM>2<EM> H <EM>0<EM> I
J <BM>3<BM> K <EM>3<EM> L\%{ M\}%O
关于python - 如何用唯一编号的标记跨度替换定界跨度?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42645692/