Ordering string of commands in a file

R

Raghuramaiah Gompa

I have a file that has lines like the following:

Titl1=B2a
Command1=c:\chi\cw.exe
Title2=f2a
Directory1=c:\chi
Type1=1
Command2=c:\chi\cw.exe
Directory2=c:\chi
Options2=%@%
Type11=2
Title14=Ma3
Command14=c:\chi\cpb.bat
Options14=c:\temp\temp.bin
Use long names3=1
Title12=Dir
Command12=Tfd
Title13=a2h
Command13=c:\bat\a2h.bat
Options13=%@dpn%
Show13=2
Command31=C:\bat\tview.bat
Use long names31=1
Title31=tview
.....

Basically Title,Command, Show,... constitute a group of commands that are associated with the
name described in Title. Now I want to reorder them in the alphabetical order of names described in
Title. For instance, the new file should have :

Title1=a2h
Command1=c:\bat\a2h.bat
Options1=%@dpn%
Show1=2

and all the lines (Title2=B2a, ..) are changed accordingly (because or the order a2h, B2a, Dir, f2a, Ma3, .... )

How can I achieve this? Please help. .. Raghu
 
X

xicheng

you may need to reset $/ to read your data, and then use hash keys to
sort your results. see the following code.
-----------------------------------------------------------------------
#!/usr/bin/perl -w
use strict;
my %h=();
my $n;
{
local $/="Title";
while(<DATA>) {
chomp;
$h{$1}=$2 if(/\A\d+=(.*?)\n(.*)\z/sm);
}
}
foreach my $k(sort{lc $a cmp lc $b} keys %h) {
$n++;
print "Title$n=$k\n$h{$k}";
}
__DATA__
Title1=B2a
Command1=c:\chi\cw.exe
Title2=f2a
Directory1=c:\chi
Type1=1
Command2=c:\chi\cw.exe
Directory2=c:\chi
Options2=%@%
Type11=2
Title14=Ma3
Command14=c:\chi\cpb.bat
Options14=c:\temp\temp.bin
Use long names3=1
Title12=Dir
Command12=Tfd
Title13=a2h
Command13=c:\bat\a2h.bat
options13=%@dpn%
Show13=2
Command31=C:\bat\tview.bat
Use long names31=1
Title31=tview
 
J

John W. Krahn

Raghuramaiah said:
I have a file that has lines like the following:

Titl1=B2a
Command1=c:\chi\cw.exe
Title2=f2a
Directory1=c:\chi
Type1=1
Command2=c:\chi\cw.exe
Directory2=c:\chi
Options2=%@%
Type11=2
Title14=Ma3
Command14=c:\chi\cpb.bat
Options14=c:\temp\temp.bin
Use long names3=1
Title12=Dir
Command12=Tfd
Title13=a2h
Command13=c:\bat\a2h.bat
Options13=%@dpn%
Show13=2
Command31=C:\bat\tview.bat
Use long names31=1
Title31=tview
.....

Basically Title,Command, Show,... constitute a group of commands that are associated with the
name described in Title. Now I want to reorder them in the alphabetical order of names described in
Title. For instance, the new file should have :

Title1=a2h
Command1=c:\bat\a2h.bat
Options1=%@dpn%
Show1=2

and all the lines (Title2=B2a, ..) are changed accordingly (because or the order a2h, B2a, Dir, f2a, Ma3, .... )

How can I achieve this? Please help. .. Raghu

Perhaps something like this:

#!/usr/bin/perl
use warnings;
use strict;


my %hash = do { local $/; grep length, split /^(Title\d+=.+)/m, <DATA> };

print
map $_->[ 1 ],
sort { lc $a->[ 0 ] cmp lc $b->[ 0 ] }
map [ /=(.+)/, "$_$hash{$_}" ],
keys %hash;


__DATA__
Title1=B2a
Command1=c:\chi\cw.exe
Title2=f2a
Directory1=c:\chi
Type1=1
Command2=c:\chi\cw.exe
Directory2=c:\chi
Options2=%@%
Type11=2
Title14=Ma3
Command14=c:\chi\cpb.bat
Options14=c:\temp\temp.bin
Use long names3=1
Title12=Dir
Command12=Tfd
Title13=a2h
Command13=c:\bat\a2h.bat
Options13=%@dpn%
Show13=2
Command31=C:\bat\tview.bat
Use long names31=1
Title31=tview




John
 
R

Raghuramaiah Gompa

Your description is not very clear.

You want to group the lines where the number is in
common (so Title14
goes with Options14 and Command14, and so forth)?

Then sort the groups them based on the value of the
Title element?
What about when there is no Title elelement, such as in Type11
above?

Then ouput in this new order, but renumber them, so the
the first
group is always Title1=... , then second has Title2=...
and so on?

Is that what you mean?

The code below *might* do something like you want, but
since your
specification is lacking, the results may be too.

Interesting (to me) sidenote: I noticed that when I
added the lc()
calls to the sort, the warnings about use of undefined
variables
(because Title isn't defined for some elements) went
away. Shouldn't
lc() warn if it's passed undef?


#!/usr/bin/perl
use warnings;
use strict;

my %items;
while(<DATA>) {
$items{$2}{$1} = $3 if /^(\w+?)(\d+)=(.+)/;
}

my $n = 1;
for my $idx (
sort {
lc $items{$a}{Title} cmp lc $items{$b}{Title}
} keys %items)
{
print map {
"$_$n=$items{$idx}{$_}\n";
} keys %{$items{$idx}};
print "----\n";
++$n;
}

__DATA__
Title1=B2a
Command1=c:\chi\cw.exe
Title2=f2a
Directory1=c:\chi
Type1=1
Command2=c:\chi\cw.exe
Directory2=c:\chi
Options2=%@%
Type11=2
Title14=Ma3
Command14=c:\chi\cpb.bat
Options14=c:\temp\temp.bin
Use long names3=1
Title12=Dir
Command12=Tfd
Title13=a2h
Command13=c:\bat\a2h.bat
options13=%@dpn%
Show13=2
Command31=C:\bat\tview.bat
Use long names31=1
Title31=tview

First of all, I apologize for not making my question
clear. However, you (and others, too) understood exactly
what I want. Thank you all for the codes and help. Now I
am faced with another problem. This sorting must be done
only for a part of the text that is between the
line that contain [Buttons] and someother line that
starts with [ (it could be [Directories] or [Files]).
Rest of the document should be copied as it is. I tried
several ways and failed :( Please help. .. Raghu
 
P

Paul Lalli

Raghuramaiah said:
This sorting must be done
only for a part of the text that is between the
line that contain [Buttons] and someother line that
starts with [ (it could be [Directories] or [Files]).
Rest of the document should be copied as it is. I tried
several ways and failed :(

You generally get more helpful responses if you post what you
attempted, explain how it failed, and allow us to help you fix your
attempt, rather than simply claiming that you tried, and asking for the
solution outright.
Please help.

Look up the "flip-flop" operator (which is the range operator, but used
in a scalar context) in
perldoc perlop

Paul Lalli
 
R

Raghuramaiah Gompa

Raghuramaiah said:
This sorting must be done
only for a part of the text that is between the
line that contain [Buttons] and someother line that
starts with [ (it could be [Directories] or [Files]).
Rest of the document should be copied as it is. I tried
several ways and failed :(

You generally get more helpful responses if you post what you
attempted, explain how it failed, and allow us to help
you fix your
attempt, rather than simply claiming that you tried,
and asking for the
solution outright.
Please help.

Look up the "flip-flop" operator (which is the range
operator, but used
in a scalar context) in
perldoc perlop

Paul Lalli

Thank you for your response. Here is one that was very
close to getting what I want. But it is somehow printing
the whole file first and doing the reordering I wanted.


#!/usr/bin/perl

use warnings;
use strict;
my %par;


my %items;
print "[Options]\n";
while(<>) {
$items{$2}{$1} = $3 if /^(\w+?)(\d+)=(.+)/;
print if /[Options]\n/ .. /[Buttons]\n/;
#the above line is the problem. I just want the lines
#between [Options] and [Buttons]
#be printed including these lines.
}
print "[Buttons]\n";
my $n = 1;
for my $idx (
sort {
lc $items{$a}{Title} cmp lc $items{$b}{Title}
} keys %items)
{
print map {
"$_$n=$items{$idx}{$_}\n";
} keys %{$items{$idx}};
print "----\n";
++$n;
}

Please help. .. Raghu
 
P

Paul Lalli

Raghuramaiah said:
my %items;
print "[Options]\n";
while(<>) {
$items{$2}{$1} = $3 if /^(\w+?)(\d+)=(.+)/;
print if /[Options]\n/ .. /[Buttons]\n/;
#the above line is the problem. I just want the lines
#between [Options] and [Buttons]
#be printed including these lines.
}

[ and ] are special characters in a regular expression. You need to
escape them.

print if /\[Options\]\n/ .. /\[Buttons\]\n/;

(as it stands, the first reg ex is true if it contains any of O, p, t,
i, o, n, or s.)

Paul Lalli
 
R

Raghuramaiah Gompa

Interesting (to me) sidenote: I noticed that when I
added the lc()
calls to the sort, the warnings about use of undefined
variables
(because Title isn't defined for some elements) went
away. Shouldn't
lc() warn if it's passed undef?


#!/usr/bin/perl
use warnings;
use strict;

my %items;
while(<DATA>) {
$items{$2}{$1} = $3 if /^(\w+?)(\d+)=(.+)/;
}

my $n = 1;
for my $idx (
sort {
lc $items{$a}{Title} cmp lc $items{$b}{Title}
} keys %items)
{
print map {
"$_$n=$items{$idx}{$_}\n";
} keys %{$items{$idx}};
print "----\n";
++$n;
}

__DATA__
Title1=B2a


Thank you all very much. I was able to get the results I
wanted. (I posted code and Xicheng pointed out my
mistake in ignoring the necessary \ before [ and ]). As
you noticed, group of commands with no title was
processed with no title. I do not know how to fix (this
minor) problem. I am very happy with the present code.
But could it be improved? Thank you once again. .. Raghu
 
P

Paul Lalli

Raghuramaiah said:
my %items;
print "[Options]\n";
while(<>) {
$items{$2}{$1} = $3 if /^(\w+?)(\d+)=(.+)/;
print if /[Options]\n/ .. /[Buttons]\n/;
#the above line is the problem. I just want the lines
#between [Options] and [Buttons]
#be printed including these lines.
}

[ and ] are special characters in a regular expression. You need to
escape them.

print if /\[Options\]\n/ .. /\[Buttons\]\n/;

(as it stands, the first reg ex is true if it contains any of O, p, t,
i, o, n, or s.)

Paul Lalli
 
R

Raghuramaiah Gompa

Raghuramaiah said:
my %items;
print "[Options]\n";
while(<>) {
$items{$2}{$1} = $3 if /^(\w+?)(\d+)=(.+)/;
print if /[Options]\n/ .. /[Buttons]\n/;
#the above line is the problem. I just want the lines
#between [Options] and [Buttons]
#be printed including these lines.
}

[ and ] are special characters in a regular expression.
You need to
escape them.

print if /\[Options\]\n/ .. /\[Buttons\]\n/;

(as it stands, the first reg ex is true if it contains
any of O, p, t,
i, o, n, or s.)

Paul Lalli

That explains the weird results I got. :) Thank you so
much. I learned a lot. .. Raghu
 
R

Raghuramaiah Gompa

Is that what you mean?
The code below *might* do something like you want, but
since your
specification is lacking, the results may be too.

Interesting (to me) sidenote: I noticed that when I
added the lc()
calls to the sort, the warnings about use of undefined
variables
(because Title isn't defined for some elements) went
away. Shouldn't
lc() warn if it's passed undef?


#!/usr/bin/perl
use warnings;
use strict;

my %items;
while(<DATA>) {
$items{$2}{$1} = $3 if /^(\w+?)(\d+)=(.+)/;
}

my $n = 1;
for my $idx (
sort {
lc $items{$a}{Title} cmp lc $items{$b}{Title}
} keys %items)
{
print map {
"$_$n=$items{$idx}{$_}\n";
} keys %{$items{$idx}};
print "----\n";
++$n;
}

Now I am trying to modify the above code to print the
hash without the sort command. Could some one help me
with this? Thanks. .. Raghu
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,754
Messages
2,569,522
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top