Perl - 使用正则表达式匹配哈希键或值中的输入

问题描述:

首先,这是一项家庭作业。我用正则表达式很困难,而且我卡住了。Perl - 使用正则表达式匹配哈希键或值中的输入

这是我到目前为止的代码,我有用户指定一个文件名,如果它存在,填充作为键的名称和电话号码作为值的散列。

#!/usr/bin/perl 

use strict; 

print "\nEnter Filename: "; 
my $file = <STDIN>; 
chomp $file; 

if(!open(my $fileName, "<", "$file")) 
{ 
    print "Sorry, that file doesn't exist!", "\n"; 
} 
else 
{ 
    my %phoneNums; 
    while (my $line=<$fileName>) 
    { 
     chomp($line); 
     (my $name,my $number) = split /:/, $line; 
     $phoneNums{$name} = $number; 
    } 

    print "Read in the file!", "\n\n"; 

    print "Enter search: "; 
    my $input = <STDIN>; 
    chomp $input; 

    #HERE IS WHERE I'M LOST 
} 

print "\n"; 

这是我坚持的部分:

允许用户输入搜索字符串。 使用与手机相同的样式来查找匹配。搜索字符串中的任何个人 字符都可以与 键中的任何其他字符相匹配,这意味着搜索字符串中的'2'可以与联系人列表中的'2','A','B'或'C'匹配。匹配可能发生在联系人姓名或电话号码中。要进行匹配,搜索字符串中的每个字符必须按顺序出现在联系信息中,但不一定要在其他每个字符旁边出现。例如,搜索字符串“86”(基本上与搜索字符串“TM”或“NU”相同)将匹配“TOM”而不匹配“母亲”。每个手机按键 特点: 0, 1, 2ABC, 3DEF, 4GHI, 5JKL, 6MNO, 7PQRS, 8TUV, 9WXYZ

我只是我被困在究竟如何使所有这些角色类和任何帮助都非常感谢。

+0

你想做的事情不清楚。显示输入值意味着你在散列或文件中有什么,以及你想如何得到输出,对你得到答案和为我们提供正确的解决方案会更有帮助。 – serenesat

解决这个问题的方法是编写一个函数,将您的“事物”减少到它们的通用组件。国际海事组织做到这一点,最好的方法是使用散列:

my %num_to_letter = (
    0 => [], 
    1 => [], 
    2 => [ "A", "B", "C" ], 
    3 => [ "D", "E", "F" ], 
    4 => [ "G", "H", "I" ], 
    5 => [ "J", "K", "L" ], 
    ## etc. 

); 

my %letter_to_num; 
foreach my $key (keys %num_to_letter) { 
    foreach my $element (@{$num_to_letter{$key}}) { 
     $letter_to_num{lc($element)} = lc($key); 
    } 
} 
print Dumper \%letter_to_num; 

这将创建一个地图,字母或数字地图到原来的 - 有点像这样:

$VAR1 = { 
      'b' => '2', 
      'g' => '4', 
      'e' => '3', 
      'i' => '4', 
      'a' => '2', 
      'j' => '5', 
... 

注意 - 你可以做这一手,但我更喜欢从顶部地图生成,因为我认为它看起来更整洁。请注意 - 我们使用lc来小写所有内容,因此这会变得不区分大小写。这可能值得看看fc - 这是一个类似的工具,但处理国际字符。 (在这个例子中不相关,虽然)

然后你“减少”搜寻和“目标”,以他们的共同的价值观:

sub normalise { 
    my ($input) = @_; 

    #join with no delimiter. 
    return join ('', 
      #look up $_ (each letter) in $letter_to_num 
      #if not present, use // operator to return original value. 
      #this means we get to turn numbers into letters, 
      #but leave things that are already numbers untouched. 
      map { $letter_to_num{lc($_)} // $_ } 
        #split the input line into characters. 
        split (//, $input) 
      ); 
} 

print normalise ("DAD"),"\n"; ## 323 

,然后比较一个顶着一个:

my $search   = "DAD"; 
my $normalised_search = normalise($search); 
print "Searching for: \"$normalised_search\"\n"; 

my $number_to_match = '00533932388'; 
my $string_to_match = "daddyo"; 

print "Matches number\n" 
    if normalise($number_to_match) =~ m/$normalised_search/; 
print "Matches string\n" 
    if normalise($string_to_match) =~ m/$normalised_search/; 
+0

++简单和真实的Perl - 我的答案有点太聪明。为了改善我的反应,我开始考虑一种简单的方法来确定与小键盘号码相关联的三个或四个字母中的哪一个被选择。我没有马上拿出任何东西...... :-) –

这是一个几乎程序化的方法,通过使用Hash::MultiValue作弊:

use Hash::MultiValue; # makes reversing and flattening easier 

# build a hash from the phone_keypad array or do it manually! 
my @phone_keypad = qw(0 1 2ABC 3DEF 4GHI 5JKL 6MNO 7PQRS 8TUV 9WXYZ); 
my %num2let = map { /(\d{1})(\w{3,4})/; 
       if ($2) { $1 => [ split('',$2) ] } else { 0 => [] , 1 => [] } 
       } @phone_keypad ; 

# Invert the hash using Hash::MultiValue 
my $num2let_mv = Hash::MultiValue->from_mixed(\%num2let); 
my %let2num = reverse $num2let_mv->flatten ; 

# TOM in numbers - 866 in letters 
my $letters = "TOM" ; 
print join '', $let2num{$_} // $_ for (split('', $letters)), "\n"; 
my $phone_input = "866" ; 
print join '', @{$num2let{$_}}," " for (split('', $phone_input)) , "\n"; 

输出

866 
TUV MNO MNO 

所以这里"TOM"将与"UNO"重叠...我喜欢@索布里克的回答:-)

要使用电话键盘输入搜索联系人名称的数组/列表,我们可以创建一个包含名称及其数字等值的键和值的哈希,然后匹配“转换后”名称相对于输入值:

use Hash::MultiValue; # makes reversing and flattening easier 

my @contacts = <DATA> ; 
chomp @contacts; 

# build a hash from the phone_keypad array or do it manually! 
my @phone_keypad = qw(0 1 2ABC 3DEF 4GHI 5JKL 6MNO 7PQRS 8TUV 9WXYZ); 
my %num2let = map { /(\d{1})(\w{3,4})/; 
       if ($2) { $1 => [ split('',$2) ] } else { 0 => [] , 1 => [] } 
       } @phone_keypad ; 

# Invert the hash using Hasj::MultiValue 
my $num2let_mv = Hash::MultiValue->from_mixed(\%num2let); 
my %let2num = reverse $num2let_mv->flatten ; 

# create key/value pairs for contact database 
my %contacts2nums ; 
for $contact (@contacts) { 
    $contacts2nums{$contact} = join "", 
    map { $let2num{$_} } split('', uc $contact); 
} 

my $phone_input = "866"; 

for my $contact (keys %contacts2nums) { 
print "The text: \"$contact\" matches the input: \"$phone_input\" \n" 
    if $phone_input eq $contacts2nums{$contact}; 
} 

__DATA__ 
Tom 
Mother 
TIMTOWDI 
DAD 
Gordon 

输出

The text: "Tom" matches the input: "866" 

一个更有组织的方法将包裹在一个功能的转换操作。


附录

有了一个真正的键盘,你也许可以想出一个简单的算法,可以更确定性的关于要与键盘上的数字相关联的信。您可以根据按键的次数遍历数组:例如,两次按下“2”将等于“B”等。你只需要弄清楚如何/何时移动到具有某种超时/等待值的下一个字符。这样你就可以有一个更准确的字符串来进行搜索。