我希望将拉丁语中的西里尔字符转换为仅特定分隔符 - $$
和[]
。我在指定转换范围时遇到了问题。
我想出了:
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]
答案 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$§!¤"
或者,更具说明性,在我的终端模拟器之前和之后可以看到非拉丁字符: