使用 sed 忽略部分字符串

使用 sed 忽略部分字符串

所以,我的文件的文本格式如下:

untranslatedString : "translated string",

我需要将“翻译字符串”部分中的字符替换为其西里尔字母表示形式。我用这样的东西:

paste <(sed 's/\([^:]\+:\)\([^:]\+\)/\1/' resources.js) <(sed 's/[^:]\+:\([^:]\+\)/\1/;y/abc/абц/' resources.js)

(abc/абц/ 部分实际上更长并且包括所有字符,这是为了说明目的)。

问题出现在这样的行中:

abcTestString : "abc {ccb} bbc",

{} 之间的所有内容都应保留其原始状态,即。字符不应该被替换。结果应该是:

abcTestString : "aбц {ccb} ббц",

并不是

abcTestString : "aбц {ццб} ббц",

此外,每行可以有多个 {} 部分。

我怎样才能做到这一点?

答案1

如果你可以使用perl

$ s='abcTestString : "abc {ccb} bbc",'
$ echo "$s" | perl -Mopen=locale -Mutf8 -F: -lane '
               $F[-1]=~s/\{[^{}]+\}(*SKIP)(*F)|[a-z]+/$&=~tr|abc|абц|r/ge;
               print join ":",@F'
abcTestString : "абц {ccb} ббц",
  • -Mopen=locale -Mutf8unicode 设置(感谢这个精彩的答案unicode 字符的 tr 模拟?
  • -F: -lane用作:字段分隔符,保存在@F数组中(参见https://perldoc.perl.org/perlrun.html#命令开关对于其他选项)
  • $F[-1]@F数组的最后一个字段
  • \{[^{}]+\}(*SKIP)(*F)|[a-z]+在这里我们说该[a-z]+部分必须匹配,但\{[^{}]+\}应保持原样
  • $&=~tr|abc|абц|r对匹配部分进行音译
  • geg用于替换所有匹配项的修饰符,用于e允许替换部分中的 Perl 代码的修饰符


如果代码太大而无法从命令行处理,请将其更改为程序

$ echo "$s" | perl -MO=Deparse -Mopen=locale -Mutf8 -F: -lane '
               $F[-1]=~s/\{[^{}]+\}(*SKIP)(*F)|[a-z]+/$&=~tr|abc|абц|r/ge;
               print join ":",@F'
BEGIN { $/ = "\n"; $\ = "\n"; }
use open (split(/,/, 'locale', 0));
use utf8;
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    our @F = split(/:/, $_, 0);
    $F[-1] =~ s[\{[^{}]+\}(*SKIP)(*F)|[a-z]+][use utf8 ();
    $& =~ tr/abc/\x{430}\x{431}\x{446}/r;]eg;
    print join(':', @F);
}

答案2

如果您想留在sed

sed 's/"/"_/;:l
  s/_[^{]*/&_/;h
  s/.*_\(.*\)_.*/\1/
  y/abc/абц/;G
  s/\(.*\)\n\(.*\)_.*_\([^}]*}\)\{0,1\}/\2\1\3_/
  /_$/!bl
  s/_//'

处理过程中使用下划线作为标记。如果下划线可以是文件的一部分,请使用不同的分隔符。

这个想法是标记字符串的一部分,保存一个副本以保留空间,删除标记之外的所有内容,进行转换,取回副本,用转换后的部分组成一个字符串并将下划线向前移动。如果 中有一部分{},则跳过该部分。

如果您有兴趣,我可以提供更详细的解释。

答案3

sed -rf <(echo ':l'; printf 's/("| [^{]*)%s/\\1%s/g\n' a а b б c ц; echo 'tl') input.txt

或者更简洁,但也更容易出错,因为seds 表达式用双引号括起来,而不是用单引号括起来,因此bash应该转义特殊字符,例如$符号。

sed -r ":l; $(printf 's/("| [^{]*)%s/\\1%s/g;' a а b б c ц) tl" input.txt

解释(第一个命令被执行)

sed -f script-file- 将脚本文件的内容添加到要执行的命令中。

<()- 流程替代。它允许将命令输出表示为文件并将其传递给需要文件的命令。

echo ':l'; printf 's/("| [^{]*)%s/\\1%s/g\n' a а b б c ц; echo 'tl'- 它正在转换为下一个sed命令序列:

:l
s/("| [^{]*)a/\1а/g
s/("| [^{]*)b/\1б/g
s/("| [^{]*)c/\1ц/g
tl

测试:

输入

abcTestString : "abc {bcb} bbc",
abcTestString : "bbc {acb} bbc {bcb}",
abcTestString : "acc {cab} {ccb} bbc",
abcTestString : "cbc {ccb} bac {aca} bac",

输出

abcTestString : "абц {bcb} ббц",
abcTestString : "ббц {acb} ббц {bcb}",
abcTestString : "ацц {cab} {ccb} ббц",
abcTestString : "цбц {ccb} бац {aca} бац",

相关内容