Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:
Hey Monks,
Im trying to convert a set of ASCII Characters to Hex Characters. The code below opens a plain text file, converts things to ASCII but I cant figure out how to goto Hex. Any ideas?
#!/usr/bin/perl
open(fil,"file.txt");
@file = <fil>;
close(fil);
$converted="";
foreach(@file) {
(@chrs) = split("",$_);
foreach $chr(@chrs) {
my $asciiChar = ord($chr);
###########DO Hex Stuff HERE##########
$hexChr
$converted = join("",$converted,$hexChr);
}
}
open(outp, ">output.txt");
print outp $converted;
close(outp);
Re: Converting ASCII to Hex
by merlyn (Sage) on Jul 21, 2005 at 01:01 UTC
|
my $hex_string = unpack "H*", $ascii_string;
| [reply] [d/l] |
|
| [reply] |
|
#!/usr/bin/env perl
use strict;
use warnings;
use Encode;
use Test::More;
my @tests = (
{
source => "\x{2013}",
want => 'E2 80 93'
}
);
plan tests => scalar @tests;
for my $t (@tests) {
Encode::_utf8_off ($t->{source}); # bytes
my $have = uc unpack "H*", $t->{source}; # into hex
$have = join (' ', $have =~ /(..)/g); # spaced pairs
is ($have, $t->{want}, "Covert $t->{source} into $t->{want}");
}
| [reply] [d/l] [select] |
|
That did not seem to work
My Hex codes are coming out like "313030" instead of things like "A5" or "0C" etc...
| [reply] |
|
#!/usr/bin/perl
use strict;
use warnings;
my @values = (0, 1, 5, 25, 100, 200, 255);
print join(", ", map { unpack "H*", chr } @values), $/;
__END__
00, 01, 05, 19, 64, c8, ff
You may also consider printf/sprintf with the X indicator:#!/usr/bin/perl
use strict;
use warnings;
my @values = (0, 1, 5, 25, 100, 200, 255, 500, 1000);
print join(", ", map { sprintf "%X", $_ } @values), $/;
__END__
0, 1, 5, 19, 64, C8, FF, 1F4, 3E8
Note that this second solution works well with numbers beyond 255. You can also pad with zeroes on the left, just look in the docs for sprintf.
Flavio
perl -ple'$_=reverse' <<<ti.xittelop@oivalf
Don't fool yourself.
| [reply] [d/l] [select] |
|
Well, 313030 are the hex equivelents for the three characters "1", "0" and "0". Without knowing what your data is, we don't know if that's right or wrong. To clarify matters, are you sure you want the ASCII values of the characters, or do you want the hex representation of the number 100?
| [reply] |
|
You are missing what merlyn is saying. Use the unpack on the original string, not on the array of ordinals.
If you run it on the ordinals, then you are converting strings that are made up of digits, so you will get back strings in the range 30..39.
Update:
The following should be more than sufficient to replace the logic in the OP:
use strict;
use warnings;
open my $in, "<", "./infile";
my $input = do { local $/; <$in> };
open my $out, ">", "./outfile";
print $out unpack 'H*', $input;
Though presumably you aren't hardcoding filenames in real life.
| [reply] [d/l] [select] |
|
Was your test string "100" by chance? :) 31 = hex 1, 30 = hex 0. You're getting the right output, it just doesn't look like what you expected.
Here's an example you can try:
my $text = 'WHY HELLO THERE!';
# split into array of individual characters
my @characters = split(//,$text);
# transform each one individually into uppercase hex
foreach my $char (@characters) {
$char = uc(unpack "H*", $char);
}
# print in quotes to demonstrate separation between array elements
print "@characters";
You can cross-check the results with http://www.lookuptables.com. | [reply] [d/l] |
Re: Converting ASCII to Hex
by zentara (Archbishop) on Jul 21, 2005 at 11:37 UTC
|
Here is a clever little converter...it prints the hex vertically under each ascii char. Stick this in your tool box.
#!/usr/bin/perl -wnl012
# Prints the contents of a file a line at a time
# followed by the ASCII value of each character in vertical columns.
# Useful for debugging.
# If no filename is specified then input is read from the keyboard.
# Version 1.00 Ian Howlett ian@ian-howlett.com 6 July 2001
# Version 1.10 James Yolkowski ajy@sentex.net 8 July 2001
print; # Print the line we've just read
@hexvals = map {sprintf "%02X", ord $_} split //; # Get hex value of e
+ach char
for $a (0, 1) {print map {substr $_, $a, 1} @hexvals} # Print the hex
+values.
print "\n";
I'm not really a human, but I play one on earth.
flash japh
| [reply] [d/l] |
Re: Converting ASCII to Hex
by graff (Chancellor) on Jul 22, 2005 at 04:05 UTC
|
There is one slight disadvantage to merlyn's solution in the initial reply: the strings you are converting into hex numerics will probably include "\n" characters, which of course are "\x0a" -- but unpack "H*", "\n" will produce just "a" (no leading zero), and based on your reply to merlyn, this is not what you want.
You seem to want output that consistently shows two hex digits per ASCII character, with leading zero where needed.
So use sprintf (and use ALL_CAPS for a file handle name, or else use a lexically scoped scalar variable, instead of a lower-case bare word; and don't bother holding the whole file content in an array):
use strict;
open( IN, "file.txt" ) or die "file.txt: $!";
open( OUT, "out.txt" ) or die "out.txt: $!";
# or: open( my $in, "file.txt") ...
while (<IN>) { # or: while (<$in> ...)
$_ = join "", map { sprintf("%2.2x",ord($_)) } split //;
print OUT $_, $/;
}
If "map" is foreign to you, you can use a loop like the following, but you should learn to like map because in this kind of case it'll probably run faster than the for loop):
my $outstr = "";
$outstr .= sprintf("%2.2x",ord($_)) for (split //);
print $outstr, $/;
For that matter, when doing a simple "in->out" text filter like this, I prefer not to use open at all -- just while (<>) { ... print; } -- then provide the input file name as a command line arg, and redirect STDOUT to some other file.
| [reply] [d/l] [select] |
|
|