我正在处理perl和正则表达式中的chet程序,但是我没有得到想要的结果,因为我在散列中有所有的代词和动词,我是通过字符串循环的,如果它与散列键匹配,那么用当前的子字符串值替换散列键值。
程序输出
Eliza:嗨,我是心理治疗师。您的名字是什么?
亚当:,我叫亚当
Eliza:你好,亚当,你好吗?
adam:,我感觉很糟糕
Eliza:,你为什么感觉不好?
adam:,因为我病了
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";
}发布于 2017-02-03 07:53:14
编辑:如@zdin所建议的,我将'\s'替换为' ',这将匹配任意数量的空白,同时也忽略了领先的空白空间。
这是因为您正在遍历%反射散列的全部键,并进行系统的替换。因此,您可以在循环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;
}发布于 2017-02-03 08:02:34
您的代码会进行循环替换,因为它总是处理整个短语。它取代了一个词,只是后来才替换了这个词。David Verdin的答复对此进行了解释,并展示了解决这一问题的方法。
这里有另一种方法
my $phrase = join ' ', map { $reflections{$_} // $_ } split ' ', $patient;拆分生成的单词列表被输入到地图,地图将块中的代码应用于每个单词。在块内部,当前处理的元素位于默认的变量中。
如果单词是带有defined值的散列中的键,则返回该值,否则返回单词本身。这是由//,运算符实现的。因此,所有具有散列键的单词都会被相应的值替换,而其他的则不会改变。他们的订单也被保留下来,因此我们可以根据需要处理我们的单词列表。
然后,将输出列表用空格连接起来,形成由'Why '加在前面的短语。
注意,split中的模式split与任意数量的空白相匹配。它通常用于将字符串“由空格”(改为“word”)中断,这是split的默认设置。
我想在发布的代码中添加一个关于正则表达式使用的注释。您不需要为匹配进行第一次测试就可以进行替换。你可以直接做
foreach my $item (@list) {
$item =~ s/$pattern/$repl/;
}如果$pattern在$item中不匹配,则$item将保持不变。
https://stackoverflow.com/questions/42018775
复制相似问题