Appending hex value to string - perl

$temp = 'abc'.0x12;
print $temp; # prints abc18
While appending the hex value to string it is getting converted to decimal value and final result is string. what I want is that the ascii value of the hex should get appended to the string.
for e.g. 0x12 in ascii is DC2 (device control 2).

Try using chr:
my $a = 'abc'.chr 0x3e;
print $a;

I think Sly Raskal was on the right track but instead of %x use %c, so:
my $hex = 0x12;
my $ascii = sprintf "%c", $hex;
my $temp = 'abc' . $ascii;
I think this gives the result you were looking for. I got it from http://www.perlmonks.org/?node_id=191039 .

Related

Converting to hexadecimal value in Perl

The following code:
$tmp1 = $_;
print "tmp1 is $tmp1";
$tmp1_hex = hex($tmp1);
print "tmp1_hex is $tmp1_hex\n";
$Lat_tmp1 = ($tmp1_hex >> 8) &0x00ff;
prints:
tmp1 is 0018
tmp1_hex is 24
The text file I'm reading the data from contains the string 0018, but when I convert it to the hex value I shouldn't be receiving 24.
If you want to convert to hex rather than from hex, use sprintf:
my $tmp1_hex = sprintf '%x', $tmp1;
The hex function merely interprets the string as a number in hexadecimal form. Beyond that, it's just a number and its original representation doesn't matter.
When you print a number, Perl uses its internal format (%g) to show it. That's a normal, decimal float.
If you want to output the number as something other than Perl's internal format, use printf and the appropriate specifier:
printf '%x', $number;
You probably want something like:
my $tmp1 = '0018';
print "tmp1 is $tmp1\n";
my $tmp1_hex = hex( $tmp1 );
printf "tmp1_hex is %x\n", $tmp1_hex;
Note that the bitwise operators don't need you to convert the number to any particular base. The number is the same number no matter how you display it.
The function hex() converts from hex to decimal. Try something like this instead
$tmp=$_;
$tmp1_hex=sprintf("%X",$tmp);

hexadecimal bit wise and operation

I am fresher in writing scripts so need some help.
so the issue is in one of my script i am doing a bitwise AND operation but i am getting wrong data.
elaborating on this:
$value have a hex value 0xffffffc0.
And i have done some grepping and i have hex value stored in $pattern.
so i need to do and operation of $value & $pattern but getting wrong data, because whatever the $value i am passing its getting converted into decimal value.
$value = hex '0xffffffc0' ;
print $value;
$pattern = 0x35040 ; ####this value will be from the grepping####
$pattern1 = $pattern & 0xfffffffc;
print "$pattern1\n";
i am seeing O/P: 35008
You can specify hexadecimal numbers like $hex_number = 0xaf56, hex converts a string having hexadecimal text into the equivalent number, i.e. $hex_number == hex 'af56'. Numbers are represented in binary inside a computer and they will behave properly with any bit-wise operation you do on them.
It is only when you print a number that you need to be careful about how you want it formatted. By default numbers are printed in decimal, you can print in hexadecimal using the %x format specifier with printf.

Using Perl to split a float

Why did I lose precision using split?
My goal is to get just the fractional part, all of it.
$a = 123456789.123456789;
#b = split(/\./, $a);
$baseDec = "." . $b[1];
Above gives $baseDec == .123457
But this gives the correct precision:
Is it the right way to do it? CORRECTION: THIS GIVES THIS SAME BAD PRECISION!
I did not properly test the code. Sorry!
$a = 123456789.123456789;
#b = split(/\./, $a);
$baseInt = $b[0];
$baseDec = $a - $baseInt;
Should I be using Math::BigFloat?
Edit: $a should be a string $a = "123456789.123456789"; and then the original code works. Until I figure out how to get my Perl to work with longdouble, I can't test the original question. The answer seems to be that I lost precision because $a is being stored in a double (52 bits ~ 15 decimal digits, as #Ben stated below). print $a gives 123456789.123457.
You can use int:
$a = 123456789.123456789;
$baseDec = $a - int($a);
You lost precision because 123456789.123456789 is a numeric literal which, by default, the Perl compiler stores in a double (52 bits, ~15 decimal digits) $a. Next, when #b = split(/\./, $a); runs, $a is implicitly coerced into a string before it can be split.
If your Perl were compiled to use longdoubles (See: perl -V:uselongdouble and perl -V:doublesize), the numeric literal would have been represented with 80 bits (~21 decimal digits) and string coercion.
IF you're going to treat it as a string, do so all the way through. You wouldn't assign a string without quoting, right?
my $a = "123456789.123456789";
You can get it by using sprintf:
my $a = 123456789.123456789;
my #b = split(/\./, sprintf("%.8f",$a));
my $baseDec = "." . $b[1];
print $baseDec;

How to convert hex to string of hex

I have a problem understanding and using the 'vec' keyword.
I am reading a logpacket in which values are stored in little endian hexadecimal. In my code, I have to unpack the different bytes into scalars using the unpack keyword.
Here's an example of my problem:
my #hexData1 = qw(50 65);
my $data = pack ('C*', #hexData1);
my $x = unpack("H4",$data); # At which point the hexadecimal number became a number
print $x."\n";
#my $foo = sprintf("%x", $foo);
print "$_-> " . vec("\x65\x50", $_, 1) . ", " for (0..15); # This works.
print "\n";
But I want to use the above statement in the way below. I don't want to send a string of hexadecimal in quotes. I want to use the scalar array of hex $x. But it won't work. How do I convert my $x to a hexadecimal string. This is my requirement.
print "$_-> " . vec($x, $_, 1).", " for (0..15); # This doesn't work.
print "\n";
My final objective is to read the third bit from the right of the two byte hexadecimal number.
How do I use the 'vec' command for that?
You are making the mistake of unpacking $data into $x before using it in a call to vec. vec expects a string, so if you supply a number it will be converted to a string before being used. Here's your code
my #hexData1 = qw(50 65);
my $data= pack ('C*', #hexData1);
The C pack format uses each value in the source list as a character code. It is the same as calling chr on each value and concatenating them. Unfortunately your values look like decimal, so you are getting chr(50).chr(65) or "2A". Since your values are little-endian, what you want is chr(0x65).chr(0x50) or "\x65\x50", so you must write
my $data= pack ('(H2)*', reverse #hexData1);
which reverses the list of data (to account for it being little-endian) and packs it as if it was a list of two-digit hex strings (which, fortunately, it is).
Now you have done enough. As I say, vec expects a string so you can write
print join ' ', map vec($data, $_, 1), 0 .. 15;
print "\n";
and it will show you the bits you expect. To extract the the 3rd bit from the right (assuming you mean bit 13, where the last bit is bit 15) you want
print vec $data, 13, 1;
First, get the number the bytes represent.
If you start with "\x50\x65",
my $num = unpack('v', "\x50\x65");
If you start with "5065",
my $num = unpack('v', pack('H*', "5065"));
If you start with "50","65",
my $num = unpack('v', pack('H*', join('', "50","65"));
Then, extract the bit you want.
If you want bit 10,
my $bit = ($num >> 10) & 1;
If you want bit 2,
my $bit = ($num >> 2) & 1;
(I'm listing a few possibilities because it's not clear to me what you want.)

How do I get a checksum from unpack in hexadecimal format?

I've been trying to figure out the unpack function in Perl and can't quite figure out the whole thing.
What I have:
A string and a 16-bit hex checksum
(e.g. "this is my string", "0671")
I need to check that "this is my string" equals the checksum '0671'.
So I know unpack("%16W*", $string) will give me the 16-bit decimal value, but I need the hex representation. I know this is an easy one so please forgive my ignorance.
As you said, unpack("%16W*", $string) gives you an integer. To convert an integer to hex, use sprintf:
my $string = "this is my string";
my $expected = '0671';
my $checksum = sprintf('%04x', unpack("%16W*", $string));
print "match\n" if $checksum eq $expected;
If you want upper-case hex digits, use %X instead of %x (or %04X in this case).
Or, you could go the other way and convert your hex checksum to an integer using hex:
my $string = "this is my string";
my $expected = '0671';
my $checksum = unpack("%16W*", $string);
print "match\n" if $checksum == hex $expected; # now using numeric equality
Try unpack("b*',$string).
See the pack man page for syntax.