2015-11-01 57 views
2

首先,這是一項家庭作業。我用正則表達式很困難,而且我卡住了。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

回答

2

解決這個問題的方法是編寫一個函數,將您的「事物」減少到它們的通用組件。國際海事組織做到這一點,最好的方法是使用散列:

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 - 我的答案有點太聰明。爲了改善我的反應,我開始考慮一種簡單的方法來確定與小鍵盤號碼相關聯的三個或四個字母中的哪一個被選擇。我沒有馬上拿出任何東西...... :-) –

1

這是一個幾乎程序化的方法,通過使用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」等。你只需要弄清楚如何/何時移動到具有某種超時/等待值的下一個字符。這樣你就可以有一個更準確的字符串來進行搜索。