首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用perl的pack函数重新排序字段

如何使用perl的pack函数重新排序字段
EN

Stack Overflow用户
提问于 2016-06-28 23:07:52
回答 2查看 148关注 0票数 1

在使用pack构建字符串时,我试图重新排序字段,但我似乎无法让pack做我想做的事情。例如,我想在偏移量12处填充一个字符串,在偏移量12处填充abc,在偏移量8处填充defg,在偏移量3处填充hi (以及任何可能是空格或\0的偏移量0-2和5-7)。

代码语言:javascript
运行
复制
perl -e '
   use strict; use warnings;
   my $str = "...hi...defgabc";
   my $fmt = q{@12 a3 @8 a4 @3 a2};

   my @a = unpack $fmt, $str;
   print "<$_>\n" for @a;
   print "\n";

   print unpack("H*", pack($fmt, @a)), "\n";
'

这对于字符串以外的任何顺序的unpacking字段来说都很好。但是对于packing,它将\0-fills和截断为记录在案。有没有任何方法阻止它从\0-filling和截断而不重新排序pack模板,以产生从左到右的字段?

从外部源读取字段规范时会出现这个问题。当然,可以将pack模板按从左到右的顺序排列,由此产生的列表可以重新排序以符合外部字段规范。但是,在不填充中间位置或截断位置的情况下,动态地重新定位pack“游标”是非常方便的。

在上面的代码中,如果pack(...)的返回值与用于.的任何字节(例如.\0)的返回值相同,我会很高兴。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-06-29 13:55:38

显然,pack没有办法直接做到这一点。这里有一种方法可以避免循环和使用substr。然而,与unpack的易懂性相比,它并不是很令人满意。我希望我误解了pack文档中的一些内容,即允许packunpack相反,用于在packed字符串中放置字段。

代码语言:javascript
运行
复制
use strict; use warnings;
my $str = "...hi...defgabc";
my @pos = (
   { pos => 12, len => 3 }, 
   { pos =>  8, len => 4 }, 
   { pos =>  3, len => 2 }, 
);
my $fmt = join " ", map { "\@$_->{pos} a$_->{len}" } @pos;
# q{@12 a3 @8 a4 @3 a2};

my @a = unpack $fmt, $str;
print "<$_>\n" for @a;
print "\n";

my @sorted_idxes =
   sort { $pos[$a]{pos} <=> $pos[$b]{pos}
       or $pos[$a]{len} <=> $pos[$b]{len} }
   0..$#pos;

my $sorted_fmt = join " ", 
   map { "\@$pos[$_]->{pos} a$pos[$_]->{len}" } @sorted_idxes;

my $out = pack $sorted_fmt, @a[@sorted_idxes];
$out =~ s/\0/./g;
print "$out\n";
票数 1
EN

Stack Overflow用户

发布于 2016-06-29 06:27:56

不能让pack写入字符串中的特定位置。它不使用可以重新定位的“游标”在字符串周围移动--但是它只是将给定给它的所有东西连接起来,然后用它编写一个新的字符串。

包装模板,列表 获取一个值列表,并使用模板提供的规则将其转换为字符串。得到的字符串是转换值的级联。..。

在页面的下方,文档还说

您必须自己进行任何调整或填充,例如,在打包时插入足够的"x"es。packunpack无法知道字符的去向或来自何处,因此它们将输出和输入处理为扁平的字符序列。

当然,您可以以任何您想要的方式写出字符串,但是只有通过重新安排模板(如果尝试按顺序排列,它会根据每个@的需要填充,从零到覆盖每个值),以及写出或填充“中间位置”。所以你可以说

代码语言:javascript
运行
复制
my $str = "...hi...defgabc";
my $fmt = q{@12 a3 @8 a4 @3 a2};

my @parts = unpack $fmt, $str;
# Add to @parts and template what need be in between or change $fmt to get all
my $res = pack "A3A4A2", @parts;

然后,您可以提取原始字符串的所有部分,重新排列它们或构建合适的索引掩码,并对其进行pack。我知道你知道这一点,也不想要它,但pack除了写出整个字符串之外,别无他法。

至于编写字符串的部分,这正是底座的工作。因此,也许您可以使用@fmt和/或@parts编写一个小循环,其中substr将在需要的位置替换给定长度的序列。然而,pack-ing --这一切都应该是一次有效得多的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38087689

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档