在Perl字符串中无法用L替换0,用H替换1

时间:2014-06-30 23:48:36

标签: perl replace binary hex substring

我正在努力解决一段简单的代码,无法解决问题。我要做的就是用L代替0,用H代替1代表十六进制数的二进制等价。我需要从用户那里获取十六进制数,将其转换为二进制数,扫描二进制文件的每一位,并用L&1代替0和1代替H' s。简单的要求,但发现很难解决。

use warnings;
use strict;

my $i2c = "80";
my $binary_string = sprintf "%08b", hex($i2c);
print "$binary_string \n";

my $charz = sprintf "%s", $binary_string;
print "$charz\n";

for (my $i=1; $i < @charz; $i++) {
  if (substr($charz, $i) eq "0")
    substr($charz, $i) = "L";
  else if (substr($charz, $i) eq "1")
    substr($charz, $i) = "H";
}

我的输出应该是这样的:

input hex = 80 

因此二进制文件为10000000。 所以我的输出必须是HLLLLLLL

我无法获得这个简单的输出。我尝试了很多东西来使它工作(正则表达式匹配并替换子字符串,索引等)。我不确定我是否在某处犯了一个基本错误。请帮我解决这个问题。

我得到的错误是:

syntax error at temp3.pl line 12, near ")
substr"
Execution of temp3.pl aborted due to compilation errors.

5 个答案:

答案 0 :(得分:4)

只需使用tr

use warnings;
use strict;

my $i2c = "80";

my $binary_string = sprintf "%08b", hex($i2c);
print "$binary_string \n";

$binary_string =~ tr/10/HL/;
print "$binary_string\n";

输出:

10000000
HLLLLLLL

答案 1 :(得分:3)

Perl if语句总是需要{}围绕此操作:

if (substr($charz, $i) eq "0")
{
    substr($charz, $i) = "L";
}
else if (substr($charz, $i) eq "1")
{
    substr($charz, $i) = "H";
}

(你应该看一下封闭的循环索引;数组在Perl中从0开始索引除非你真的喜欢危险地生活。而且,当我们解构代码时,正如TLP评论的那样, $charz通过sprintf撰写$charz = $binary_string;是一种冗长的方式!)

另外,正如hobbs comment指出的那样,substr()运算符需要第三个参数才能按照您的意愿运行:

if (substr($charz, $i, 1) eq "0")
{
    substr($charz, $i, 1) = "L";
}
else if (substr($charz, $i, 1) eq "1")
{
    substr($charz, $i, 1) = "H";
}

或者您可以使用:

substr($charz, $i, 1) = "L" if (substr($charz, $i, 1) eq "0");
substr($charz, $i, 1) = "H" if (substr($charz, $i, 1) eq "1");

或者您可以避免显式循环并使用:

$charz =~ s/1/H/g;
$charz =~ s/0/L/g;

或者您可以使用:

$charz =~ y/01/LH/;

或者您可以将y拼写为tr

$charz =~ tr/01/LH/;

或者你可以在Perl中使用其他所有方法...

在显示的机制中,我使用ytr(可能tr是首选; y适用于顽固的sed程序员;它完成所有这一切:没有大惊小怪,没有麻烦。

答案 2 :(得分:2)

正如已经指出的,使用tr//可能是最好的解决方案。我只是想添加这种按位比较方法,因为你正在使用位,它很有趣:

use strict;
use warnings;

my $bin = shift // 0x80;                 # take arg or default
my $str;
for (my $n = 1; $n <= $bin; $n *= 2) {   # $n -> 1, 2, 4, ...
    $str .= $bin & $n ? 'H' : 'L';       # check bits
}
$str = reverse $str;                     # well...
printf "Org: %b\nNew: $str\n", $bin;

某些测试运行:

$ foo.pl
Org: 10000000
New: HLLLLLLL

$ foo.pl 3
Org: 11
New: HH

$ foo.pl 31
Org: 11111
New: HHHHH

$ foo.pl 33
Org: 100001
New: HLLLLH

答案 3 :(得分:0)

尝试以下正则表达式:

$charz =~ s/0/L/g;
$charz =~ s/1/H/g;

答案 4 :(得分:0)

按照给定的方式运行代码,我收到错误&#39;全局符号&#34; @ charz&#34;需要在字符串第11行显示包名称。

这是真的,因为您正在使用数组@charz(在for循环条件中)而不在任何地方定义它。您在问题中没有提到此错误这一事实让我觉得您没有向我们展示您实际运行的代码。至少,你没有在真实代码中打开use strict

如果我注释掉use strict行,我会收到您提到的语法错误。这是由其他人指出的缺失括号引起的。我们也可以使用elsif代替else if来整理一些事情。

for (my $i=1; $i < @charz; $i++) {
  if (substr($charz, $i) eq "0") {
    substr($charz, $i) = "L";
  } elsif (substr($charz, $i) eq "1") {
    substr($charz, $i) = "H";
  }
}

现在我们遇到代码运行的情况,但没有任何变化。这是因为$i < @charz。该数组为空,因此您的循环不会运行且没有任何变化。

我们可以通过将foreach循环更改为:

来解决这个问题
for (my $i=0; $i < length$charz; $i++) {
  ...
}

但由于其他人提到的substr问题,仍然无效。

所以你真正想写的(我认为)是这样的:

for (my $i=0; $i < length$charz; $i++) {
  if (substr($charz, $i, 1) eq "0") {
    substr($charz, $i, 1) = "L";
  } elsif (substr($charz, $i, 1) eq "1") {
    substr($charz, $i, 1) = "H";
  }
}

这可以按预期工作。但是你在这里做了太多的工作。您应该使用tr///: - )