http://www.perlmonks.org?node_id=11114076

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

Note: I'm a beginner.

I have a file with questions (lines ending with a "?") followed immediately with answers, then a new line break:

$ cat quiz.txt Name 2 shapes? square circle Which continent is north of South America? North America Who was the 1st person on the moon? Neil Armstrong

I'm trying to create a perl script that prompts me with the question, followed by my <STDIN> and then displays the answer/s. Just as simple as that. No evaluation of whether the answer is correct and no score measurements etc..

I've done a perl one-liner that can prompt me the questions successfully:

$ perl -le '@array_q = `cat quiz.txt | grep ?`; foreach(@array_q){ print ; chomp($enter=<STDIN>) ; print "\n";}'

I then did another one-liner that can probe me for the answer:

$ perl -le '@array_ans = `cat quiz.txt | grep -v ?`; foreach(@array_ans){ print ; chomp($enter=<STDIN>) ; print "\n";}'

Since I had the 2 components of my quiz engine, I thought it would be simple combining the 2 one-liners using a nested foreach loop, but I'm running into all sorts of problems:

perl -le '@array_ans = `cat quiz.txt | grep -v ?`; foreach(@array_ans){ @array_q = `cat quiz.txt | grep ?`; foreach(@array_q){ print ; chomp($enter=<STDIN>) ; print "\n";}  print;}'

The output is all over the place and not what I expected.

Now I'm not necessarily interested in the answer, but more if I'm thinking about this problem in the correct way. After chewing on this issue for a week, I'm thinking along the lines of hashes being more appropriate since a quiz question can be associated with an answer. Any advice please?

Replies are listed 'Best First'.
Re: How could I create a command line quiz?
by Fletch (Bishop) on Mar 10, 2020 at 15:56 UTC

    Shelling out to cat or grep in backticks is almost never what you want to do (unless you're doing a one-liner throwaway or something). And your approach loses the correspondence between questions and answers.

    You should write a sub, let's call it parse_quiz_text, which will take the filename and return your questions and answers. The sub can cheat and use local $/ = q{}; (see perlvar) to say you want to read in paragraph mode, then you'd split off the first line from the answer(s). Each question would be represented by a hashref of the question and an arrayref of answers (perldsc and perlref will be useful if you're unfamiliar with those).

    sub parse_quiz_text { my( $quiz_file ) = @_; open( my $fh, q{<}, $quiz_file ) or die "problem opening quiz '$quiz +_file': $!\n"; local( $/ ) = q{}; my @quiz_questions; while( defined( my $paragraph = <$fh> ) ) { my @lines = split( /\n/, $paragraph ); push @quiz_questions, { question => (shift @lines), answers => \@l +ines }; } close( $fh ); return @quiz_questions; }

    Additionally: caveat that this does no error checking and is presuming the file is in the correct format (e.g. questions are always the first line of a paragraph, questions are always followed by at least one answer, yadda yadda yadda). You'd probably want to add some error checking at some point (check that the first line of the paragraph ends in a '?', check that @lines >= 2, . . .).

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: How could I create a command line quiz?
by Tux (Canon) on Mar 10, 2020 at 16:01 UTC
     $ perl -E'local$/="";while(<>){say"--";my($q,@a)=split/\n/;say$q;say" $_"for@a}' quiz.txt

    Enjoy, Have FUN! H.Merijn
Re: How could I create a command line quiz?
by BillKSmith (Monsignor) on Mar 10, 2020 at 19:06 UTC
    I strongly suggest that you reconsider implementing this task as a "command line". They can save some work if the task is sufficiently simple and your typing skills are adequate. Only you can judge whether you are more comfortable typing on the command line or in an editor. I am quite sure that this task is to complex for the command line, especially for a beginner. You require input from a terminal and a file. Your cannot use stdin for both. Open the file explicitly. Another big reason for using .pl files is that they save your work. Requirements change. Next week you may be back asking us how to keep score. You should not have to start over.
    Bill
Re: How could I create a command line quiz?
by Anonymous Monk on Mar 10, 2020 at 22:31 UTC

    Now I'm not necessarily interested in the answer, but more if I'm thinking about this problem in the correct way. After chewing on this issue for a week, I'm thinking along the lines of hashes being more appropriate since a quiz question can be associated with an answer. Any advice please?

    Congratulations, your journey has begun

    This is how you should think about it

    first Think of verbs

    StartQuiz( $quizfile, $userfile ); ... sub StartQuiz { my( $quizfile, $userfile ) = @_; for my $question ( Questions( $quizfile ) ){ my $answer = GetAnswer( $question ); SaveAnswer( $userfile, $question, $answer ); } }

    first Think of verbs

    Write a few of these loops before thinking about data structures

    More ideas

    Term::Interact prompting loop idea, https://metacpan.org/source/TOBYINK/Ask-0.007/examples/multiple-choice.pl

    my $answer = single_choice( text => "If a=1, b=2. What is a+b?", choices => [ [ A => 12 ], [ B => 3 ], [ C => 2 ], [ D => 42 ], [ E => "Fish" ], ], );
    https://metacpan.org/source/TOBYINK/Ask-0.007/examples/synopsis.pl
    if ($ask->question(text => "Are you happy?") and $ask->question(text => "Do you know it?") and $ask->question(text => "Really want to show it?")) { $ask->info(text => "Then clap your hands!"); }
Re: How could I create a command line quiz?
by yasser (Initiate) on Mar 12, 2020 at 15:25 UTC

    I feel like I'm getting warmer and that I have to move the foreach loop into the global section. Thanks for the advice thus far. I'm reading the docs prescribed by you all.

    #!/usr/bin/perl print "Let's start! \n"; print question(); chomp($input=<STDIN>); print answer(); sub question { @array_q = `cat quiz.txt | grep ?`; foreach(@array_q){print $array_q[0] } } sub answer { $/ = -00; @array_a = `cat quiz.txt | grep -v ?`; foreach(@array_a){print $array_a[0] } } bash-3.2$ ./quiz.pl Let's start! Name 2 shapes? Name 2 shapes? Name 2 shapes? sadf square circle North America Neil Armstrong bash-3.2$

      Did you *really* read all the answers and advice? If you did, why didn't you follow them or what was unclear?

      You still use backticks and external commands to do what perl itself is perfectly capable of doing (and people told you).


      Enjoy, Have FUN! H.Merijn

        Yes, you're right. I want to get the structure of the script correct first and then I'll replace the backticks with perl code

        I've built up to this part slowly by testing a basic subroutine that outputs static values, then added more functionality as my knowledge builds.