Gossamer Forum
Home : General : Perl Programming :

breaking up multi-line file data

Quote Reply
breaking up multi-line file data
I've been trying to make a very simple message board where I post form field info on a single line. However, I realized that if a carriage return is used in one of the fields, then when I try to read and output the information, the formatting in the file is all messed up. As of now, I've been reading line by line, which isn't working out because of the carriage returns in the file.

Does anyone have suggestions for either A) outputting the data to a file so that I can keep the information blocks separate (while including the formatting of the text fields), or B) reading the data from the file across multiple lines and parsing the data into appropriate blocks. Right now I'm using the Split function to break the data from a single line into different variables, but that doesn't work with carriage returns.

outputted file example:

12/24/80 @ 9PM,,,John,,,test,,,

2/13/80 @ 4PM,,,John,,,this with part has carriage

returns and uses multiple lines for a single block of data,,,

12/24/80 @ 9PM,,,John,,,test,,,



I'd greatly appreciate any help since I'm still new to perl. I'm not sure whether or not I can use a delimiter to place in front of each line to break up the data into blocks, or use a hash or what. Thanks in advance.





-John
Quote Reply
Re: [ODiN91] breaking up multi-line file data In reply to
I didn't totally understand what you were asking but is this anywhere near?

my @blocks = split /\r?\n/, $input;
Quote Reply
Re: [Paul] breaking up multi-line file data In reply to
Like I said, I'm pretty new to perl and regular expressions. Is this statement creating an array that splits up the file ($input) by carriage returns? I would like to read the file so that I get all the data for each block of information, especially if the data spans over more than one line. Currently I have a while loop to read the data file line by line and parse that... but, everything gets messed up if obviously if there is a carriage return in the data fields which brings the rest of the block to subsequent lines. Will the statement you posted account for that?

Hope this is a little more clear. Thanks for the help!



-John
Quote Reply
Re: [ODiN91] breaking up multi-line file data In reply to
Yeah it will (*should*) put each paragraph into a new element of the array.
Quote Reply
Re: [ODiN91] breaking up multi-line file data In reply to
Have you thought of using something like this:

Code:
sub encode {
# --------------------------------------------------
( my $txt = shift ) =~ s,([\x0-\x1f]),'\\x' .ord $+,ge;
return $txt;
}

sub decode {
# --------------------------------------------------
( my $txt = shift ) =~ s,(\\x(\d+)),chr $+,ge;
return $txt;
}

Those two functions will encode a multi-line string into one line and then decode it back to its orginal form again.
Quote Reply
Re: [Paul] breaking up multi-line file data In reply to
Paul, maybe I'm just reading the whole file incorrectly with my WHILE loop, but I couldn't get that code segment to work. Just resulted in the same problem. Here's a snippet of what I have:

Code:
open(TEMP, "temp.txt");


$n = 0;

while($file = <TEMP>) {

@block[$n] = split /\r?\n/,$file;

($dtime, $user, $event, $time, $ip) = split (",,,", @block[$n]);

.....

$n = $n+1;


Could it be that my WHILE loop is still reading line by line? Basically I need to parse the information in a block for each iteration. Thanks.



-John

Quote Reply
Re: [Aki] breaking up multi-line file data In reply to
Aki,

I'm not too familiar with substitutions (which I assume this is)... but, are these functions independent of one another? If I were to use something that encodes / decodes the data, I would need to use the encode function in one script and use the decode in the one that's outputting the data.

Regardless, I'm not quite clear on how to use these functions. Since I'm dealing with multiple entries in a file, could I make $txt an array ( @txt[$n] )?

Thanks for the help.


-John
Quote Reply
Re: [ODiN91] breaking up multi-line file data In reply to
They are, just copy one function in file A and the other into the file B.

Try this:

Code:

my $buf = qq!
This is a a
multi
line
comment. yay :)
!;

my $encoded = encode( $buf );

print "Encoded: ", $encoded, "\n";

my $decoded = decode( $encoded );

print "Decoded: ", $decoded, "\n";

Last edited by:

Aki: Sep 24, 2002, 3:19 PM
Quote Reply
Re: [Paul] breaking up multi-line file data In reply to
This thread appears to relate to a question I posted in this forum on how to extract paragraphs from a longer text - (a post that was unfortunately moved out of this forum).

Now, thanks to Paul's suggestions here, I have been able to write this global which outputs a first para (or any other according to index[x]) by detecting one carriage return:

sub {
my $tags = shift;
my $content = $tags->{Content};
@paras = split(/\r?\n/,$content);
return @paras[0];
}

Pursuing,
- how do I detect occurences of two successive carriage returns. ie paragraphs often have a blank line between them?
- can I pass the desired index into the sub when calling the global?
Thanks again!

Last edited by:

charly: Sep 25, 2002, 12:03 AM
Quote Reply
Re: [charly] breaking up multi-line file data In reply to
Code:
sub {
my $tags = shift;
my $content = $tags->{Content};
@paras = split(/\r?\n/,$content);
return @paras[0];
}

That last line needs to be $paras[0] not @paras[0]

>>- how do I detect occurences of two successive carriage returns. ie paragraphs often have a blank line between them?
<<

if ($content =~ /\r?\n\r?\n/) {

>>
- can I pass the desired index into the sub when calling the global?
<<

Yeah. <%global(index)%>
Quote Reply
Re: [Paul] breaking up multi-line file data In reply to
Thanks Paul,

so <%display_para(1)%> and the global lines:

sub {
my $index;
($index) = @_;
my $tags = shift;
my $content = $tags->{Content};
my @paras = split(/\r?\n/,$content);
return $paras[$index];
}

should output my first paragraph, but I obtain the message:
Can't use string ("1") as a HASH ref while "strict refs" in use at (eval 17) line 5.
Here I'm in deep trouble !

Last edited by:

charly: Sep 25, 2002, 8:57 AM
Quote Reply
Re: [charly] breaking up multi-line file data In reply to
No, if you pass in an argument to display_para() then you won't have $tags as your first argument. Try:

<%display_para(1)%>

sub {
my $index = shift;
my $tags = GT::Template->tags;
my @paras = split /\r?\n/, $tags->{Content};
return $paras[$index - 1];
}

The -1 is because the array starts at 0.

Cheers,

Alex
--
Gossamer Threads Inc.
Quote Reply
Re: [Aki] breaking up multi-line file data In reply to
Aki, thanks... I think I can use this for part of what I need to do, but I'm still worried that the problem lies with reading the file once the data is outputted to it. Basically I have a form that writes data to a file. Then, I have another file that actually parses the information from the file and outputs in a table. Maybe it's just my inexperience, in which case I apologize, but isn't the main problem simply reading the data from the outputted file? Maybe what I should be asking is, what is the best way to read multiple blocks of data from a file so I can parse the information (storing the different data fields in different variables) and having the flexibility of outputting that data in whatever manner.

Thanks again for all the help. It's greatly appreciated.



-John
Quote Reply
Re: [Alex] breaking up multi-line file data In reply to
Thanks Alex, really works fine !!
Ultimate step of my quest, would it be possible to output a range of paragraphs with one call of the global, ie. something like:
<%display_para(3-7)%> or (3...7) ?

Incidentally, my questions on this subject of text formatting and the answers everyone has provided would, I think, make a nice new page for your resources section!
Cheers!
Quote Reply
Re: [charly] breaking up multi-line file data In reply to
Code:
<%display_para(3-7)%>

Try:

<%display_para(3,7)%>

Then in your global use:

my $low = shift;
my $high = shift;

...then:

return @paras[$low..$high];

Last edited by:

Paul: Sep 27, 2002, 5:53 AM
Quote Reply
Re: [Paul] breaking up multi-line file data In reply to
Not quite there!
Whereas <%display_para%> works perfectly, ie.

sub {
my $index = shift;
my $tags = GT::Template->tags;
my @paras = split /\r?\n/, $tags->{Content};
return $paras[$index - 1];
}

the following <%display_paragraphs (2,7)%> with

sub {
my $low = shift;
my $high = shift;
my $tags = GT::Template->tags;
my @paras = split /\r?\n/, $tags->{Content};
# return $low; or return $high; => do show respectively 2 & 7
return $paras[$low..$high];
# return @paras[$low..$high]; no difference
# return $paras[2]; => does output the second paragragh
}

doesn't return anything. (No error displayed). My debug attempts are included above as comments.
Am I right concluding it's the final return instruction that isn't coping with the range 2 to 7 ?
Thanks for your wisdom!
Quote Reply
Re: [charly] breaking up multi-line file data In reply to
In my example I used

@paras[$low..$high];

not

$paras[$low..$high];

$paras is for returning one element, but you need @paras when returning more than one.

The code is correct so I'm not sure why it wouldn't work for you. Try this small example:

Code:
#!/usr/bin/perl
#==========================================================

use strict;
main();

sub main {
#----------------------------------------------------------
# Testing.

my @paras = qw/1 2 3 4 5 6 7 8 9 10/;
my $low = 5;
my $high = 8;

print "Content-type: text/html\n\n";
print join '<br>', @paras[$low..$high];
}

...that prints:

6
7
8
9

All I can suggest is to make sure $low and $high are being defined properly in your global and make sure @paras has more than seven elements (if using 2,7).

Last edited by:

Paul: Sep 28, 2002, 2:09 AM
Quote Reply
Re: [Paul] breaking up multi-line file data In reply to
Paul, please don't laugh when you see my solution !! Accept my novice's apologies. Yes, I confirmed your token example, and yes, in principle, your suggested lines should work: ie.

sub {
my $low = shift;
my $high = shift;
my $tags = GT::Template->tags;
my @paras = split /\r?\n/, $tags->{Content};
return @paras[$low..$high];
}

But for me, and for some reason I don't understand, they don't. So I churned it around during the day and devised this:

sub {
my $low = shift;
my $high = shift;
my $inc;
my $element;
my $additall;
my $tags = GT::Template->tags;
my @paras = split /\r?\n/, $tags->{Content};
for ($inc=$low; $inc<$high+1; $inc++) {
$element = @paras[$inc];
$additall = $additall . $element;
}
return $additall;
}

Yes, truly and grossly inelegant and verbose, but it DOES produce the desired result of outputing the call to the global <%display_paragraphs (x,y)%>! Your comments?
Charly
Quote Reply
Re: [charly] breaking up multi-line file data In reply to
I might be missing something totally blatant but I still can't see why it wouldn't work for you. Try this one:

Code:
sub {
my ($low, $high) = @_;
my ($tags) = GT::Template->tags;
my (@paras) = split /\r?\n/, $tags->{Content};

scalar @paras > $high or return "Bad!";

return join ("<br><br>", @paras[$low..$high]);
}

...see if the join() makes any difference.

Last edited by:

Paul: Sep 28, 2002, 2:42 PM
Quote Reply
Re: [Paul] breaking up multi-line file data In reply to
this works with a proviso. The line:

return join ("<br><br>", @paras[$low..$high]);

inserts unrequired extra spacing. I understand this: it's because my split function produces an array with every other element being just a carriage return. ie.

@para[0] : "bla bla bla bla bla... <BR>"
@para[1] : "<BR>" <= displays as space between two paragraphs
@para[2] : "bla bla bla bla bla... <BR>"
@para[3] : "<BR>"
etc. etc.

If I adapt to:

return join ("", @paras[$low..$high]);

it displays perfectly. But If I dispense with the join function ie:

return @paras[$low..$high];

it no longer works, only returning the last element/paragraph ie. @para[$high]

I think I'll stick with (and build on) these two versions - yours here and my long-winded one. I really thank you (and others here) a lot for your assistance.
Regards