简体   繁体   中英

Convert letters in phone number to numbers according to phone keypad

I am trying to find the simplest (or at least shortest) method that does the following:

Take any text from an input field and convert it as follows:

abc => 2
def => 3
ghi => 4
...
wxyz => 9

*Any other character that is not part of the English alphabet is converted to '#' (or any other special character).

This may sound simple, but the code can be made very simple and elegant and that is what I am looking for, fewer lines in a php or js/jquery script. If it converts "abc", "def", I can finish the rest.

Build an associative array that maps A onto 2, B onto 2, C onto 2, D onto 3, etc.

Iterate through the string, one character at a time. If a character is found in the array, concatenate it to your output; if not concatenate "#" to the output. You will probably want to convert the string to all uppercase or all lowercase first.

Edited to add: I didn't include code because it appears that the OP knows JavaScript and PHP, and of course, the code would be different, but the principles are the same.

If one is absolutely, positively sure that the string is in ASCII/UTF-8/ISO-8859, one could make use of the fact that the uppercase letters occupy code points 65 to 90 decimal, and that three letters are assigned to each number from 2 to 9 and so compute the result. (Note that Q is missing from US telephones and Z maps to zero.) However, this is not so much elegant as excessively tricky.

Earlier today I was reminded of this:

“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.” -- Brian Kernighan and PJ Plauger, The Elements of Programming Style

You can use str_replace($searchArr, $replaceArr, $string) to replace anything in the "search array" with the corresponding value in the "replacement array". And you can populate those arrays like this:

$string = "dhebfctgddekj";
$pattern = array();
$replacement = array();

for($i = 97; $i < 123; $i++) //Ascii 97 = a to ascii 122 = z
{
   $pattern[] = chr($i); //Convert the ascii to a character
}

$r = array(3,3,3,3,3,4,3,4); //How many characters each number has
$j = 2;

foreach($r as $val)
{
    for($i = 0; $i < $val; $i++)
        $replacement[] = $j;
    $j++;
}

$string2 = str_replace($pattern, $replacement, strtolower($string));

echo $string2;
$subject = '0900ABCDEF'    
$ReplacementPattern = array(
    'a' => '2',
    'b' => '2',
    'c' => '2',
    'd' => '3',
    'e' => '3',
    'f' => '3',
    'g' => '4',
    'h' => '4',
    'i' => '4',
    'j' => '5',
    'k' => '5',
    'l' => '5',
    'm' => '6',
    'n' => '6',
    'o' => '6',
    'p' => '7',
    'q' => '7',
    'r' => '7',
    's' => '7',
    't' => '8',
    'u' => '8',
    'v' => '8',
    'w' => '9',
    'x' => '9',
    'y' => '9',
    'z' => '9',
    '+' => '00',
    ' ' => '',
);
echo str_ireplace(array_keys($ReplacementPattern), array_values($ReplacementPattern), $subject);

One-liner in javascript:

phoneStr.replace(/./g, x => 
    '22233344455566677778889999'[(x.charCodeAt()-65)%32] || x
);

You can do [x.toLowerCase().charCodeAt()-97] if you want to be clearer.

Demo (stick above in appropriate-named function):

> phoneToKeypad('+1-800-abc-WXYZ')
"+1-800-222-9999"

You can also use Array.from(phoneStr, x => x) to work with an Array representation if you need, then .join('') it later back into a string.

Strip dirty inputs (eg hyphens, parentheses, etc.) as appropriate by preprocessing:

phoneStr.replace(/[^0-9*#+a-zA-Z]/g, '').replace( ... etcetc

Of course, you will need to do sanitize such on the server side, so you can't only rely on client-side javascript (unless your server is also in javascript).

The layout of a keypad is referred as ISO/IEC 9995-8 . Do note however that (according to my very cursory research) there are a plethora of international standards, such as the 184-page ETSI ES 202 130 standard in Europe.

Here is a javascript function that I use to convert text to phone keypad number:

const textToKeypadNumber = (text) => {
  const phoneCharMap = {
    a: "2",
    b: "2",
    c: "2",
    d: "3",
    e: "3",
    f: "3",
    g: "4",
    h: "4",
    i: "4",
    j: "5",
    k: "5",
    l: "5",
    m: "6",
    n: "6",
    o: "6",
    p: "7",
    q: "7",
    r: "7",
    s: "7",
    t: "8",
    u: "8",
    v: "8",
    w: "9",
    x: "9",
    y: "9",
    z: "9",
    "+": "00",
    " ": ""
  };
  const _text = text.split("");
  return _text
    .map(char => {
      const number = phoneCharMap[char.toLowerCase()];
      if (number) return phoneCharMap[char.toLowerCase()];
      return char;
    })
    .join("");
}

Use like this:

textToKeypadNumber('1-800-MY-APPLE'); // 1-800-69-27753

To obey ISO/IEC 9995-8 (which is the letter-to-number translation that comes to my mind for this task), PHP's strtr() will work with two compact strings.

If lowercase letters are possible, then call strtoupper() before translating, but whenever I see phone numbers advertised with letters, they are in all-caps.

Code: ( Demo )

$phone = '1300EXAMPLE';
echo strtr(
         $phone,
         'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
         '22233344455566677778889999'
     );
// 13003926753

If you want to sanitize all remaining non-numbers as # , then use preg_replace() :

echo preg_replace(
         '/\D+/',
         '#',
         strtr(
             $phone,
             'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
             '22233344455566677778889999'
         )
     );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM