Perl中,能不能把一个长字符串转化为一个更短的字符串或是数字呢?

时间:2022-06-01 19:58:22
假设我有一系列由32个字符组成的字符串,如"67AE83F79341E0C878686899F645C123",如何能把字符串转化为更短的字符串或是数字,且每一个长字符串对应的更短的字符串是唯一的?
有没有现成的函数来解决这个问题呢?

问题背景:
长字符串是我的一个脚本的输出,因为太多,所以很吃内存,因此想找到一种压缩的方法,缓解内存压力。还请大家赐教,谢谢~~~~

13 个解决方案

#1


脚本的“输出”为什么会占内存?

#2


如果不用反编可以用16位的md5,这样可以减少一半

#3


我晕……

#4


输出存在内存中,作为下一个程序的输入

#5


如果你的字符串都是符合:0~9,A~F这样的规则,例如你的例子中的67AE83F79341E0C878686899F645C123,那么可以减半。
你需要做的是将2个字符计算成一个字符,也就是6变为0110,7变为0111最后构成01100111存成一个字符,这样你的字符串就会减半,同时,转换可逆并且唯一。

#6


谢谢fibery。请问,是否有相关的函数做这种转换呢?

#7


这个字符串中都是由"0-9""A-F"构成的,若按照fibery的方法:
"67AE83F79341E0C878686899F645C123,你需要做的是将2个字符计算成一个字符,也就是6变为0110,7变为0111最后构成01100111存成一个字符,这样你的字符串就会减半,同时,转换可逆并且唯一。"

我有下列的问题
1. 怎样把67转化为"01100111"呢?
2. 转化为"01100111"后,应该存成什么样的字符呢?方法是什么呢?

不大懂这种位数转换的问题,还请大家指教了

#8


按16进值压缩的话:
my $x = '67AE83F79341E0C878686899F645C123';

my $b = pack("h*", $x); # encode

print length($b), "\n"; # length of $b should be 16 (half of 32)

my $x2 = uc(unpack("h*", $b)); # decode

print $x2, "\n"; # $x2 should be $x now.


但说心里话,压缩不是正经途径。正经途径是改善内存管理方式,而不是压缩内存使用。

#9


个人觉得如果不介意速度的话,用文本文件作为中介也可以的。就是把输出存为文本文件,再传给下一个程序作为输入,然后就可以按行处理,减少内存的占用量。

#10


谢谢iambic,我试一下~

#11


采用了iambic建议的方式后,在下游处理时产生了问题,我输出的数据行的格式如下:$key\t$id_count\t@value
其中@value里面是pack后的集合,$key和$value没有做pack操作。测试时,将这类记录存在一个文件里,假设为log。当我用下游脚本处理log时,出现了很奇怪的问题,
1. 打出来的$key和$id_count里面有乱码
146
9
?皣-'7Ls\!

2. 打出来的字符串不全是原来的32个字符的串了。而是如下的格式
16F8566DBD6130B4
B4557367F6E817CDF0E58F059207A1E7
4C04E335CE1E6104DD63194180306BBA
630333
63

请问这是为什么呢?

下游的脚本代码如下:

while(<>){
#$tmp=uc(unpack("h*", $_));
my @tmp = split /\s+/,$_;
$mid = $tmp[0];
$count = $tmp[1];
print $mid;
print $count;
shift @tmp;
shift @tmp;
foreach $t(@tmp)
{
$tmp=uc(unpack("h*", $t));
print $tmp;
}
}

#12


唉,这样处理是不行的。
压缩过后的数据里面可能存在\t\r\n之类的字节,所以你在while (<>)的时候就可能中途断行了。
看起来,基于文本流的逻辑,最好的办法还是不压缩……

#13


我们在程序开发中遇到的问题,我一般分为两类:
1、技术问题
2、设计问题
技术问题就是具体的技术和使用方法问题,设计问题指软件的结构、解决问题的方法,即思维方面的问题。

对于你的这个帖子呢,本来属于技术问题,即,你想把字符串压缩,基本实现;
导致了其他问题的产生,即,压缩后解压还原问题。本来在内存中存储压缩后的数据,解压是没有问题的,但是保存到文件中就有了问题。
问题的产生,实际上,产生在如何对压缩后的数据的解释。一般的压缩程序,对于压缩后的数据都是看作二进制数据来处理的,比如:WinRar、Winzip等。
对于你的程序,压缩后的数据同样是二进制数据,因为,压缩后的数据,会包含0~255的字符中的任何一个控制字符。所以,对于保存压缩后的数据,应该以二进制方式保存,读取时以二进制读取,每次读取16个字节,或更大的16的倍数字节,甚至一次读取整个文件,然后再每16个字节作为一个数据处理单元。这就是你的设计问题。

我再来分析一下你的问题,如果因为占用内存而压缩数据,那么,你是否担心占用磁盘空间而压缩要写入磁盘的数据?
这完全是两个问题。如果不担心占用磁盘,我们完全可以在写入磁盘的时候将数据解压缩,保存成可打印ASCII,避免控制字符一文本方式保存到文本文件,如果遇到退格控制字符,你的数据还会变少呢!

解决问题的办法很多,要压缩数据无可厚非,但一定要正确处理压缩的数据。

#1


脚本的“输出”为什么会占内存?

#2


如果不用反编可以用16位的md5,这样可以减少一半

#3


我晕……

#4


输出存在内存中,作为下一个程序的输入

#5


如果你的字符串都是符合:0~9,A~F这样的规则,例如你的例子中的67AE83F79341E0C878686899F645C123,那么可以减半。
你需要做的是将2个字符计算成一个字符,也就是6变为0110,7变为0111最后构成01100111存成一个字符,这样你的字符串就会减半,同时,转换可逆并且唯一。

#6


谢谢fibery。请问,是否有相关的函数做这种转换呢?

#7


这个字符串中都是由"0-9""A-F"构成的,若按照fibery的方法:
"67AE83F79341E0C878686899F645C123,你需要做的是将2个字符计算成一个字符,也就是6变为0110,7变为0111最后构成01100111存成一个字符,这样你的字符串就会减半,同时,转换可逆并且唯一。"

我有下列的问题
1. 怎样把67转化为"01100111"呢?
2. 转化为"01100111"后,应该存成什么样的字符呢?方法是什么呢?

不大懂这种位数转换的问题,还请大家指教了

#8


按16进值压缩的话:
my $x = '67AE83F79341E0C878686899F645C123';

my $b = pack("h*", $x); # encode

print length($b), "\n"; # length of $b should be 16 (half of 32)

my $x2 = uc(unpack("h*", $b)); # decode

print $x2, "\n"; # $x2 should be $x now.


但说心里话,压缩不是正经途径。正经途径是改善内存管理方式,而不是压缩内存使用。

#9


个人觉得如果不介意速度的话,用文本文件作为中介也可以的。就是把输出存为文本文件,再传给下一个程序作为输入,然后就可以按行处理,减少内存的占用量。

#10


谢谢iambic,我试一下~

#11


采用了iambic建议的方式后,在下游处理时产生了问题,我输出的数据行的格式如下:$key\t$id_count\t@value
其中@value里面是pack后的集合,$key和$value没有做pack操作。测试时,将这类记录存在一个文件里,假设为log。当我用下游脚本处理log时,出现了很奇怪的问题,
1. 打出来的$key和$id_count里面有乱码
146
9
?皣-'7Ls\!

2. 打出来的字符串不全是原来的32个字符的串了。而是如下的格式
16F8566DBD6130B4
B4557367F6E817CDF0E58F059207A1E7
4C04E335CE1E6104DD63194180306BBA
630333
63

请问这是为什么呢?

下游的脚本代码如下:

while(<>){
#$tmp=uc(unpack("h*", $_));
my @tmp = split /\s+/,$_;
$mid = $tmp[0];
$count = $tmp[1];
print $mid;
print $count;
shift @tmp;
shift @tmp;
foreach $t(@tmp)
{
$tmp=uc(unpack("h*", $t));
print $tmp;
}
}

#12


唉,这样处理是不行的。
压缩过后的数据里面可能存在\t\r\n之类的字节,所以你在while (<>)的时候就可能中途断行了。
看起来,基于文本流的逻辑,最好的办法还是不压缩……

#13


我们在程序开发中遇到的问题,我一般分为两类:
1、技术问题
2、设计问题
技术问题就是具体的技术和使用方法问题,设计问题指软件的结构、解决问题的方法,即思维方面的问题。

对于你的这个帖子呢,本来属于技术问题,即,你想把字符串压缩,基本实现;
导致了其他问题的产生,即,压缩后解压还原问题。本来在内存中存储压缩后的数据,解压是没有问题的,但是保存到文件中就有了问题。
问题的产生,实际上,产生在如何对压缩后的数据的解释。一般的压缩程序,对于压缩后的数据都是看作二进制数据来处理的,比如:WinRar、Winzip等。
对于你的程序,压缩后的数据同样是二进制数据,因为,压缩后的数据,会包含0~255的字符中的任何一个控制字符。所以,对于保存压缩后的数据,应该以二进制方式保存,读取时以二进制读取,每次读取16个字节,或更大的16的倍数字节,甚至一次读取整个文件,然后再每16个字节作为一个数据处理单元。这就是你的设计问题。

我再来分析一下你的问题,如果因为占用内存而压缩数据,那么,你是否担心占用磁盘空间而压缩要写入磁盘的数据?
这完全是两个问题。如果不担心占用磁盘,我们完全可以在写入磁盘的时候将数据解压缩,保存成可打印ASCII,避免控制字符一文本方式保存到文本文件,如果遇到退格控制字符,你的数据还会变少呢!

解决问题的办法很多,要压缩数据无可厚非,但一定要正确处理压缩的数据。