Hi Jim,

thanks a lot for these perfect explanations and, of course, the bugfix for 
what I was assuming to have an impact (the fact that maybe not only the LF 
is present as a one byte hexcode), but in my case didn't, since there is 
not likely a TAB or anything to be found in a Cisco config file.

But --WOW--, I very much appreciate your immense effort in explaining 
exactly what the one-liner does. I have clearly understood a little more 
about Perl, and without trying, I am able to understand *why* your fixed 
script should work the way it does.

I am sure Christian Schneider will catch up with you in order to publish 
your solution on the Wiki.

Thanks a lot again, you saved me a lot of work!

Freundliche G�����e / Best regards

Christian Fieres

Mainova AG
Planung und Betrieb Infrastruktur (M3-ON2)
Service Operation Center
Solmsstr���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 - Solmsstr���e 38 - D-60623 Frankfurt am Main
Vorsitzende des Aufsichtsrates: Obe��ü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 


���ssen Sie diese E-Mail wirklich ausdrucken? - fragt der Mainova 
Energiecoach. 
Mehr Tipps und Antworten zum Thema Energieeffizienz unter 
http://www.mainova-energiecoach.de



"Pfleger, Jim" <[email protected]> 
15.09.2009 17:31
Bitte antworten an
"Pfleger, Jim" <[email protected]>


An
"spectrum" <[email protected]>
Kopie

Thema
Re: [spectrum] Octet string conversion 






Christian & list-

The code you posted is hard to understand because i����s doing a lot in a 
single line! This is not good code to be starting out with if you���re just 
learning Perl. Le����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 scrip����s first command line argument���� in this case the 
string you want to convert, so le����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.2���� becomes�����2����, �������, ��������,����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 
�����H���� 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 �������� 
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 i����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 �����s ignoring th�����A���s. �����s doing 
this because the pack pattern �����H���� - specifies that it should expect a 
two byte string to pack, but �����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, ther����s more than one way to do it. We could do some 
fanciness with map, but for readability, le����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)�����\����;

The�����s one last thing we can do to improve readability. Since w����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, �����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. �����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) did����t work is that it does 
a one-to-one translation. In your case it was replacing�������� wit�����\���� 
and �����A��� with nothing. A substitution (s) could probably be made to work 
there, 
but it would only fix the��������s and not any other single digit hex codes.

HTH,
Jim


BT����� 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 G�����e / Best regards

Christian Fieres

Mainova AG
Planung und Betrieb Infrastruktur (M3-ON2)
Service Operation Center
Solmsstr���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 - Solmsstr���e 38 - D-60623 Frankfurt am Main
Vorsitzende des Aufsichtsrates: Obe��ü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 


���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] 


---
To unsubscribe from spectrum, send email to [email protected] with the body: 
unsubscribe spectrum [email protected]

Reply via email to