Home > Articles > Web Development > Perl

Like this article? We recommend

Like this article? We recommend

The PhoneToWord Module

Now we can begin stepping through the module that will do all the work for us.

    01: package PhoneToWord;

Line 1 defines our package name. This is the name of our module, as well.

    02: use strict;
    03: use Text::Ispell qw(spellcheck);

Lines 2 and 3 use() the strict pragma and Text::Ispell module, respectively. The strict pragma will turn on compile-time restrictions such as no barewords, soft references, and ensuring that we declare all our variables. Using the strict pragma is a good thing to do because it helps catch you when trying to do something which is not-so-good.

The Text::Ispell module is being used in line 3, as well as importing the spellcheck() method. This is the method that will be used to see if words that are able to be made with number combinations are actual words (or at least a word in your local dictionary file).

    04: sub new {
    05:   my ($class,$num) = @_;
    06:   my $self = {};
    07:   bless $self, $class;

Lines 4 through 7 begin our new() method. The new() method is what will be used to instantiate a new PhoneToWord object. Line 3 takes the two arguments that are passed when instantiation occurs. The first one will be the name of the package, or class. This will be a 'PhoneToWord' because it is the package name of this module. The second argument is the telephone number we want to work with. Line 6 defines the variable $self as an array reference. This will be the building block of our object as we go along. Finally, line 7 bless()' $self into class $class. Huh? Well, it is basically turning the $self variable into an instance of a PhoneToWord object. This is especially important if someone were to subclass this module to add their own functionality; for example, to add a way to check area codes or international numbers.

    08:   my @numbers = ([qw(0)], # No letters for 0
    09:       [qw(1)], # ditto
    10:       [qw(A B C)],
    11:       [qw(D E F)],
    12:       [qw(G H I)],
    13:       [qw(J K L)],
    14:       [qw(M N O)],
    15:       [qw(P Q R S)],
    16:       [qw(T U V)],
    17:       [qw(W X Y Z)]
    18:      );

Lines 8 to 18 create a list of lists with the important alphanumeric information. There are 10 entries, one for each number on the telephone, starting with 0. Each entry is an anonymous array containing the possible letters (or numbers, for 0 and 1) for the corresponding telephone digit. For example, the 4th indices (not element!) corresponds with the 4; and holds the letters G, H, and I. We will be using this to find out what the possible letters are for each digit in the telephone number.

    19:   $num =~ s/\D//g;
    20:   my @nums = split //, $num;

Line 19 removes all non-digits from the telephone number. This should give us a string of 7 digits to work with. Line 20 then creates a list of the individual numbers.

    21:   $self->{THREE} = [$numbers[$nums[0]], $numbers[$nums[1]], 
                     $numbers[$nums[2]]];
    22:   $self->{FOUR} = [$numbers[$nums[3]], $numbers[$nums[4]], 
                     $numbers[$nums[5]], $numbers[$nums[6]]];
    23:   $self->{SEVEN} = [$self->{THREE}, $self->{FOUR}];

Lines 21, 22, and 23 create properties in our object that store the values of various numbers letter representations. Line 21 creates one call THREE, which contains the first three. Lines 22 and 23 create ones named FOUR and SEVEN, respectively. For example, if the telephone number is 555-1212, the values of these properties would be like so:

    THREE: [[qw(J K L)] [qw(J K L)] [qw(J K L)]]
    FOUR: [[qw(1)] [qw(A B C)] [qw(1)] [qw(A B C)]]
    SEVEN: [[qw(J K L)] [qw(J K L)] [qw(J K L)] [qw(1)] [qw(A B C)] [qw(1)]
[qw(A B C)]

Now, these properties contain the possible letter combinations for each segment of the telephone number, and the entire number itself. Now that we have these things nicely separated, we will need to write the methods that will permute the combinations. More on this in a moment.

    24:   return $self;
    25: }

Lines 24 and 25 finish off the new() method by returning the object and closing the braces. Now, on to the really fun stuff!

    26: sub first_three {
    27:   my $self = shift;
    28:   my @combos = $self->permute(@{$self->{THREE}});
    29:   my @retval = $self->get_words(\@combos, @{$self->{THREE}});
    30:   return wantarray ? @retval : \@retval;
    31: }

Ok, so I lied. We aren't really to the fun stuff just yet. We are accessing the fun stuff. Lines 26 to 31 is the first_three() method. This is the method to call when you want to get any words that are made of the first three numbers. Line 27 gets the first argument (and only argument) passed to the method, which will be a reference to the object. We save this value in the $self variable because it refers to itself. Next, line 28 calls the permute() method, and passes the values of the first three alpha combinations (hence, the name first_three()). This method, which will be covered shortly, returns an array of possible combinations. Actually, it returns all the combinations. In line 29, a reference to the list returned in line 28 is passed, along with the original list, to the get_words() method. This method, also explained a little later on, is what will actually see if the letter combinations are really words. Finally, line 30 returns the final results of possible words. wantarray() is used to account for calling scripts that desire both arrays and array references in return.

    32: sub last_four {
    33:   my $self = shift;
    34:   my @combos = $self->permute(@{$self->{FOUR}});
    35:   my @retval = $self->get_words(\@combos, @{$self->{FOUR}});
    36:   return wantarray ? @retval : \@retval;
    37: }

    38: sub seven {
    39:   my $self = shift;
    40:   my @combos = $self->permute(@{$self->{SEVEN}});
    41:   my @retval = $self->get_words(\@combos, @{$self->{SEVEN}});
    42:   return wantarray ? @retval : \@retval;
    43: }

Lines 32 to 43 make up the last_four() and seven() methods. These methods do the same thing as the first_three() method, but for the last four and all seven digits. Ok, now on to the fun stuff, honest!

    44: sub permute {
    45:   my $self = shift;
    46:   my @arrays = @_;
    47:   my @lengths;
    48:   for my $array_ref (@arrays) {
    49:       push @lengths, scalar @$array_ref;
    50:   }
    51:   return $self->combine(@lengths);
    52: }

Lines 44 to 52 comprise the permute() method. This method goes through the given list of single-letter combinations. Line 48 goes through the array of array references (described above as THREE, FOUR and SEVEN), takes the length of each reference, and pushes it onto the @lengths array. So, if the permute() method was given an array that looks like the following:

     [[qw(J K L)] [qw(J K L)] [qw(J K L)]]

The @lengths array would look like this:

    (3, 3, 3)

If the original array looked like (for example, the numbers 755):

     [[qw(P Q R S)] [qw(J K L)] [qw(J K L)]]

Then the @lengths array would look like this:

    (4, 3, 3)

So, in essence, it is figuring out how many letters are available in each slot. This is needed for the combine() method, which is called in line 51.

    53: sub combine {
    54:   my $self = shift;
    55:   my $length = shift;
    56:   my @results;
    57:   for (0 .. ($length - 1)) {
    58:       if (@_) {
    59:         foreach my $result ($self->combine(@_)) {
    60:           push @results, $_ . $result;
    61:         }
    62:       } else {
    63:         push @results, $_;
    64:       }
    65:   }
    66:   return @results;
    67: }

Lines 53 through 67 is the combine() method. It is a recursive method because it calls itself when needed. The functionality of this method is to take the results from the permute() method and combine all of the permutations. Taking the example above (4, 3, 3), the combinations would look like the following (counts are zero-based):

000 001 002 010 011 012 020 021 022 100 101 102 110 111 112 120 121 122 200 201 202 210 211 212 220 221 222 300 301 302 310 311 312 320 321 322

Can you start to see what is happening? If we take a subset of the above list of permutations and match them with the corresponding letters, it would look like this:

    222 - RLL
    300 - SJJ
    301 - SJK
    302 - SJL

Of course, none of these are words, but you should get the idea of how we are turning the numbers into letters into words. So, at the end of this, we are given an array of these numeric combinations, which our methods— (first_three(), last_four(), and seven())—store in the @combo array. These arrays are then passed to the get_words() method, which will map the number permutations to their letter combinations, as well as check them against the dictionary file with Text::Ispell.

    68: sub get_words {
    69:   my $self = shift;
    70:   my $combos = shift;
    71:   my @uses = @_;
    72:   my @ret;
    73:   my $words = join " ", $self->show_text($combos, @uses);
    74:   eval {
    75:       for my $word (spellcheck($words)) {
    76:           if ($word->{type} =~ /(?:ok|compound)/) {
    77:               push @ret, $word->{term};
    78:           }
    79:       }
    80:   };
    81:   return @ret;
    82: }

Lines 68 to 82 define the get_words() method, which is called by the three accessor methods: first_three(), last_four(), and seven(). It takes two arguments: an array reference with all the combinations gathered from the permute() and combine() methods, as well as the array of possible letters (which we stored in the appropriate object property THREE, FOUR, or SEVEN).

On line 73, a new scalar, $words, is created by joining the results of the show_text() method by spaces. We will cover the show_text() method in moment, but in order for the rest of this method to make sense, just know that it returns an array of possible words. So, if the three numbers 344 were being inspected, the $words scalar would look something like this:

    "DGG DGH DGI DHG DHH DHI DIG DIH DII EGG EGH EGI EHG EHH EHI EIG EIH
     EII FGG FGH FGI FHG FHH FHI FIG FIH FII"

That is the possible combinations of letters corresponding to the numbers 344. Next, lines 74 to 80 is an eval() that will use Text::Ispell::spellcheck to see if these are actual words. Line 75 starts looping through the list returned by spellcheck(). The spellcheck() method will return a hash reference for each of the possible words passed to it. As we iterate through this list, line 76 inspects the type keyword in the hash reference. If the type keyword contains the words 'ok' or 'compound' (meaning it is a compound word), we have a match! We then push() all the matches onto the @ret array. The actual word that matched is stored in the term keyword of the $word hash reference. Once we iterate through all the words, line 81 returns the final list of word matches.

    83: sub show_text {
    84:   my ($self, $combos, @arrays) = @_;
    85:   my @all;
    86:   foreach my $combo (@$combos) {
    87:       my $i = 0;
    88:       my $text;
    89:       for my $elem (split'', $combo) {
    90:           $text .= $arrays[$i++]->[$elem];
    91:       }
    92:       push @all, $text;
    93:   }
    94:   return @all;
    95: }

Lines 83 through 95 make up show_text(), which is called in the get_words() method. When this method is called, it is given two arguments: an array reference ($combos) and the array of array references that holds all the possible letters for the original numbers we are trying to match (that is, what is in the THREE, FOUR, or SEVEN object properties).

Lines 86 to 93 iterates through all the possible combinations in $combo. As this happens, another iteration occurs on the $combos array reference. Each element in @$combos is a permutation from the perlmute() method. In line 87, the $i variable is initialized. This will be used as a counter in the coming lines. Line 88 initializes the $text variable, which will be used to create the letter combinations.

Line 89 begins another iteration. This time, we iterate over each number for each number permutation. So, if $combo is 220, these are split apart and assigned to $elem.

Line 90 creates the letter combination. Again, take for example that $combo is 220—first, the 2 will be looked at; then another 2; then 0. As these three iterations happen, $text is appended to, based on the appropriate value of $i and $elem. Here is what it would look like with 220:

    I is [[qw(D E F)] [qw(G H I)] [qw(G H I)]]
    I is 0
    I is 2
    I is appended with I[2]> which is F
    I is 1
    I is 2 
    I is appended with I[2]> which is I
    I is 2
    I is 0 
    I is appended with I[0]> which is G

In line 92, the word 'FIG' is then pushed onto the @all array, and the next permutation is converted to letters. When this is complete, the final @all array is returned on line 94.

Now, line 75 may make more sense because you can see where and how each word that is passed to spellcheck() gets created.

    96: 1;

Line 96 makes sure that our module returns a true value when it is being use()d.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020