使用perl进行LZW减压

时间:2018-01-18 14:57:40

标签: perl compression

我在Perl中找到了LZW压缩/解压缩示例,我想让它适用于从文件压缩/解压缩。

以下是原始代码:

#Compress a string to a list of output symbols.
sub compress {
my $uncompressed = shift;

# Build the dictionary.
my $dict_size = 256;
my %dictionary = map {chr $_ => chr $_} 0..$dict_size-1;

my $w = "";
my @result;
foreach my $c (split '', $uncompressed) {
    my $wc = $w . $c;
    if (exists $dictionary{$wc}) {
        $w = $wc;
    } else {
        push @result, $dictionary{$w};
        # Add wc to the dictionary.
        $dictionary{$wc} = $dict_size;
        $dict_size++;
        $w = $c;
    }
}

# Output the code for w.
if ($w) {
    push @result, $dictionary{$w};
}
return @result;
}

#Decompress a list of output ks to a string.
sub decompress {
my @compressed = @_;

# Build the dictionary.
my $dict_size = 256;
my %dictionary = map {chr $_ => chr $_} 0..$dict_size-1;

my $w = shift @compressed;
my $result = $w;
foreach my $k (@compressed) {
    my $entry;
    if (exists $dictionary{$k}) {
        $entry = $dictionary{$k};
    } elsif ($k == $dict_size) {
        $entry = $w . substr($w,0,1);
    } else {
        die "Bad compressed k: $k";
    }
    $result .= $entry;

    # Add w+entry[0] to the dictionary.
    $dictionary{$dict_size} = $w . substr($entry,0,1);
    $dict_size++;

    $w = $entry;
}
return $result;
 }

# How to use:
my @compressed = compress('TOBEORNOTTOBEORTOBEORNOT');
print "@compressed\n";
my $decompressed = decompress(@compressed);
print "$decompressed\n";

输出:

T O B E O R N O T 256 258 260 265 259 261 263 TOBEORNOTTOBEORTOBEORNOT

这是我的代码:

use strict;
use POSIX;
use Data::Dumper;

print "0 - compress; 1 - decompress:";
my $CD=<STDIN>;
$CD+=0;
if ($CD != 0 && $CD != 1) {print "Wrong symbol"."\n"}

if($CD==0){

print "Type the name of file you want to compress:";
my $file=<STDIN>;


open (DATAIN, "<$file") or die "There is no such a file $file: $!";
binmode (DATAIN);

my $uncompressed = <DATAIN>;


print "\n";
print "File to binary:\n";
print "$uncompressed\n";

# Build the dictionary.
my $dict_size = 256;
my %dictionary = map {chr $_ => chr $_} 0..$dict_size-1;

my $w = "";
my @result;
foreach my $c (split '', $uncompressed) {
    my $wc = $w . $c;
    if (exists $dictionary{$wc}) {
        $w = $wc;
    } else {
        push @result, $dictionary{$w};
        # Add wc to the dictionary.
        $dictionary{$wc} = $dict_size;
        $dict_size++;
        $w = $c;
    }
    }

# Output the code for w.
if ($w) {
    push @result, $dictionary{$w};
}
#print into screen
print "\n";
print "Compressed:\n";
print "@result\n";
#print into file
my $output = "output.txt";
open FILE, '>'.$output;
print FILE "@result";
close FILE;
}

if($CD==1){

print "Type the name of file you want to decompress:";
my $outfile=<STDIN>;


open (DATAIN, "<$outfile") or die "There is no such a file $outfile: $!";
binmode (DATAIN);

my @compressed = <DATAIN>;

# Build the dictionary.
my $dict_size = 256;
my %dictionary = map {chr $_ => chr $_} 0..$dict_size-1;

my $w = shift @compressed;
my $result = $w;
foreach my $k (@compressed) {
    my $entry;
    if (exists $dictionary{$k}) {
        $entry = $dictionary{$k};
    } elsif ($k == $dict_size) {
        $entry = $w . substr($w,0,1);
    } else {
        die "Bad compressed k: $k";
    }
    $result .= $entry;

    # Add w+entry[0] to the dictionary.
    $dictionary{$dict_size} = $w . substr($entry,0,1);
    $dict_size++;

    $w = $entry;
}
print "$result\n";

}

所以,它压缩file.txt - “TOBEORNOTTOBEORTOBEORNOT”很好,但是当我想要解压缩输出文件 - output.txt - “TOBEORNOT 256 258 260 265 259 261 263”它失败了,只是给了我相同的“TOBEORNOT 256 258 260 265 259 261 263“结果。也许你有任何想法我的代码可能有什么问题?

1 个答案:

答案 0 :(得分:0)

您正在将整个文件读入此行中@compressed数组的第一个元素:

my @compressed = <DATAIN>;

但是你的print语句将它全部输出到一行。这意味着在my $w = shift @compressed语句中,整个文本被移动到$w变量中,因此下面的循环永远不会运行。

您需要按空格分割您读入的数据,如下所示:

my $compressed = <DATAIN>; # Data file contains only one line so read into scalar variable
my @compressed = split(/ /, $compressed);