Perl命令行替换为unicode

时间:2017-07-21 15:48:03

标签: regex bash perl unicode

我正在尝试用shell脚本替换每个单词(存储在名为_id的tmp文件中)。它工作正常,除了unicode单词,生成一个数字但使用Perl替换不起作用。有问题的bash代码如下:

x=0
for id in `cat _id`; do
    echo $x $id
    perl -p -i -e "s/\b$id\b/$x/g" x_graph.dot
    x=$(($x + 1))
done 

有人可以指出错误的位置吗?

3 个答案:

答案 0 :(得分:2)

假设您使用UTF-8编码é(U + 00E9):C3 A9。由于您不进行任何解码,因此您将获得由"\xC3\xA9"生成的字符串。

正则表达式 - 或者\b\w\d等等 - 期望输入为Unicode代码点,这意味着您有效地提供U+00C3和{ {3}}而不是U + 00E9。 U + 00C3是单词字符,但U + 00A9不是,因此第二个\b与预期匹配的位置不匹配。

因此您需要解码输入并对输出进行编码。 -C为UTF-8提供了一种方便的方法。

perl -i -CSDA -pe'
   BEGIN {
      ($id, $x) = splice(@ARGV, 0, 2);
      die "Bad id" if $id !~ /^\w(?:.*\w)?\z/s;
   }

   s/\b\Q$id\E\b/$x/g
' "$id" "$x" x_graph.dot

注意:

  • 通过使用命令行参数传递参数,我修复了注入错误。

  • \b的使用假定$id始终以\w字符开头,并始终以\w字符结尾,因此我添加了一个检查验证这个假设。

  • 通过使用\Q..\E将id转换为正则表达式模式,我修复了注入错误。

测试:

$ printf "é\n" >_id

$ printf "[é]\n" >x_graph.dot

$ x=0

$ id=`cat _id`

$ perl -i -CSDA -pe'
   BEGIN {
      ($id, $x) = splice(@ARGV, 0, 2);
      die "Bad id" if $id !~ /^\w(?:.*\w)?\z/s;
   }

   s/\b\Q$id\E\b/$x/g
' "$id" "$x" x_graph.dot

$ cat x_graph.dot
[0]

答案 1 :(得分:1)

请参阅perldoc perlrun

  

-C [number / list]

     

-C标志控制一些Perl Unicode功能:

I     1   STDIN is assumed to be in UTF-8
O     2   STDOUT will be in UTF-8
E     4   STDERR will be in UTF-8
S     7   I + O + E
i     8   UTF-8 is the default PerlIO layer for input streams
o    16   UTF-8 is the default PerlIO layer for output streams
D    24   i + o
A    32   the @ARGV elements are expected to be strings encoded
          in UTF-8

所以,至少,您需要perl -COi,但perl -CSD看起来更整洁。

此外,您可能想要使用

  根据Unicode规则

u匹配

与您的s///。或者,写:

perl -CSD -Mutf8 -Mfeature=unicode_strings -p -i -e "s/\b$id\b/$x/g" x_graph.dot

请注意使用单引号而不是双引号,以避免意外插值。

答案 2 :(得分:1)

  1. 添加-Mutf8(相当于use utf8;):这将在源代码中启用UTF-8(在您的情况下为-e一行)。

    < / LI>
  2. 添加-CD:这会使perl使用UTF-8作为输入和输出流的默认图层。

  3. 以下测试在LANG=en_US.UTF-8

    下产生了所需的结果
    echo "a ó b" > z.txt
    id=ó
    x=ń
    perl -CD -Mutf8 -p -i -e "s/\b$id\b/$x/g" z.txt
    cat z.txt