Print a section of a text file.

P

Prabh

Hello all,
I'm trying to print a section of a text file which has the following
contents.

===========================
..
..
..
Files Section:
{
File1:
{
Description1
Size1
Date1
}

File2:
{
Description2
Size2
Date2
}
}
..
..
===========================

In here, I want to print the contents of "File Section".

I tried the following:

#!/usr/local/bin/perl

use strict ;
use warnings;

open(FDL,"file.txt") or die "Can't open file.txt: $!\n" ;
while(<FDL>)
{
chomp ;
print "$_\n" if ( /^Files Section/ .. /\}/ ) ;
}
close(FDL) ;

====================================
This only prints the contents till the first occurence of the closing
brace, i.e., till Date1 of the first file1.

How do I tell it to "print till the closing brace of Files Section,
not just the first occurence of }"?

2. Also, whats the closest Perl-equivalent module/package for Java's
Velocity to readin a well-formatted file, because file.txt is always
of a standard format.

Thanks for your time,
Prabh
 
G

Gunnar Hjalmarsson

Prabh said:
How do I tell it to "print till the closing brace of Files Section,
not just the first occurence of }"?

If you can trust the indenting, why not just anchor the pattern in the
second regex to the beginning of the string?

/^\}/

Btw,

chomp;
print "$_\n"

gives you the same result as just

print
 
P

Paul Lalli

Hello all,
I'm trying to print a section of a text file which has the following
contents.

===========================
.
.
.
Files Section:
{
File1:
{
Description1
Size1
Date1
}

File2:
{
Description2
Size2
Date2
}
}
.
.
===========================

In here, I want to print the contents of "File Section".

I tried the following:

#!/usr/local/bin/perl

use strict ;
use warnings;

open(FDL,"file.txt") or die "Can't open file.txt: $!\n" ;
while(<FDL>)
{
chomp ;
print "$_\n" if ( /^Files Section/ .. /\}/ ) ;
}
close(FDL) ;

====================================
This only prints the contents till the first occurence of the closing
brace, i.e., till Date1 of the first file1.

How do I tell it to "print till the closing brace of Files Section,
not just the first occurence of }"?


Is that file exactly as you showed it above, including all whitespace? If
so, your second pattern match can just look for a right-brace as the first
character on the line:
print "$_\n" if ( /^Files Section/ .. /^}/ );

Paul Lalli
 
B

Ben Morrow

Quoth Gunnar Hjalmarsson said:
If you can trust the indenting, why not just anchor the pattern in the
second regex to the beginning of the string?

/^\}/

If you can't, but you can assume there is at most one {} on a line, and
that they are all significant (i.e. you won't ever get braces-inside-
quotes or something that don't count towards the nesting) then you can
do

my $braces = 0; # loathe uninit variable warnings

while (<$file>) {
/\}/ and $braces--;
print if /Files section/ .. (/\}/ and not $braces);
/\{/ and $braces++;
}

If you can't even assume that, you'll have to do something more
complicated; possibly slurping the whole file (File::Slurp) and using
Text::Balanced would be easiest.
Btw,

chomp;
print "$_\n"

gives you the same result as just

print

Tut tut... only if $/="\n" :)

Ben
 
P

Prabh

Paul Lalli said:
Is that file exactly as you showed it above, including all whitespace? If
so, your second pattern match can just look for a right-brace as the first
character on the line:


Thanks everyone for your responses.
After looking all over the file.txt, unfortunately the right-brace is
not always the first char. I guess, I cant use the "starts with }" as
my delimiter.

Heres a long shot, but anyone have an idea what algorithm the VI
editor uses to match the { with the corresponding }. It does it so
well, if the algorithm is simple enough, maybe I could replicate it
:).

Thanks,
Prabh
 
P

Prabh

Hello all,
I'm trying to print a section of a text file which has the following
contents.

===========================
.
.
.
Files Section:
{
File1:
{
Description1
Size1
Date1
}

File2:
{
Description2
Size2
Date2
}
}
.
.
===========================

In here, I want to print the contents of "File Section".

I tried the following:

#!/usr/local/bin/perl

use strict ;
use warnings;

open(FDL,"file.txt") or die "Can't open file.txt: $!\n" ;
while(<FDL>)
{
chomp ;
print "$_\n" if ( /^Files Section/ .. /\}/ ) ;
}
close(FDL) ;

====================================
This only prints the contents till the first occurence of the closing
brace, i.e., till Date1 of the first file1.

How do I tell it to "print till the closing brace of Files Section,
not just the first occurence of }"?

2. Also, whats the closest Perl-equivalent module/package for Java's
Velocity to readin a well-formatted file, because file.txt is always
of a standard format.

Thanks for your time,
Prabh



Hello all,
I'm posting from Google, time-delay and all.
I was able to print the Files section this way:

=============================================================

#!/usr/local/bin/perl

use strict ;
use warnings ;

my $open_brace = 0 ; # Count the open braces
my $close_brace = 0 ; # Count the close braces
my $in_FilesSection = 0 ; # This will tell if I should start
printing.

open(FDL,"file.txt") or die "Can't open file.txt: $!\n" ;
while(<FDL>)
{
chomp ;
$in_FilesSection = 1 if ( /^Files section/i ) ;
if ( $in_FilesSection )
{
$open_brace++ if ( /\}/ ) ;
$close_brace++ if ( /\{/ ) ;
print "$_\n" ;
last if ( ( $open_brace == $close_brace ) && (
$open_brace and $close_brace != 0 ) ) ;
}

}
close(FDL) ;

==================================================================


Inside the Files section, I increment the open or close brace count
and keep printing "$_" till the count of open brace is equal to close
brace and they're non-zero.

This did print the entire Files section and not just till the first }.
I'd appreciate if someone could give some feedback on my solution.

Thanks for your time,
Prabh
 
H

Herr Hardy

In here, I want to print the contents of "File Section".

Hmmh, counting FILE SECTION and { || } to open or close the
'print-gate'.

Ciao Hardy

#!/usr/bin/perl

use warnings;
use strict;

my $print_from_here = 0;

for(<DATA>){
$print_from_here = -1 if(/Files Section/);
$print_from_here++ if(/{/);
$print_from_here-- if(/}/);
next if((/{/) && ($print_from_here == 0));
# ^ just to avoid printig the closing brace
# of FILE SECTION where $print_from_here == 0
print $print_from_here.$_ if ($print_from_here >= 0);
}

__DATA__
 
H

Herr Hardy

+0200:

Sorry,
print $print_from_here.$_ if ($print_from_here >= 0);
is developing-status, should be

print if ($print_from_here >= 0);

at last.

Ciao Hardy
 
H

Herr Hardy

+0200:

Well, I shouldn't print ALL USELESS CONTENT of file.txt that appears
before 1st FILE SECTION. So we have to 'initialise' the counting

#!/usr/bin/perl

use warnings;
use strict;

my $print_from_here = 0;

open(FDL,"file.txt") or die "Can't open file.txt: $!\n" ;
while(<FDL>){
$print_from_here = 1 if(/Files Section/);
$print_from_here++ if(/{/);
$print_from_here-- if(/}/);
next if((/{/) && ($print_from_here == 2));
print if ($print_from_here >= 2);
}
close(FDL);
 
A

Anno Siegel

[nested "{}"]
[...]

Heres a long shot, but anyone have an idea what algorithm the VI
editor uses to match the { with the corresponding }. It does it so
well, if the algorithm is simple enough, maybe I could replicate it
:).

Well, this is really a job for Text::Balanced -- I think that has been
mentioned elsewhere.

For an ad-hoc solution, assume the whole file is read into $_ (if it's
too large for that, things get more complicated). The following prints
exactly the contents of the nested "{}" with no concern for line structure.
It may lose more line-feeds than is aesthetically pleasing.

my $bal = 0;
my $from;
while ( /([{}])/g ) {
$from = pos() - 1 if $bal == 0; # $bal will go up or we die
# ( $bal += 2*( $1 eq '{') - 1) >= 0 or die "unbalanced '}'"; # hi uri :)
$bal ++ if $1 eq '{';
$bal -- if $1 eq '}';
die "unbalanced '}'" if $bal < 0;
print substr( $_, $from, pos() - $from) if $bal == 0;
}

Anno
 
A

Anno Siegel

[problem snipped on the assumption that everyone still around knows it]
Hello all,
I'm posting from Google, time-delay and all.
I was able to print the Files section this way:

=============================================================

#!/usr/local/bin/perl

use strict ;
use warnings ;

my $open_brace = 0 ; # Count the open braces
my $close_brace = 0 ; # Count the close braces
my $in_FilesSection = 0 ; # This will tell if I should start
printing.

open(FDL,"file.txt") or die "Can't open file.txt: $!\n" ;
while(<FDL>)
{
chomp ;

No need to chomp, you only add the "\n" back on.
$in_FilesSection = 1 if ( /^Files section/i ) ;
if ( $in_FilesSection )
{
$open_brace++ if ( /\}/ ) ;
$close_brace++ if ( /\{/ ) ;

There's no need to escape the {}.
print "$_\n" ;
last if ( ( $open_brace == $close_brace ) && (
$open_brace and $close_brace != 0 ) ) ;
}

}
close(FDL) ;

==================================================================


Inside the Files section, I increment the open or close brace count
and keep printing "$_" till the count of open brace is equal to close
brace and they're non-zero.

You need only a single count. Increment on '{', decrement on '}'.
It's 0 outside {}, > 0 inside and negative on error.
This did print the entire Files section and not just till the first }.
I'd appreciate if someone could give some feedback on my solution.

Your solution assumes that all '{' and '}' are on a line by themselves.
It fails if a line is allowed to contain complete or partial blocks.

I have shown a solution that doesn't care about line feeds elsewhere
in this thread. For convenience I'll repeat the short version of the
code below.

Anno

my ( $bal, $from) = 0;
while ( /([{}])/g ) {
$from = pos() - 1 if $bal == 0;
$bal += 2*( $1 eq '{') - 1; # increment or decrement
print substr( $_, $from, pos() - $from) if $bal == 0;
}
 

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
474,156
Messages
2,570,878
Members
47,413
Latest member
KeiraLight

Latest Threads

Top