Operating System - HP-UX
1753814 Members
7652 Online
108805 Solutions
New Discussion юеВ

Re: From single ASCII to several Octal chars

 
SOLVED
Go to solution
Jose Mosquera
Honored Contributor

From single ASCII to several Octal chars

Hi pals,

I need replace into an ASCII file any simpe char by two or more Octals chars. For example the "X" ASCII char by \012, \013 and \014 Octals chars. Among the octal characters spaces should not exist. Any hint?

Rgds
9 REPLIES 9
A. Clay Stephenson
Acclaimed Contributor

Re: From single ASCII to several Octal chars

There are several methods available but Perl or awk are probably the most straight forward. I'll assume that you actually want to replace more than simply 'X' so I'll add a bit more logic than is actually needed for your task.

Create a file, my.awk:

{
i = 1
len = length($0)
while (i <= len)
{
s = substr($0,i,1)
done = 0
if (s == "X")
{
printf("%c%c%c",012,013,014)
done = 1
}
if (s == "Y")
{
printf("%c%c",012,033)
done = 1
}
if (!done) printf("%c",s)
++i
}
printf("\n")
}

If I got all that typed in it should work and substitute 3 octals for "X" and 2 for "Y".

awk -f my.awk infile > outfile

A better solution would be to put your characters and replacement values in a file and let awk read it in in the BEGIN section and then apply the substitutions but I'll leave that as an exercise.
If it ain't broke, I can fix that.
Rodney Hills
Honored Contributor

Re: From single ASCII to several Octal chars

You could use perl

perl -pie 's/X/\012\013\014/g' myfile

HTH

-- Rod Hills
There be dragons...
Gregory Fruth
Esteemed Contributor
Solution

Re: From single ASCII to several Octal chars

Try this:

perl -pe 's/X/\012\013\014/g' myfile
Hein van den Heuvel
Honored Contributor

Re: From single ASCII to several Octal chars

I'm with Clay that you probably need a file with a list of translations. I coded up an example in perl. The tricky bit (because I did not read the perl books) was to make it dynamically interpret the octal (or any other 'special') sequence. I used 'eval' and created a piece of double quoted string. That feels sub-obtimal... but it works.
There may be something smarter with de-referencing strings.
The example below reads any number of transliterations, for any length result.
If I knew there were only a handfull, then I'd generate tr statements.
One might also consider pre-filling the (normal, or associative) array with all characters avoiding a test.

Sample table, input, command, and result:

$ cat data
aapXnootYmiesX
X
Y
000Z000
niets

$ cat table
X\012\013\014
Yaaa
Z\t\023

$ perl tr.p table data | od -b
0000000 141 141 160 012 013 014 156 157 157 164 141 141 141 155 151 145
0000020 163 012 013 014 012 012 013 014 012 141 141 141 012 060 060 060
0000040 011 023 060 060 060 012 156 151 145 164 163 012
0000054

script:

$file = shift @ARGV;
die "Please provide a translation table as first argument" unless $file;
open (FILE,"<$file") or die "could not open translation table file:$file";
while () {
chop;
$tr{substr($_,0,1)}=eval '"' . substr($_,1) . '"';
}
close (FILE);
$file = shift @ARGV;
die "Please provide a data file name as second argument" unless $file;
open (FILE,"<$file") or die "could not open input data file:$file";
while () {
$new_line = "";
$l = length;
for ($i=0; $i<$l;$i++) {
$x = substr($_,$i,1);
$new_x = $tr{$x};
$new_line .= ($new_x) ? $new_x : $x;
}
print $new_line;
}




hth,
Hein.

Hein van den Heuvel
Honored Contributor

Re: From single ASCII to several Octal chars

Is there a function like 'chop' in perl which removes the leading character?
That would be a nicer way to walk a string without all the substr stuff. Mind yoy, it would just look nicer, it may well be more work. Using 'chop' the main loop from the previous example looks a lot simpler:

$file = shift @ARGV;
die "Please provide a translation table as first argument" unless $file;
open (FILE,"<$file") or die "could not open translation table file:$file";
while () {
chop;
$tr{substr($_,0,1)}=eval '"' . substr($_,1) . '"';
}
close (FILE);
$file = shift @ARGV;
die "Please provide a data file name as second argument" unless $file;
open (FILE,"<$file") or die "could not open input data file:$file";
while () {
$new_line = "";
while (!/^$/) {
$x = chop;
$x = $tr{$x} if ($tr{$x});
$new_line = $x . $new_line;
}
print $new_line;
}


cheers,
Hein.
c_51
Trusted Contributor

Re: From single ASCII to several Octal chars

here is another way:

awk '
BEGIN {
ascii["X"]=sprintf("%c%c",012,033);
ascii["Y"]="ts";
}
{
i = 1;
len = length($0);
for (i=1;i <= len;i++) {
s = substr($0,i,1);
if ( ascii[s] ) printf("%s",ascii[s]);
else printf("%s",s);
}

printf("\n");
}'
Jose Mosquera
Honored Contributor

Re: From single ASCII to several Octal chars

Great solutions all of them!

Perl solutions are one-shoot!, however I would like in awk's solutions the way to search a ASCII's multicharacter string instead of a single character.
i.e search for: "-MarkToReplace-"
It would be ideal that was a pattern of search of dynamic length.

After this I will assign points generously!

Rgds.
Rodney Hills
Honored Contributor

Re: From single ASCII to several Octal chars

Maybe a little more detail on the input file you are processing would help.

If you have some strings of text embedded in a file of the form -xxxxx- and want to replace them with octal character \0nnn, then here is a perl one-liner you might consider-

perl -pe '%z=("-MarkToReplace-","\070\072","-Other-","\071"); while(/(-\w+-)/g) {$s=$1; s/$s/$z{$s}/;}' yourfile

Each -xxxx- string to be replaced are defined in variable %z along with its replacement value. The while loop will scan the line for any pattern that matches -xxxx- and then lookup the replace value.

HTH

-- Rod Hills
There be dragons...
Gregory Fruth
Esteemed Contributor

Re: From single ASCII to several Octal chars

I'm not sure I understand your second
question, but you can replace multiple
strings (FOO or BAR or BAZ) this way:

perl -pe 's/FOO|BAR|BAZ/\012\013\014/g' file

If you have a table of things (FOO or BAR
or BAZ) that you want to replace with
respectively (DOG or CAT or COW), try this:

perl -pe 'BEGIN {$a{FOO} = 'DOG';
$a{BAR} = 'CAT'; $a{BAZ} = 'COW'} ; s/(FOO|BAR|BAZ)/$a{$1}/g' file

This will change FOO to DOG, BAR to CAT,
and BAZ to COW. You could probably
tighten this up using the map() operator,
but I'll leave that as an exercise for the
reader :-)