代码之家  ›  专栏  ›  技术社区  ›  sid_com

List::Util-reduce-length-encoding-question

  •  2
  • sid_com  · 技术社区  · 14 年前

    为什么第一个reduce示例会得到错误的结果?

    test.txt文件

    __BE  
    bb bbbbbbbbbbbbbbb  
    
    aaaaaa  
    

    测试.pl

    #!/usr/bin/env perl
    use warnings; use 5.012;
    use open ':encoding(UTF-8)';
    use List::Util qw(reduce);
    use Encode;
    
    my( @list, $longest, $len );
    open my $fh, '<', 'test.txt' or die $!;
        while( my $line = readline( $fh ) ) {
        chomp $line;
        push @list, split( /\s+/, $line );
        }
    close $fh;
    
    $longest = reduce{ length($a) > length($b) ? $a : $b } @list;
    $len = length $longest;
    say $longest; # aaaaaa
    say $len;     # 6
    
    $longest = reduce{ length(Encode::encode_utf8($a)) > length(Encode::encode_utf8($b)) ? $a : $b } @list;
    $len = length(Encode::encode_utf8($longest));
    say $longest;  # bbbbbbbbbbbbbbb
    say $len;     # 15
    
    $longest = $list[0];
    $len = length $longest;
    for my $str (@list) {
        if ( length($str) > $len ) {
            $longest = $str;
            $len = length($str);
        }
    }
    say $longest; # bbbbbbbbbbbbbbb
    say $len;     # 15
    
    2 回复  |  直到 14 年前
        1
  •  2
  •   Jonathan Leffler    14 年前

    AFAICS,它甚至可能是Perl中的一个bug……它的行为是否正确显然不是很明显。我将第一个reduce修改为打印诊断:

    #!/usr/bin/env perl
    use warnings; use 5.012;
    use open ':encoding(UTF-8)';
    use List::Util qw(reduce);
    use Encode;
    
    my( @list, $longest, $len );
    open my $fh, '<', 'test.txt' or die $!;
        while( my $line = readline( $fh ) ) {
        chomp $line;
        push @list, split( /\s+/, $line );
        }
    close $fh;
    
    $longest = reduce { say "<<$a>>/<<$b>> : ", length($a), " : ", length($b);
                        length($a) > length($b) ? $a : $b } @list;
    $len = length $longest;
    say $longest; # aaaaaa
    say $len;     # 6
    
    $longest = reduce { length(Encode::encode_utf8($a)) > length(Encode::encode_utf8($b)) ? $a : $b } @list;
    $len = length(Encode::encode_utf8($longest));
    say $longest;  # bbbbbbbbbbbbbbb
    say $len;     # 15
    
    $longest = $list[0];
    $len = length $longest;
    for my $str (@list) {
        if ( length($str) > $len ) {
            $longest = $str;
            $len = length($str);
        }
    }
    say $longest; # bbbbbbbbbbbbbbb
    say $len;     # 15
    

    当使用Perl5.13.4在MacOSX(10.6.5)上运行时,我得到的输出是:

    <<>>/<<__BE>> : 0 : 4
    <<__BE>>/<<>> : 0 : 0
    <<>>/<<bb>> : 0 : 2
    <<bb>>/<<bbbbbbbbbbbbbbb>> : 0 : 15
    <<bbbbbbbbbbbbbbb>>/<<>> : 0 : 0
    <<>>/<<aaaaaa>> : 0 : 6
    aaaaaa
    6
    bbbbbbbbbbbbbbb
    15
    bbbbbbbbbbbbbbb
    15
    

    从表面上看,第一个reduce的第一个参数始终是一个零长度的字符串,即使在它包含某些数据的奇数情况下也是如此。

    如果 use open ':encoding(UTF-8)'; “线被移除了,它的行为就正常了。

    <<>>/<<__BE>> : 0 : 4
    <<__BE>>/<<>> : 4 : 0
    <<__BE>>/<<bb>> : 4 : 2
    <<__BE>>/<<bbbbbbbbbbbbbbb>> : 4 : 15
    <<bbbbbbbbbbbbbbb>>/<<>> : 15 : 0
    <<bbbbbbbbbbbbbbb>>/<<aaaaaa>> : 15 : 6
    bbbbbbbbbbbbbbb
    15
    bbbbbbbbbbbbbbb
    15
    bbbbbbbbbbbbbbb
    15
    

    这可能意味着这个bug出现在文件I/O、UTF-8编码和List::Util的交互中。另一方面,它可能是更隐晦的地方。但我的印象是,您有一个可复制的测试用例,可能在Perl及其核心模块中的某个地方被报告为一个可能的错误。

        2
  •  1
  •   Alexandr Ciornii    14 年前

    我已经报告过了 as bug in List::Util 尝试修改此程序后。