如何用唯一编号的标记跨度替换分隔的跨度?
How to replace delimited spans with uniquely-numbered marked spans?
我有一个由 <BD>
begin 和 <ED>
end delimiters 分隔的文本文件允许嵌套。我希望更改这些分隔符以唯一地指示它们之间的每个文本范围。这些定界符可以是任意字符串。例如:
%{ # 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>
是任意长度的字符串,可以是二进制的,并且不存在于正在处理的文件中。例如,在大多数文本文件中,<BM>
可以使用 $'\x01'
,<EM>
可以使用 $'\x02'
。
例如,文件包含带分隔符的文本跨度,包括嵌套跨度:
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[=69= 生成的最大数量 N ].我在想象 Bash 函数:
ChangeMarkup()
{
local InputFile=""
local OutputFile=""
local BD="" # Begin delimiter
local ED="" # End delimiter
local BM="" # Begin unique numbered marker
local EM="" # 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 最小版 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",[=10=],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)
if improper nesting is detected, that the script can return an error code? For example: %{ A }% }% the second has no
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",[=12=],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)
to allow for the and to be escaped? That is, if there is a backslash in front of these delimiters, then they're not treated as delimiters
例如 和转义为 \%{
和 \}%
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",[=13=],RT; next}
{
if(i<0 && tag!=""){
print "Error <ED> without opener" > "/dev/stderr"
exit 1
}
printf "%s%s%s%s",[=13=],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
我有一个由 <BD>
begin 和 <ED>
end delimiters 分隔的文本文件允许嵌套。我希望更改这些分隔符以唯一地指示它们之间的每个文本范围。这些定界符可以是任意字符串。例如:
%{ # 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>
是任意长度的字符串,可以是二进制的,并且不存在于正在处理的文件中。例如,在大多数文本文件中,<BM>
可以使用 $'\x01'
,<EM>
可以使用 $'\x02'
。
例如,文件包含带分隔符的文本跨度,包括嵌套跨度:
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[=69= 生成的最大数量 N ].我在想象 Bash 函数:
ChangeMarkup()
{
local InputFile=""
local OutputFile=""
local BD="" # Begin delimiter
local ED="" # End delimiter
local BM="" # Begin unique numbered marker
local EM="" # 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 最小版 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",[=10=],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)
if improper nesting is detected, that the script can return an error code? For example: %{ A }% }% the second has no
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",[=12=],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)
例如to allow for the and to be escaped? That is, if there is a backslash in front of these delimiters, then they're not treated as delimiters
和转义为 \%{
和 \}%
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",[=13=],RT; next}
{
if(i<0 && tag!=""){
print "Error <ED> without opener" > "/dev/stderr"
exit 1
}
printf "%s%s%s%s",[=13=],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