Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Reading a File by Line then Analyzing each Line

by soon_j (Scribe)
on Jun 06, 2006 at 16:29 UTC ( [id://553858]=perlquestion: print w/replies, xml ) Need Help??

soon_j has asked for the wisdom of the Perl Monks concerning the following question:

Monks, I am faced with a task of reading a text file line by line, then analyzing each line. The "reading" part of the file by line is easier, but the "analyzing" part is what troubles me.

This is a sample of my text file:

1. What is my name?
A. Rooney *
B. Gerrard
C. Ronaldo
D. Ronaldinho
2. Who's your bet in the coming World Cup?
A. Brazil *
B. Germany
C. England
D. Cameroon

My code for reading each line goes like this:
use FileHandle; $fh = new FileHandle; $fh->open("<c:\\test.txt") || die ("Could not open file!!!!. $!"); until ($fh->eof) { $tmp = $fh->getline; # If $tmp starts with any number followed by a period (it means that + the part after the period is the question portion), do FUNCTION1 # If $tmp starts with a "letter" followed by a period (it means that + this is one of the choices), do FUNCTION2 } $fh->close;
In the above example, if:

$tmp = "1. What is my name?"

How will I match the "number" until it encounters a "period", discard this portion and assigns the remaining part to:

$question = "What is my name?"

Same goes for this also:

$tmp = "A. Rooney *"

How will I match the "letter" until it encounters a "period", discards this portion and assigns the remaining part to:

$choice_a = "Rooney *"

Also if it encounters "*" at the end of the choices, it removes this "*" and declares this as the answer:

Example:
$choice_a = "Rooney *" (becomes $choice_a = "Rooney" after "*" is removed)
$choice_b = "Gerrard"
$choice_c = "Ronaldo"
$choice_d = "Ronaldinho"

$answer = "Rooney"

Please bear with me as I am not good is regular expressions, matching, etc.

Replies are listed 'Best First'.
Re: Reading a File by Line then Analyzing each Line
by japhy (Canon) on Jun 06, 2006 at 16:36 UTC
    I'll answer the latter half of your node later (it's time for lunch), but let me just say that your file-opening-and-reading code is really cumbersome. It's so much easier just to do:
    open my($fh), "<", "/path/to/file" or die "can't read /path/to/file: $ +!"; while (my $line = <$fh>) { # do stuff with $line } close $fh;
    As for line analysis, I'll write something after I've eaten (but I'll be too late, since I'm sure some other monks will give you sound advice).

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: Reading a File by Line then Analyzing each Line
by thundergnat (Deacon) on Jun 06, 2006 at 17:54 UTC

    Personally, I'd read everything into a hash.

    use Data::Dumper; my (%quiz, $number); while (<DATA>){ chomp; if (s/^(\d+)\. *//) { $number = $1; $quiz{$number}{question} = $_; } elsif (s/^([A-Z])\. *//) { my $option = $1; $quiz{$number}{answer} = $option if s/ *\*$//; $quiz{$number}{$option} = $_; } else { next; } } print Dumper \%quiz; __DATA__ 1. What is my name? A. Rooney * B. Gerrard C. Ronaldo D. Ronaldinho 2. Who's your bet in the coming World Cup? A. Brazil * B. Germany C. England D. Cameroon

    You can then do things like: "What is the answer to question two?"

    print $quiz{2}{$quiz{2}{answer}};

    or, "Display question 1:"

    print '1. ',$quiz{1}{question},"\n"; for ( sort keys %{$quiz{1}} ){ print "$_. ",$quiz{1}{$_},"\n" if $_ !~ /\p{Lower}/; }

    or, "Display them all:"

    for (sort keys %quiz) { my $number = $_; print "\n$number. $quiz{$number}{question}\n\n"; for ( sort keys %{$quiz{$number}} ){ next if /question|answer/; print "$_. $quiz{$number}{$_}\n"; } print "\nAnswer: $quiz{$number}{answer}\n"; }

    Update: or a little clearer:

    for (sort keys %quiz) { my $current = $quiz{$_}; print "\n$_. $current->{question}\n\n"; for ( sort keys %{$current} ){ next if /question|answer/; print "$_. $current->{$_}\n"; } print "\nAnswer: $current->{answer}. $current->{$current->{answer} +}\n"; }
Re: Reading a File by Line then Analyzing each Line
by ahmad (Hermit) on Jun 06, 2006 at 16:41 UTC

    i dont know if this example could help you any

    # File containing Q&A my $file = 'Q.txt'; open(FH,$file) or die $!; while (my $line = <FH>) { if ($line =~m/^\d+\./) { print "Question : $line"; }else{ print $line; } } close(FH);

    Update : if you want to remove "*" from the end just add the following line after the while loop

    $line =~s/\*$//;
Re: Reading a File by Line then Analyzing each Line
by neniro (Priest) on Jun 06, 2006 at 18:06 UTC
    I suggest using a hash instead of plain variables:
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %questions; my $cur; while (<DATA>) { $cur = $1 if /^\d+\.\s*(.*)$/; $questions{$cur}->{selected} = $1 if $cur and /^[A-Z]+\.\s*(.*)\s+ +\*$/; s/\s*\*\s*$//; push @{$questions{$cur}->{answers}}, $1 if $cur and /^[A-Z]+\.\s*( +.*)\s*$/; } print Dumper \%questions; __DATA__ 1. What is my name? A. Rooney * B. Gerrard C. Ronaldo D. Ronaldinho 2. Who's your bet in the coming World Cup? A. Brazil * B. Germany C. England D. Cameroon
Re: Reading a File by Line then Analyzing each Line
by GrandFather (Saint) on Jun 06, 2006 at 19:37 UTC

    Building your question sheet in a hash seems to be the way to go. The following code reads the quiz into a hash then reprints the form slightly reformatted.

    use strict; use warnings; my %questions; my $question = 0; while (<DATA>) { chomp; my ($prefix, $text, $tag) = /^(\w+)\.\s*((?:(?!\*$).)*)(\*)?$/; next if ! defined $text; if ($prefix =~ /^\d+/) { $question = $prefix; $questions{$question}{Question} = $text; } else { push @{$questions{$question}{Answers}}, "$prefix. $text"; $questions{$question}{Answer} = "$prefix. $text" if defined $t +ag; } } # Print the question sheet for my $num (sort keys %questions) { print "$num. $questions{$num}{Question}\n"; for (@{$questions{$num}{Answers}}) { print " $_"; print " (answer)" if $_ eq $questions{$num}{Answer}; print "\n"; } } __DATA__ 1. What is my name? A. Rooney * B. Gerrard C. Ronaldo D. Ronaldinho 2. Who's your bet in the coming World Cup? A. Brazil * B. Germany C. England D. Cameroon

    Prints:

    1. What is my name? A. Rooney (answer) B. Gerrard C. Ronaldo D. Ronaldinho 2. Who's your bet in the coming World Cup? A. Brazil (answer) B. Germany C. England D. Cameroon

    DWIM is Perl's answer to Gödel

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://553858]
Approved by bpphillips
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (4)
As of 2024-04-20 02:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found