Christian & list-
The code you posted is hard to understand because it¹s doing a lot in a
single line! This is not good code to be starting out with if you¹re just
learning Perl. Let¹s start by adding back the optional parentheses to see
how the code is being interpreted.
printf ("%s\n",pack ("H2" x scalar(split (/\./, $ARGV[0])), split (/\./,
$ARGV[0])));
Now we can see which arguments go to which functions. Even so, it can be
hard to see what¹s going on, so let¹s break this into multiple lines, using
variable names, to follow what¹s happening.
my $string = $ARGV[0];
my @chars = split /\./, $string;
my $count = scalar @chars;
printf "%s\n", pack ("H2" x $count, @chars);
$ARGV[0] is the script¹s first command line argument in this case the
string you want to convert, so let¹s just put it into a variable. split is
used to take a string and break it into an array, based on some sort of
delimiter. In this code it takes two arguments (it can take more or fewer):
the pattern we want to split on and the thing we want to split. You can do
really fancy things with split by passing a regular expression as a
delimiter, but here your pattern is a literal period. Since $string contains
a number of one or two character hex codes, separated by periods, split
/\./, $string will return an array of just the hex codes. For example
³21.A.21.20² becomes [21¹, A¹, 21¹, 20¹]. Thus, @chars is the array of
these hex codes.
Skipping ahead to the pack statement, pack expects its first argument to be
a string describing how to pack the rest of its arguments. In this case ³H2²
means to take the argument and interpret it as a hex code for a character
(its ASCII value). However, if we were to just put a single ³H2² here, pack
would only interpret the first element of @chars, and silently discard the
rest. What we need is an ³H2² for every element of the array, which is why
we need the count. Casting an array as a scalar is the Perlish way of
getting the number of elements in the array. With the count we use the x
operator, which repeats a string a given number of times. Here we use it to
create a string containing one ³H2² for every element of @chars.
printf is used to print items in a particular format. Typically this is used
for printing numbers to a certain number of decimal places, or with zero
padding, things like that. Here it¹s being used to print the results of the
pack with a newline after them. Normally this would just be written as:
print pack ("H2" x $count, @chars), ³\n²;
However, if we try to do this with the original code:
print pack "H2" x scalar split /\./, $ARGV[0], split /\./, $ARGV[0], "\n";
we end up with a parse error:
Argument "\n" isn't numeric in split at ./test.pl line 3.
This is because, without the parentheses the original author was obviously
trying to avoid, the ³\n² is treated as an argument to the second split, not
as an argument to the print statement.
Whew! Now that we can see what¹s going on, we can get to fixing it. The
problem lies in the pack statement, since this is what takes the hex codes
and generates characters. Obviously it¹s ignoring the ³A²s. It¹s doing this
because the pack pattern - ³H2² - specifies that it should expect a two byte
string to pack, but it¹s only getting one. The simplest way to fix this is
to zero pad the hex codes before pack ever sees them. As always in Perl,
there¹s more than one way to do it. We could do some fanciness with map, but
for readability, let¹s just use an explicit loop.
foreach my $hex (@chars) {
if (length($hex) == 1) {
$hex = '0'.$hex;
}
}
This goes through each element of the array. If the element is only one
character long, add a zero to the front of the character. The nice thing
about foreach is that modifications to the element your working on (in this
case $hex) are automagically copied back into the array.
Currently, our script looks like this:
my $string = $ARGV[0];
my @chars = split /\./, $string;
foreach my $hex (@chars) {
if (length($hex) == 1) {
$hex = '0'.$hex;
}
}
my $count = scalar @chars;
print pack ("H2" x $count, @chars), ³\n²;
There¹s one last thing we can do to improve readability. Since we¹re already
iterating over @chars, there¹s no need to pack the entire array at once. We
can build the output string as we iterate instead.
my $string = $ARGV[0];
my @chars = split /\./, $string;
my $result = '';
foreach my $hex (@chars) {
if (length($hex) == 1) {
$hex = '0'.$hex;
}
$result .= pack ("H2", $hex);
}
print "$result\n";
Now we append each character one at a time to the $result, and print it at
the end.
Besides fixing a bug, we¹ve improved readability without impacting
performance much. The original script ran your test string in 0.62 seconds,
and the code above does it in 0.91 seconds. We¹re not doing much more work
than the original one-liner, and in scripts this size the bulk of the
execution time is going to be starting the Perl interpreter, not in
executing our code.
As an aside, the reason your translation (tr) didn¹t work is that it does a
one-to-one translation. In your case it was replacing ³.² with ³\n² and ³A²
with nothing. A substitution (s) could probably be made to work there, but
it would only fix the ³A²s and not any other single digit hex codes.
HTH,
Jim
BTW If someone can contact me off list about getting this up on the Wiki
(at least the corrected script), I¹m more than happy to do so.
--
JIM PFLEGER | Application Architect | Insight Networking | insight.com
o. 480.889.9680 f. 480.889.9599 [email protected]
The information contained in this message and any attachment may contain
privileged or confidential information protected from disclosure. If you are
not the intended recipient, or an employee or agent responsible for
delivering this message to the intended recipient, you are hereby notified
that any review, dissemination, distribution or copying of this information
is strictly prohibited. If you have received this transmission in error,
please notify the sender immediately by replying to this message and
destroying the original and all copies. Thank you.
On 9/15/09 6:16 AM, "Christian Fieres" <[email protected]> wrote:
>
> Hi all,
>
> probably an easy one, but as a totally newbie to e.g. Perl or C, I do not
> really understand what the simple octetstring 2 ascii perl script someone gave
> me a few years ago that is intended to convert an octet string to an ascii
> text does:
>
> printf "%s\n",pack "H2" x scalar(split /\./, $ARGV[0]), split /\./,
> $ARGV[0];
>
> What it does is clear - but not how it does it. So I am not able to convert
> such things as whole NCM configuration files given as an attribute's value in
> octet string format. (I'm on Solaris.) It contains ASCII #10 characters which
> are obviously ignored by the perl line above, so what I get is a
> one-line-string with concatenated lines.
>
> I'm sure the solution is clear, but I simply can't grab it. What I also did
> was try to replace all ".A." in my one line octet string by a newline, but
> didn't succeed with awk and sed, and my tr knowledge is rather non-existant,
> so a simple
>
> tr ".A." "\n"
>
> to have single lines to feed my perl script with doesn't do the job either.
>
> Whoever knows what I mean: please enlighten me! :) Thanks a lot.
>
> Freundliche Grüße / Best regards
>
> Christian Fieres
>
> Mainova AG
> Planung und Betrieb Infrastruktur (M3-ON2)
> Service Operation Center
> Solmsstraße 38
> 60623 Frankfurt
>
> Telefon / Phone (069) 2 13-2 36 17
> Mobil / Mobile (0170) 5 60 15 63
> Telefax / Facsimile (069) 2 13-9 62 36 17
> E-Mail [email protected]
>
>
> Mainova Aktiengesellschaft - Solmsstraße 38 - D-60623 Frankfurt am Main
> Vorsitzende des Aufsichtsrates: Oberbürgermeisterin Dr. h. c. Petra Roth -
> Vorstand: Dr. Constantin H. Alsheimer (Vorsitzender), Lothar Herbst, Joachim
> Zientek
> Sitz der Aktiengesellschaft: Frankfurt am Main - Amtsgericht Frankfurt HRB
> 7173 - USt-ID-Nr. DE 114184034
>
>
> Müssen Sie diese E-Mail wirklich ausdrucken? - fragt der Mainova Energiecoach.
> Mehr Tipps und Antworten zum Thema Energieeffizienz unter
> http://www.mainova-energiecoach.de
> * --To unsubscribe from spectrum, send email to [email protected] with the
> body: unsubscribe spectrum [email protected]
>
---
To unsubscribe from spectrum, send email to [email protected] with the body:
unsubscribe spectrum [email protected]