perl中的模式匹配和正则表达式?

时间:2017-02-03 07:18:23

标签: perl

我正在研究perl和正则表达式中的chet-bot程序,但是我没有得到预期的结果,因为你看到我有哈希的所有代词和动词,我循环通过字符串,如果它匹配哈希键然后替换哈希具有当前子字符串值的键值。

节目输出
Eliza:嗨,我是一名心理治疗师。你叫什么名字?
adam:我的名字是adam
Eliza:你好亚当,你好吗?
亚当:我感觉很糟糕 Eliza:为什么你感觉不舒服?
亚当:因为我生病了 Eliza:为什么因为你生病了?

不管最后一个问题中的“因为”字,但输出应该是这样的

Eliza:为什么因为你生病了? 关于如何解决这个问题的任何建议。

代码:

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 "
    );

    my @toBes = keys %reflections;
    foreach my $toBe (@toBes) {
        if ($patient =~/$toBe\b/)
        {
            $patient=~ s/$toBe /$reflections{$toBe}/i;

        }

    }
    print "Why $patient? \n";
}

3 个答案:

答案 0 :(得分:3)

您的代码进行循环替换,因为它始终处理整个短语。它取代了一个单词,只是为了以后替换那个替换。 answer by David Verdin解释了它并显示了解决此问题的方法。

这是另一种方式

my $phrase =  join ' ', map { $reflections{$_} // $_ } split ' ', $patient;

split生成的单词列表被输入map$_ variable将块中的代码应用于每个单词。在块内,当前处理的元素是默认的defined-or operator

如果单词是具有defined值的哈希中的键,则返回该值,否则返回单词本身。这是通过// CODEPEN来实现的。因此,具有散列键的所有单词都被相应的值替换,而其他单词则不变地传递。他们的订单也保持不变,因此我们会根据需要处理我们的单词列表。

然后,该输出列表按空格连接,形成'Why '

前面的短语

请注意' '中的模式split匹配任何数量的空格。它通常用于打破字符串"空间" (进入"单词")并且是split的默认值。

我想在发布的代码中添加对正则表达式使用的注释。您不需要首先测试匹配以进行替换。你可以做到

foreach my $item (@list) {
    $item =~ s/$pattern/$repl/;
}

如果$pattern中的$item没有匹配,则$item不会发生变化。

答案 1 :(得分:2)

编辑: 根据@zdin的建议,我将'\s'替换为' ',它将匹配任意数量的空格,并且忽略前导空格。

那是因为你循环遍历%reflection hash的完整键并进行系统替换。因此,您在循环1中找到“am”键并将其替换为“are”。然后在循环8处找到“are”键并将其替换为“am”。

在进行单个单词替换时,您应该确保只使用split进行一次单词运行:

#!/usr/bin/perl

use strict;
use warnings;

my $question = '';

while ($question ne 'stop') {
    $question = <STDIN>;
    chomp $question;
    print makeQuestion($question)."\n";
}

sub makeQuestion{
    my ($patient) = @_;
    my @new_question;
    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",
    );
    WORDS: foreach my $word (split ' ', $patient) {
        REPLACE: foreach my $key (keys %reflections) {
            if ($word =~ m{\A$key\Z}i) {
                $word =~ s{$key}{$reflections{$key}}i;
                 last REPLACE;
            }
        }
       push @new_question, $word;
    }
    return join ' ', @new_question;
}

答案 2 :(得分:0)

这是因为在特定的短语/句子中,有两个符合条件的候选人匹配您的正则表达式。而事实是,哈希的元素在内存中以随机方式排序。在您的代码中,您只获得了%refelections的密钥,但您没有提供排序。因此,每次运行keys %reflections都会返回不同排序的数组。例如,在运行1中,它可能是( 'am', 'i', 'my', me' ... ),然后下次运行( 'i', "you'll', 'my', 'yours' )