tags:

views:

561

answers:

7

I just want to read multiple lines in a file. For example in sample.txt

"Hi, how are you?"
"Hello 

I'm
fine, thank you!"

Now my problem is how can I read the second statement without removing the newline in the sentence?

EDIT:

It seems that my questions are not clear. So I think I should edit this: In my examples above, I need to get the whole,

"Hello 

I'm
fine, thank you!"
while ($line = <PFILE>)
{
   #How can I get the statement to $line?
}
+4  A: 

If you want to read all lines at once, change the line-separator $/:

{
    local $/;  # change the line separator to undef
    $filecontents = <FILE>;
}

if you want to read two lines at a time you can just read two lines at a time.

$lines1_and_2 = <FILE>;
$lines1_and_2 .= <FILE>;
Nathan Fellman
I see, so the second sentence will stay the same, i mean with new line characters? Thanks
sasayins
this is A way to do it, but it's slightly indirect. File::Slurp is prefered
George
Did you mean to redefine `$/` rather than `$,` in order to slurp the file? (Isn't `$,` the output record separator?)
Telemachus
@Sinan: D'oh, thanks for clearing me up. Still, when I try this, I get *only* the first line. Am I missing something?
Telemachus
@Telemachus there were typos galore in my previous comment. I meant to refer to the input **record** separator: `$/`.
Sinan Ünür
+3  A: 

I'm not sure what you mean by 'without removing the newline' in the sentence, but to read a file, line by line, you would do something like

open MYFILE, "<", "MyFile.txt"; # The < is for read mode
while ($line = <MYfILE>) {
    foo($line); #do whatever, one line at a time
}

If you want to read all lines at once into an array, you can just

my @lines = <MYFILE>;

Or to read it all in one string, change the newline separator $/ to be undefined

{
local $/; #initialized to undef
$file = <MYFILE>;
}
bobDevil
this is A way to do it, but it's slightly indirect.
George
+1  A: 

EDIT: I think I finally understand the question:

The OP has a file which, for lack of better terminology, contains questions and responses. Questions always come before responses. Both types of statements are enclosed in double quotes. There is a blank line (i.e. "\n\n") between a question and its associated response. The OP wants to read the questions and their associated responses one-by-one (not line-by-line).

There are several approaches to this (without necessarily slurping). One is to assume that double-quotes do not appear anywhere other than at the beginning or end of the strings of interest. I am not sure how valid an assumption this is which makes the following script fragile. Note that the last block is invalid because the answer is not enclosed in double quotes.

#!/usr/bin/perl

use strict;
use warnings;

while (
    defined(my $q = read_statement(\*DATA))
        and defined(my $a = read_statement(\*DATA))
) {
    print "QUESTION: $q\nANSWER: $a\n\n";
}

sub read_statement {
    my ($fh) = @_;

    my $line;
    while ( $line = <$fh> ) {
        last if $line =~ /^"/;
    }
    return unless defined $line;
    return $line if $line =~ /"$/;

    my $statement = $line;
    while ($line = <$fh> ) {
        $statement .= $line;
        last if $line =~ /"$/;
    }
    return unless $statement =~ /"$/;
    return $statement;
}

Test input:

__DATA__
"Hi how are you?"
"Hello

im
fine, thank you!"

"How is the weather?"

"It rained
all week.


It's been
gray

    and cold since the 15th"

"Who are you?"

Sinan

Output:

C:\Temp> t
QUESTION: "Hi how are you?"

ANSWER: "Hello

im
fine, thank you!"


QUESTION: "How is the weather?"

ANSWER: "It rained
all week.


It's been
gray

    and cold since the 15th"
Sinan Ünür
that's kind of hacky and error prone. might as well undef it
George
What on earth makes that hacky and error prone? The input appears to be records. The records appear to be separated by a blank line (so two new lines). The standard way to read records is to redefine $/ - it *is* the Input Record Separator after all.
Nic Gibson
Of course, I'm not sure that Sinan has actually answered the question asked but that's another matter entirely :)
Nic Gibson
@newt Thanks. I am not sure if anyone can accurately deduce the actual being asked but given the apparent lack of effort and reciprocity by the OP, I am not sure I want to spend too much time on this.
Sinan Ünür
why i can't upvote?
sasayins
i think this what i need, i can read the logic, but one question, what is \*DATA that you passed in the read_statement sub? thanks
sasayins
The DATA file handle is automatically created by perl (like STDIN, STDOUT, and STDERR) and reading from DATA will return lines found after the line "__DATA__" in the Perl source file. Referring to it as \*DATA will turn it into a reference which can be passed to subroutines as a parameter.
Dave Sherohman
Er, "referring to it as \\*DATA"... I hadn't expected markdown to eat the \\ in my previous comment.
Dave Sherohman
so its basically the same as open(PFILE,"<","file.txt")? the <PIFLE>?
sasayins
The `__DATA__` section and the `DATA` file handle (among other things) make it easy to include post a script which can be run by someone else.
Sinan Ünür
A: 

The operation you are looking for is called 'file slurping' instead of undef-ing $/

use

File::Slurp - Efficient Reading/Writing of Complete Files

here's the summary from the site

  use File::Slurp;

  my $text = read_file( 'filename' ) ;
  my @lines = read_file( 'filename' ) ;

  write_file( 'filename', @lines ) ;

  use File::Slurp qw( slurp ) ;

  my $text = slurp( 'filename' ) ;
George
File::Slurp is a good suggestion. Not giving you a +1 cause you felt the need to complain on everyone else's answers.
SquareCog
Ditto. If you have a different answer, just post your answer. Don't comment on all the other answers saying they suck. That's what the voting system is for - if your answer really is the best, it will find its way to the top of the list.
Dave Sherohman
he is complainig, but he gave the best answer :)
Karel Bílek
@Karel: No, he really didn't. The OP's question was vague and hard to parse, but George didn't put any particular effort into figuring it out, either.
Telemachus
+3  A: 

Based on your last comment, I wonder if this is what you want:

#!/usr/bin/env perl
use strict;
use warnings;
use Text::Balanced qw/extract_delimited/;

my $filecontents = do { local $/; <> };

while (my $item = extract_delimited($filecontents, '"')) {
    print "Item: $item\n";
}

It captures as one item each selection in double quotes, however long. (To anticipate: George this is A solution, but, no, I didn't choose to use File::Slurp.)

Telemachus
+1  A: 

It sounds like you want to read all "double-quoted" values inside a file, including those that are split across lines. If that's the case, you can do the following:

my $content = join "", <>;
my @statements = ();
push @statements, $1 while $content =~ /"(.*?)"/msg;

This doesn't handle escaped double-quotes within your quoted values, but your example didn't have any examples of that. If you need to be able to escape quotes, you need to change the regular expression a bit or use Text::Balanced as described above.

Matt Ryall
+1  A: 

With the OP's clarification that he's trying to get quoted strings out of the file, and assuming that each string's closing quote will be at the end of a line, my approach would be:

#!/usr/bin/perl

use strict;
use warnings;

local $/ = qq("\n);    # Extra " to fix SO syntax highlighting

while (my $quot_text = <DATA>) {
  print "Next text:\n$quot_text\n"
}

__DATA__
"Hi how are you?"
"Hello 

im
fine, thank you!"

Which returns:

Next text:
"Hi how are you?"

Next text:
"Hello

im
fine, thank you!"
Dave Sherohman