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]
