在分隔符sed regex之间转换文本

时间:2017-02-01 23:36:55

标签: regex bash macos sed

我希望将拉丁语中的西里尔字符转换为特定分隔符 - $$[]。我在指定转换范围时遇到了问题。

我想出了:

sed -i '' '/[\[$][^$\[]*[\[$]/ y/АаІіВСсЕеРТтОоКкХхМ/AaIiBCcEePTtOoKkXxM/' wrong.txt

但这取代了以下示例中的所有文字:

wrong.txt:

Тут тeкст $DЕV$ ще текст...,.. $РRОVS$
 $NUМ|Y$ $DUСАТS|Y$¤ багато тексту" 
"$АDJ$ dhfg [Rооt.GеtNаmе]%
 $NАМЕ$ \n"
§Y$VАL$§!¤"

注意:我使用OS X。

注2:转换不是问题,正则表达式是。

预期输出(即指定标签内的文字变为拉丁语):

Тут текст $DEV$ ще текст...,.. $PROVS$
 $NUM|Y$ $DUCATS|Y$¤ багато тексту" 
"$ADJ$ dhfg [Root.GetName]%
 $NAME$ \n"
§Y$VAL$§!¤"
[GetCapitalName]

1 个答案:

答案 0 :(得分:1)

使用sed这样做(经常)有点痛苦,而Perl或awk解决方案可能更短,更易读 - 但这是sed中的一个。

调用
sed -E -f sedscr.sed wrong.txt

其中wrong.txt是您的输入,而sed脚本位于sedscr.sed中,如下所示:

/\$[^$]*\$/ {
    :label1
    h
    s/.*(\$[^$]*\$).*/\1/
    y/АаІіВСсЕеРТтОоКкХхМ/AaIiBCcEePTtOoKkXxM/
    s/\$/~~/g
    G
    s/(.*)\n(.*)\$[^$]*\$(.*)/\2\1\3/
    /\$[^$]*\$/b label1
    s/~~/$/g
}
/\[[^]]*\]/ {
    :label2
    h
    s/.*(\[[^]]*\]).*/\1/
    y/АаІіВСсЕеРТтОоКкХхМ/AaIiBCcEePTtOoKkXxM/
    s/[][]/~~/g
    G
    s/(.*)\n(.*)\[[^]]*\](.*)/\2\1\3/
    /\[[^]]*\]/b label2
    :label3
    s/~~/[/
    s/~~/]/
    /~~/b label3
}

两个主要块都检查该行是否包含$$[]对,如果是,则进行翻译。模式始终相同:假设您的行看起来像

abcdef $abc$ abcdef $def$ abc

并且您希望音译为大写。首先,我们将模式空间复制到保留空间(h),然后删除最后一对标记(s/.*(\$[^$]*\$).*/\1/)之外的所有内容。现在我们用y/abcdef/ABCDEF/音译。

要将该对标记为已完成,我们会将其替换为不在文本中的内容:两个~个字符(s/\$/~~/g)。 G将保留空间附加到模式空间,现在看起来像

~~DEF~~
abcdef $abc$ abcdef $def$ abc

复杂的替换s/(.*)\n(.*)\$[^$]*\$(.*)/\2\1\3/导致

abcdef $abc$ abcdef ~~DEF~~ abc

现在我们检查是否还有一对$,如果是,我们会分支到:label1/\$[^$]*\$/b label1)。当我们不再分支时,所有$$都已处理完毕,我们可以再次将~~替换为$s/~~/$/g)。

第二个区块中的[]原则上是相同的;唯一的区别是当替换~~时,我们使用另一个循环,因为我们必须插入交替的[]

这是输出:

$ sed -E -f sedscr.sed wrong.txt
Тут тeкст $DEV$ ще текст...,.. $PROVS$
 $NUM|Y$ $DUCATS|Y$¤ багато тексту"
"$ADJ$ dhfg [Root.GetName]%
 $NAME$ \n"
§Y$VAL$§!¤"

或者,更具说明性,在我的终端模拟器之前和之后可以看到非拉丁字符:

terminal printscreen

相关问题