我正在研究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";
}
答案 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' )
。