6.20. Matching AbbreviationsProblem
Suppose you had a list of commands, such as Solution
You can use the following technique if the strings all start with different characters or if you want to arrange the matches so one takes precedence over another, as chomp($answer = <>); if ("SEND" =~ /^\Q$answer/i) { print "Action is send\n" } elsif ("STOP" =~ /^\Q$answer/i) { print "Action is stop\n" } elsif ("ABORT" =~ /^\Q$answer/i) { print "Action is abort\n" } elsif ("LIST" =~ /^\Q$answer/i) { print "Action is list\n" } elsif ("EDIT" =~ /^\Q$answer/i) { print "Action is edit\n" } Or you can use the Text::Abbrev module: use Text::Abbrev; $href = abbrev qw(send abort list edit); for (print "Action: "; <>; print "Action: ") { chomp; my $action = $href->{ lc($_) }; print "Action is $action\n"; } Discussion
The first technique switches the typical order of a match. Normally you have a variable on the left side of the match and a known pattern on the right side. We might try to decide which action the user wanted us to take by saying
Compare the classic
The standard Text::Abbrev module takes a different approach. You give it a list of words, and it returns a reference to a hash whose keys are all unambiguous abbreviations and whose values are the fully expanded strings. So if This technique is commonly used to call a function based on the name of the string the user types in. Do this by using a symbolic reference, like: $name = 'send'; &$name();
But that's scary, because it allows the user to run any function in our program, assuming they know its name. It also runs afoul of that pesky Here's a partial program that creates a hash in which the key is the command name and the value is a reference to the function to call for that command: # assumes that &invoke_editor, &deliver_message, # $file and $PAGER are defined somewhere else. use Text::Abbrev; my($href, %actions, $errors); %actions = ( "edit" => \&invoke_editor, "send" => \&deliver_message, "list" => sub { system($PAGER, $file) }, "abort" => sub { print "See ya!\n"; exit; }, "" => sub { print "Unknown command: $cmd\n"; $errors++; }, ); $href = abbrev(keys %actions); local $_; for (print "Action: "; <>; print "Action: ") { s/^\s+//; # trim leading white space s/\s+$//; # trim trailing white space next unless $_; $actions->{ $href->{ lc($_) } }->(); } The last statement could have been written like this if you're not into tight expressions or need practice typing: $abbreviation = lc($_); $expansion = $href->{$abbreviation}; $coderef = $actions->{$expansion}; &$coderef(); See AlsoThe documentation for the standard Text::Abbrev module (also in Chapter 7 of Programming Perl ); interpolation is explained in the "Scalar Value Constructors" section of perldata (1), and in the "String literals" section of Chapter 2 of Programming Perl |
|