将包转换为 perl6

Posted

技术标签:

【中文标题】将包转换为 perl6【英文标题】:Converting pack to perl6 【发布时间】:2018-11-18 20:26:20 【问题描述】:

我想将以下内容从 perl5 转换为 perl6,

$salt = pack "C*", map int rand 256 1..16;

它创建一个由 16 个字符组成的字符串,其中每个字符都有一个从 0 到 255 的随机值。Perl5 不会为这些字符分配任何语义,因此它们可以是字节、Unicode 代码点或其他东西。

我觉得我能过得去

$salt = (map (^256).pick.chr,^16).join;

但我一直坚持使用 pack,这是我的尝试,

use experimental :pack;

my $salt = pack("C*",(map (^256).pick , ^16)).decode('utf-8');

say $salt;
say $salt.WHAT;

结果可能是错误,

Malformed termination of UTF-8 string  
      in block <unit> at test.p6 line 3

或者类似的,

  j
  (Str)

我的想法是打包整数 List 将返回一个 Buf 然后解码应该产生所需的 Str

更新:

正如评论和回答中所建议的那样,Buf 是要使用的正确对象。现在跟进pack 部分,

perl6 -e 'use experimental :pack; my $salt = pack("C*",(map (^256).pick , ^16));say $salt;say $salt.WHAT;'

缓冲区:0x (BUF)

只包装一个单位

另一方面,使用 P5pack(由 Scimon 建议)返回错误

perl6 -e 'use P5pack; my $salt = pack("C*",(map (^256).pick , ^16));say $salt;say $salt.WHAT;'
Cannot convert string to number: base-10 number must begin with valid digits or '.' in '⏏*' (indicated by ⏏)
  in sub one at /home/david/.rakudobrew/moar-master/install/share/perl6/site/sources/D326BD5B05A67DBE51C279B9B9D9B448C6CDC401 (P5pack) line 166
  in sub pack at /home/david/.rakudobrew/moar-master/install/share/perl6/site/sources/D326BD5B05A67DBE51C279B9B9D9B448C6CDC401 (P5pack) line 210
  in block <unit> at -e line 1

更新 2:

我没有发现差异。

perl6 -e 'say (map (^256).pick, ^16).WHAT;'
(Seq)
perl6 -e 'say Buf.new((^256).roll(16)).WHAT;'  
(Buf)

现在列出它们,

perl6 -e 'use experimental :pack; my $salt = pack("C*",(Buf.new((^256).roll(16)).list));say $salt;say $salt.WHAT;'
    Buf:0x<39>
    (Buf)

perl6 -e 'use P5pack; my $salt = pack("C*",Buf.new((^256).roll(16)).list);say $salt;say $salt.WHAT;'
    Cannot convert string to number: base-10 number must begin with valid digits or '.' in '⏏*' (indicated by ⏏)
      in sub one at /home/david/.rakudobrew/moar-master/install/share/perl6/site/sources/D326BD5B05A67DBE51C279B9B9D9B448C6CDC401 (P5pack) line 166
      in sub pack at /home/david/.rakudobrew/moar-master/install/share/perl6/site/sources/D326BD5B05A67DBE51C279B9B9D9B448C6CDC401 (P5pack) line 210
      in block <unit> at -e line 1

参考:

Buffers and Binary IO

A first approach to pack/unpack in Perl 6

提前感谢您的帮助。

【问题讨论】:

你到底想做什么?如果您想从前 256 个 Unicode 代码点中随机选择,请使用 decode('iso-8859-1')。不过,这是一件奇怪的事情。是什么让您认为它不应该是 Buf?如果您尝试生成(不安全的)加密密钥,那么您正在生成任意字节,Buf 将是合适的类型。 @ikegami,感谢您的评论。 >> 你到底想做什么? - 我在 Rosetta Code 的一项任务中看到 P5 行,并想将其翻译为 P6 作为学习过程。 一个注释 ^256.roll(16) 应该给你 16 个随机数而不需要地图。等我起来了,我再看看。 @Scimon 谢谢,你说得对,请看我的更新2。 【参考方案1】:

正如 ikegami 在对您的问题的评论中所说,您确实应该使用 Buf,它基本上是一个字节“字符串”。

my $salt = Buf.new((^256).roll(16));

您可以将其写入文件,例如:

spurt 'foo', $salt, :bin;

或使用 base-64 编码:

use MIME::Base64;
my $encoded = MIME::Base64.encode($salt);

但是,如果您需要这个相当安全,请查看Crypt::Random

use Crypt::Random;
my $salt = crypt_random_buf(16);

【讨论】:

【参考方案2】:

最简单的方法可能是使用https://modules.perl6.org/dist/P5pack:cpan:ELIZABETH,它允许您使用 Perl5 包语法。

【讨论】:

感谢您的建议,请参阅我的更新。也许我用错了?【参考方案3】:

显然"C" x 16 有效,但"C*" 无效。别问,我也不知道为什么。 :-D

perl6 -e 'use experimental :pack; my $salt = pack("C" x 16,(Buf.new((^256).roll(16)).list));say $salt;say $salt.WHAT;'
Buf:0x<64 71 D4 E6 E6 AD 7B 1C DD A2 62 CC DD DA F3 08>
(Buf)

另一方面,解包确实有效。

perl6 -e 'use experimental :pack; my $salt = pack("C" x 16,(Buf.new((^256).roll(16)).list)).unpack("C*");say $salt;say $salt.WHAT;'
(35 101 155 237 153 126 109 193 94 105 70 111 59 51 131 233)
(List)

总而言之,mscha 的答案是 P6'ish 和整洁。这是一次愚蠢的往返packBuf 列表以获得Buf

至于其他包转换,注意here中的两个关键点,

Here is the difference between Perl 5 and Perl 6 pack/unpack:

Perl 5                      Perl 6

pack(List)  --> Str         pack(List)  --> Buf
unpack(Str) --> List        unpack(Buf) --> List

一些 Perl 5 模板规则假定 Buf 和 Str 之间有一条简单的双向街道。在 Perl 5 中,Buf 和 Str 之间根本没有真正的区别,而 Perl 5 相当多地使用了这一点。

编辑:修正错字,s/masha/mscha/;

【讨论】:

s/mascha/mscha/ 抱歉,错字已修正。

以上是关于将包转换为 perl6的主要内容,如果未能解决你的问题,请参考以下文章

Perl6 中的类型强制

2包和文件夹的转换

[ Perl 6 ] 字符串基础操作

perl6 单线程破解phpmyadmin脚本

Perl 之父同意 Perl 6 改名为 Raku

Perl6多线程1: new / run