【问题标题】:Can someone translate this badly written Perl code for me?有人可以为我翻译这个写得很糟糕的 Perl 代码吗?
【发布时间】:2012-07-13 10:51:12
【问题描述】:

我需要获得在这一点 Perl 代码中使用的算法,但我对 Perl 一无所知。通常这不是问题,因为我会研究该语言,但是这个正则表达式的东西让我头疼!

有人可以对此进行伪代码吗?我只需要知道发生了什么,这样我就可以用其他东西来实现它,最好是 PHP 甚至 C++,但我会担心那部分。我只需要以某种方式破译这是在做什么:

$a = $ARGV[0];
$a =~ s/[^A-F0-9]+//simg;
@b = reverse split /(\S{2})/,$a;
$c = join "", @b;
$c .= "0000";
$d = hex($c) % 999999929;
print "$d\n";

【问题讨论】:

  • @Sinan,感谢您更改标题。 :) 确实写得不好,我希望至少会被评论,但事情就是这样。
  • 在我看来这不是“写得很糟糕的 Perl 代码”,如果它完成了它应该做的事情,那么它甚至是写得很好的代码。
  • 它写得很糟糕,因为它不是提取十六进制数字,而是通过s///,然后是split,第一个参数并不明显。它没有使用位移操作,而是在末尾连接零。即使s/// 也是愚蠢的。它应该只是s/[[:^xdigit:]]+//g/s/m 选项没有任何意义。

标签: perl


【解决方案1】:

关于它有什么不好写的?它可以使用更好的 var 名称,但我不知道这是否可能(因为中间步骤似乎没有任何可命名的质量),只留下 split 的不当使用。伪代码几乎是一个字一个字的翻译。

$a = $ARGV[0];
$a =~ s/[^A-F0-9]+//simg;
@b = reverse split /(\S{2})/,$a;
$c = join "", @b;
$c .= "0000";
$d = hex($c) % 999999929;
print "$d\n";

应该是

$a = $ARGV[0];                # Get a hex str from cmd line   E3:C9:D4
$a =~ s/[^A-F0-9]+//simg;     # Remove any non-hex digits     E3C9D4
@b = reverse $a =~ /(..)/sg;  # Extract "bytes"; reverse      D4, C9, E3
$c = join "", @b;             # Join them.                    D4C9E3
$c .= "0000";                 # Append two NULs               D4C9E30000
$d = hex($c) % 999999929;     # Convert from hex to number and modulus
print "$d\n";                 # Print the result (in decimal).

稍微清晰一点:

$a = $ARGV[0];
$a =~ s/[^0-9A-Fa-f]+//g;
$a = join '', reverse $a =~ /(..)/sg;
$a .= "0000";
$a = hex($a);
$a %= 999999929;
print "$a\n";

这些 sn-ps 中可能存在错误。在具有 32 位整数的 Perl 上,如果输入的十六进制数字超过四个,hex 将溢出。具有 64 位整数的 Perl 将处理 12 个十六进制数字。


您似乎从here 获取了代码。这意味着将 MAC 地址作为输入,这意味着代码需要 64 位整数或 Math::BigInt 才能工作。由于您想对 64 位值进行取模,因此无法解决。


这是一种只适用于 64 位整数的 Perls 的简洁方法:

my $mac = $ARGV[0];
$mac =~ s/[^0-9A-Fa-f]+//g;
die length($mac) != 12;

# "123456789ABC" => 0xBC9A785634120000
my $hash = unpack('Q<', pack('H*', "0000$mac"));

$hash %= 999999929;
print "$hash\n";

为了可移植性,最好将 Math::BigInt 集成到早期版本中。

【讨论】:

  • 添加了关于可能存在的错误的评论。
  • 添加了关于需求的评论。
  • 哈,所以我不是唯一一个尝试改编这个 Perl 脚本的人!那很好笑。好吧,您在这里有最简洁的帖子[您可能是老师],所以我将您的帖子作为公认的解决方案。真的很有帮助,谢谢。
  • 添加了更简洁的代码,仅适用于 64 位整数的 Perls。
【解决方案2】:

它正在寻找一组连接在一起的十六进制八位字节作为程序的第一个参数,并应用模数。

所以,如果程序被调用为:

$ myprog.pl A0B0

那么$c 中的值将是B0A00000。所以$d的值应该是0x396A6C8E

这是由害怕packunpack 的人编写的一段特别糟糕的代码。

【讨论】:

  • pack 在这里不会太有用(会使代码更长),除非输入具有固定宽度。
  • @ikegami 我的直觉告诉我,代码要求 $ARGV[0] 包含 16 位小端整数。
  • 实际上,它需要一个 MAC 地址,但这也是固定宽度的。看我的回答。
【解决方案3】:
$a = $ARGV[0]; # assign first command line arg to $a
$a =~ s/[^A-F0-9]+//simg; # delete non-hex from $a
@b = reverse split /(\S{2})/,$a; # split $a by 2 non-whitespace (saving them too) to array  @b and reverse it
$c = join "", @b; # join array @b to scalar $c
$c .= "0000"; # append 4 zeros to $c
$d = hex($c) % 999999929; # get modulo
print "$d\n"; # print it

【讨论】:

  • split 调用时,字符串仅包含十六进制数字。因此,split 将字符串拆分为八进制的十六进制表示。
  • @SinanÜnür:做了一些修改,希望现在清楚了,谢谢。
  • 那第二行毕竟不是那么可怕!哈哈...感谢您为此所做的工作。我还在看,以后可能还有问题……
  • 因此,如果我的输入是 ABCDEF,那么拆分后的数组 @b 将包含 (B,A),(D,C),(F,E) ?
  • @armani: 不,在列表上下文中反转反转元素顺序而不是元素本身:ABCDEF -> qw(EF, CD, AB)
【解决方案4】:
$a = $ARGV[0]; #Read in the first argument on the command line
$a =~ s/[^A-F0-9]+//simg; #Substitute non hex numbers with nothing *
@b = reverse split /(\S{2})/,$a; #What is left in $a, split by 2 non-space characters
$c = join "", @b; # put the array b into $c
$c .= "0000"; 
$d = hex($c) % 999999929; #Convert $c to an integer and % with 999999929
print "$d\n";
  • simg = i:不区分大小写; g:全球; m:多行; s:单行;

简而言之,我们剥离第一个十六进制数字,然后颠倒字节顺序(一次 2 个十六进制数字)并对结果进行取模。

【讨论】:

  • 对“simg”的解释——我在网上的任何地方都找不到!我猜这不是“基本”正则表达式
  • 正则表达式删除任何非十六进制字符,而不是您建议的。
猜你喜欢
  • 1970-01-01
  • 2016-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-16
  • 2011-07-17
  • 1970-01-01
相关资源
最近更新 更多