Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get input from the terminal in Perl

Tags:

perl

I am creating a simple chatterbot program like ELIZA.

I'm taking questions from the terminal and sending reply with dialog, but my program takes only the first input and repeats.

For example, when I run my script the output may be something like this:

[Eliza]: Hi, I'm a psychotherapist. What is your name?
user Input: hello my name is adam.
[Eliza]: hello adam, how are you?
[Eliza]: your name is adam
[Eliza]: your name is adam
[Eliza]: your name is adam
[Eliza]: your name is adam
[Eliza]: your name is adam

And it repeats endlessly.

I don't know where I am doing wrong. How can I get my program to read the next line from the keyboard?

sub hello {
    print "[Eliza]: Hi, I'm a psychotherapist. What is your name? \n";
}


sub getPatientName {
    my ($reply) = @_;

    my @responses = ( "my name is", "i'm", "i am", "my name's" );

    foreach my $response ( @responses ) {

        if ( lc($reply) =~ /$response/ ) {
            return  "$'";
        }
    }

    return lc($reply);
}

sub makeQuestion {
    my ($patient) = @_;

    my %reflections = (
        "am"    =>   "are",
        "was"   =>   "were",
        "i"     =>   "you",
        "i'd"   =>   "you would",
        "i've"  =>   "you have",
        "i'll"  =>   "you will",
        "my"    =>   "your",
        "are"   =>   "am",
        "you've"=>   "I have",
        "you'll"=>   "I will",
        "your"  =>   "my",
        "yours" =>   "mine",
        "you"   =>   "me",
        "me"    =>   "you"
    );

    if ( $count == 0 ) {
        $patientName = getPatientName($patient);
        $count += 1;
        print "Hello $patientName , How are you? \n";
    }

    my @toBes = keys %reflections;

    foreach my $toBe (@toBes) {

        if ($patient =~/$toBe/) {
            $patient=~ s/$toBe/$reflections{$toBe}/i;
            print "$patient? \n";
        }
    }
}

sub eliza {

    hello();

    my $answer = <STDIN>;

    while ($answer) {
        chomp $answer;
        #remove . ! ;
        $answer =~ s/[.!,;]/ /;
        makeQuestion($answer);
    }
}

eliza();
like image 732
kero Avatar asked Oct 18 '22 18:10

kero


1 Answers

Your while loop never reads input. The $answer got STDIN before the loop and presumably has a string, that evaluates true in the while condition. The regex in the loop cannot change that.

Thus not only is no new input assigned to $answer, but after the first iteration nothing at all changes in the loop. So it keeps running forever, printing the question based on the same $answer.

You need

while (my $answer = <STDIN>) {
    chomp $answer;
    # ...
}

instead.

Every time the condition of while (...) is evaluated the new input is read via <STDIN> and is assigned to $answer. Then each new question uses the new $answer. Note how a variable may be declared inside the while condition so to exist only inside the loop body (and in the condition after its declaration). This is a nice way to keep its scope restricted to where it is needed, inside the loop.

The filehandle read <...> returns undef when it gets EOF (or on error) and the loop terminates. See I/O Operators in perlop. A user at the terminal can normally achieve this by Ctrl-d.

like image 106
zdim Avatar answered Nov 15 '22 12:11

zdim