Reputation: 69
I am grappling with just a simple piece of code and unable to troubleshoot my way through. All I am trying to do is substitute 0 with L and 1 with H for the binary equivalent of a hex number. I need to get the hex number from the user, convert it to binary, scan through each bit of the binary and replace 0's with L's and 1's with H's. Simple requirement yet finding it hard to resolve.
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";
}
My output should be like this:
input hex = 80
Therefore binary will be 10000000
.
So my output has to be HLLLLLLL
.
I am not able to get this simple output. I tried a wide range of things to make it work (regex match and replace substring, index etc). I am not sure if I am making a basic error somewhere. Kindly help me out on this one.
The error that I get is this:
syntax error at temp3.pl line 12, near ")
substr"
Execution of temp3.pl aborted due to compilation errors.
Upvotes: 1
Views: 133
Reputation: 69284
Running your code as given, I get the error 'Global symbol "@charz" requires explicit package name at string line 11'.
And that's true, because you're using the array @charz (in your for
loop condition) without defining it anywhere. The fact that you don't mention this error in your question makes me think that you're not showing us the code that you're actually running. At the very least, you don't have use strict
turned on in your real code.
If I comment out the use strict
line, I get the syntax error that you mentioned. That's caused by the missing braces that other people have pointed out. We can also tidy things up a bit by using elsif
in place of 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";
}
}
Now we get to a situation where the code runs, but nothing changes. That's because of that $i < @charz
. The array is empty, so your loop doesn't run and nothing changes.
We can fix that by changing the foreach loop to this:
for (my $i=0; $i < length$charz; $i++) {
...
}
But that still doesn't work because of the substr
issues that others have mentioned.
So what you were actually trying to write (I think) was this:
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";
}
}
This works as expected. But you're doing far too much work here. You should have used tr///
:-)
Upvotes: 0
Reputation: 67890
Using tr//
is probably the best solution, as has been noted. I just wanted to add this bitwise comparison method, since you are using bits, and its fun:
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;
Some test runs:
$ 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
Upvotes: 2
Reputation: 754130
Perl if
statements always require {
and }
around the action:
if (substr($charz, $i) eq "0")
{
substr($charz, $i) = "L";
}
else if (substr($charz, $i) eq "1")
{
substr($charz, $i) = "H";
}
(You should probably look at the enclosing loop indexes too; arrays index from 0 in Perl unless you really like to live dangerously. And, while we're deconstructing the code, as TLP commented, the assignment to $charz
via sprintf
is a long-winded way of writing $charz = $binary_string;
!)
Also, as hobbs points out in a comment, the substr()
operator needs a third argument to work as you want it to:
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";
}
Or you could use:
substr($charz, $i, 1) = "L" if (substr($charz, $i, 1) eq "0");
substr($charz, $i, 1) = "H" if (substr($charz, $i, 1) eq "1");
Or you could avoid the explicit loop and use:
$charz =~ s/1/H/g;
$charz =~ s/0/L/g;
Or you could use:
$charz =~ y/01/LH/;
Or you could spell y
as tr
:
$charz =~ tr/01/LH/;
Or all the other ways you can do it in Perl...
Of the mechanisms shown, I'd use y
or tr
(probably tr
is preferred; y
is for die-hard sed
programmers); it does it all in one line: no fuss, no muss.
Upvotes: 3