Ria Ria - 2 months ago 5
Perl Question

how to find the lengh of the input in an array and match pattern in perl

i am new to to the perl scripting
i have an array like this
my @array (0x0B,0x04,0x02767,0x0000,0xffffaf)
my expected output:
if the length of the index is more than 4(i have assumed 0x0B=4) then do
the split and join the string like this
0x2767-->0x27,0x67
0xffffaf->0xff,0xff,0xaf

here i am trying to find out the length of the input string and matching
pattern if the length of the input string is more than 2 and match the
pattern then it should be satisfy the if condition

my $input = "0x0B";
# Name of the file the data is in
my $input_filename = 'my_input_original.txt';


# Name of the file you want to dump the output to
my $output_filename = 'my_org_output.txt';

# Open the file
open my $input_fh, "<", $input_filename or die $!;

# Open the output file
open my $output_fh, ">", $output_filename or die $!; to
my $output_filename = 'my_org_output.txt'
my updated code what i want to do

here is what i want to do
my input data:
total_sum 0x0B Uint8,unsigned char
num 0x0C Uint8,unsigned char
max 0x4A Uint8,unsigned char
padd 0x00 Uint8,unsigned char
ideal 0x01 Uint16, unsigned short
newtext{2} { 0x00, 0x00 } Uint8,unsigned char
my_new 0x02 Uint16, unsigned short
newtest2{2} { 0x00, 0x00 } Uint8,unsigned char
xyz 0x0A Uint8,unsigned char
newtest4{3} { 0x00, 0x00, 0x00 } Uint8,unsigned char
gtotal 0xffffffaf Sint8,signed char
info 0x2767 Uint16, unsigned short
my_output:

0x0B,0x0C,0x4A,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,
0x00,0x00,0x0A,0x00,0x00,0x00

1.if the line contain Uint16 then pad with 0x00 with the value

2.if the line contain the value with 0x2767 split and join
with(e.g.0x2767->0x27,0x67) or
0xffffaf (0xffffaf->0xff,0xff,0xaf)
my code :
#here is extracting only hex value
while ($_ =~ m/(0x(\d+)(?:[0-9]|[A-f])+)/gi)
{
push @hex_array, $1; # here i get only hex value of for my input data
#here if the array contain index value more than two then i need to
#split the data and join also if the line contain Uint16 then i need to
#padd with 0x00 before the value (for e.g. 0x04-->0x00,0x04)
foreach my $element (@hex_array)
{
my @parts;
if (4 < length $element)
{
pos $element = 2; # skip 0x
@hex_array = map "0x$_", $element =~ /../g;
} else
{
@hex_array = $element;
}
}
}
# Write the data to the file
print {$output_fh} join("U, ", @hex_array);
please help me

Answer

Sounds like you have a bunch of 32-bit values as hex, and that you want to pack them into the specified big-endian type, and that you want a hex representation of the packed structure.

(Note that this assumes you are wrong about the output for gtotal. If I understand correctly, 0xffffffaf means -81, which is 0xAF as a Sint8.)

use strict;
use warnings;
use feature qw( say );

my %packers = (
   Uint8  => sub { pack 'C*',  @_ },
   Sint8  => sub { pack 'c*',  @_ },
   Uint16 => sub { pack 'S>*', @_ },
   Sint16 => sub { pack 's>*', @_ },
   Uint32 => sub { pack 'L>*', @_ },
   Sint32 => sub { pack 'l>*', @_ },
);

my $packed = '';

while (<DATA>) {
   my ($vals, $type);
   if (/^\S+ \s+ \{ \s* ( 0x[0-9a-fA-F]+ (?: \s* , \s* 0x[0-9a-fA-F]+ )* ) \s* \} \s+ ([^\s,]+) /x) {
      $vals = $1;
      $type = $2;
   }
   elsif (/^\S+ \s+ ( 0x[0-9a-fA-F]+ )\s+ ([^\s,]+) /x) {
      $vals = $1;
      $type = $2;
   }
   else {
      die("Unrecognized syntax at line $.\n");
   }

   my @vals =
       map { unpack 'l', pack 'l', hex $_ }  # Convert to number and fix the sign
          split /\s*,\s*/,
             $vals;

   my $packer = $packers{$type}
      or die("Unsupported type \"$type\"\n");

   $packed .= $packer->(@vals);
}

# say sprintf '%v02X', $packed;

say
   join ',',
      map { sprintf("0x%02X", $_) }
         unpack 'C*',
            $packed;

__DATA__
total_sum   0x0B    Uint8,unsigned char
num     0x0C    Uint8,unsigned char
max     0x4A    Uint8,unsigned char
padd    0x00     Uint8,unsigned char
ideal   0x01    Uint16, unsigned short
newtext{2}  { 0x00, 0x00 }  Uint8,unsigned char
my_new  0x02     Uint16, unsigned short
newtest2{2} { 0x00, 0x00 }  Uint8,unsigned char
xyz         0x0A     Uint8,unsigned char
newtest4{3} { 0x00, 0x00, 0x00 }    Uint8,unsigned char
gtotal 0xffffffaf   Sint8,signed char
info    0x2767  Uint16, unsigned short

Output:

0x0B,0x0C,0x4A,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x0A,0x00,0x00,0x00,0xAF,0x27,0x67
Comments