【问题标题】:Odd tr/// operator behavior with the /c modifier in PerlPerl 中带有 /c 修饰符的奇怪 tr/// 运算符行为
【发布时间】:2013-03-24 12:53:29
【问题描述】:

/c 修饰符在这里做了一些我不明白的事情。我想知道为什么下面的代码会打印“abc3333”?

#!/usr/bin/perl
$x = 'abcdefg';
$x =~ tr/abc/123/c;
print $x;

【问题讨论】:

  • 这是一个有效的问题,尽管措辞可能很糟糕。音译上的/c修饰符代表“补码”,这在perlop "If the /c modifier is specified, the SEARCHLIST character set is complemented."中有解释,这确实是一个非常弱的解释。基本上,这意味着它会音译任何与“abc”不匹配的字符。
  • 谁从这个问题的标题中删除了“tr”? How to use in perl? 如何在任何地方都是一个有效的问题?
  • 如果您阅读文档-perldoc.perl.org/perlop.html :-) 可能会有更多机会理解它

标签: perl tr


【解决方案1】:

/c 使搜索列表得到补充;也就是说,未列出的每个字符都会被搜索。

假设您只有\0-\xff 范围内的字符,则:

tr/abc/123/c

等价于:

tr/\0-\x60\x64-\xff/123/

并且替换列表的最后一个字符会根据需要重复多次以匹配搜索列表中的字符数(不使用 /d 时)。

所以“\0”变成“1”,“\1”变成“2”,“a”、“b”或“c”不变,其他任何字符变成“3”。

用 /c 指定替换列表是相当不寻常的;通常 /c 仅用于计数:

tr/abc//c # returns number of non-abc characters; string is unchanged

或删除:

tr/0-9//cd # delete all non-digits

【讨论】:

  • 致:你tr/abc//c写错了,右边是tr/abc/ /c
  • @baozailove:不,有空格它会将所有 nul 字符更改为空格。只有一个空的替换列表(并且没有 /d) tr/// 才成为一个计数运算符。为什么你认为应该有一个空间?
  • 致:你说tr/abc//c #returns number of non-abc characters;,但是我执行了返回abcdefg的代码并且不返回no abc characters
  • @baozailove: $x = "ajdsfjwlljja"; print $x =~ tr/abc//c; 打印 10(并且保持 $x 不变)。我不知道你在说什么,你能举个例子吗?
【解决方案2】:

/c通常用来修饰/d

tr/...//d;    # Delete every matching char.
tr/...//cd;   # Delete every char that doesn't match.

或用于计数。

tr/...//;    # Returns number of matching chars.
tr/...//c;   # Returns number of chars that don't match.

我无法用非空替换集为它提供一个有用的示例,但它很容易解释:它只是使用搜索集的补集。请记住,a、b 和 c 是字符 0x61、0x62 和 0x63,

tr/abc/123/c;

因此等价于

tr/\x00-\x60\x64-\x{FFFFFFFFF}/123/;            # Perl with 32bit ints
  or
tr/\x00-\x60\x64-\x{FFFFFFFFFFFFFFFFFF}/123/;   # Perl with 64bit ints

请记住,替换集的最后一个字符用于搜索集中没有对应字符的字符,

  • "\x00" 变为 1
  • "\x01" 变为 2
  • 其他匹配的都变成3。

此行为与tr/// 所基于的tr 命令行工具完全一致。我不确定在没有/d 的情况下/c 会有什么用处,但也许是因为tr 命令行工具具有超过tr/// 的额外功能(例如字符类)。

【讨论】:

  • 我觉得这有点令人困惑,所以添加了我自己的答案:)
  • @ikegami:为什么a是字符0x61?
  • @baozailove: 因为那是 'a' 在 ASCII 和 utf8 中的字符代码:printf "%x\n", ord("a");
  • @baozailove,每个码位都有一个编号。这是a 的号码。 "a" 和 "\x61" 产生相同的字符串。
【解决方案3】:

/c 修饰符影响列表中字符的补码。它主要与/d 修饰符一起使用,删除给定字符集以外的所有字符。

my $string = 'ABCdef123';
$string =~ tr/a-z//cd;
print $string;

输出

def

【讨论】:

    猜你喜欢
    • 2010-12-16
    • 2012-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-13
    • 2011-11-13
    • 1970-01-01
    • 2015-11-17
    相关资源
    最近更新 更多