如何将电话簿号码转换为字母[关闭]

Posted

技术标签:

【中文标题】如何将电话簿号码转换为字母[关闭]【英文标题】:How to convert telephone pad numbers to letters [closed] 【发布时间】:2020-06-23 22:48:02 【问题描述】:

我正在尝试编写代码来模拟使用 Ruby 中的multi-tap 电话键盘编写文本消息。这是电话键盘:

  1    2    3
      ABC  DEF

  4    5    6
 GHI  JKL  MNO

  7    8    9
PQRS  TUV  WXYZ

       0
    (space)

我尝试在 Ruby 中将其定义为:(不起作用)

"0" = [" "] # (adds a space)
"1" = [""]  # (adds nothing)
"2" = ["a", "b", "c"]
"3" = ["d", "e", "f"]
"4" = ["g", "h", "i"]
"5" = ["j", "k", "l"]
"6" = ["m", "n", "o"]
"7" = ["p", "q", "r", "s"]
"8" = ["t", "u", "v"]
"9" = ["w", "x", "y", "z"]

我将通过两个示例来解释它是如何工作的。首先我将发送字符串goat。要发送g,我按4 一次。接下来,要发送o,我按6 三次(因为按6 一次将发送m,按6 两次将发送@ 987654331@)。对于a,按一次2,对于t,按一次8。因此我们会发送

466628
g  oat

接下来,考虑cake。通过相同的程序,我们将发送

22225533
  ca k e

这里有问题。解码时,2222 有几种可能性。可能是aaaabb 等等。为了克服这种歧义,在每个数字字符串之后插入一个表示为空格的“暂停”,然后是相同数字的字符串。因此,对于cake,我们会写

222 25533
  c a k e

我已经有了一个带有数字及其对应字母的散列,而且我知道我必须按照数字重复的次数对数字进行排序。 但我不知道我用什么方法。

另外,如果我需要编码(数字到字母),我是否必须使用相同的逻辑?

【问题讨论】:

请查看“How to Ask”、“Stack Overflow question checklist”及其所有链接页面。我们希望看到您尝试解决此问题。目前,您已经向我们提出了您应该解决的要求,并希望我们为您编写代码。 “How do I ask and answer homework questions?”会解释。 @CarySwoveland 这是一个暂停,所以222 可以注册为c。如果没有空格,2222 可以是 aaaaaababaac 或任何其他组合。 g13,我相信@Stefan 和我所做的编辑与您尝试做的一致。如果是这样,您可能希望澄清最后一句话,这是您的原话。如果您澄清该句子以说明您希望仅对文本进行编码,或者同时对文本进行编码和解码,则有可能会重新打开该问题。这一个有趣的问题。 你好@CarySwoveland 和@Stefan!对不起,我花了太长时间,我已经做了很长时间的这些作业,所以我决定花一些时间离开电脑,不久前回来了。我测试了编码和解码解决方案,它们都有效。它鼓励我更深入地研究正则表达式和地图,它帮助我解决了其他作业!非常感谢您花时间帮助我。当我有另一个问题时,我会更加小心。现在我将根据我在此处寻求帮助时取得的进展对其进行编辑。 【参考方案1】:

(当 Cary Swoveland 指出你可能想要解码时,我先有编码部分。现在答案包含两种方式并且变得很长,我希望你不介意)


您的示例代码不起作用。您不能只分配给字符串文字。但是,您可以使用这样的哈希值在 Ruby 中定义您的键盘:

keypad = 
  '0' => [' '],
  '1' => [],        # <- you can leave this out
  '2' => %w[a b c],
  '3' => %w[d e f],
  '4' => %w[g h i],
  '5' => %w[j k l],
  '6' => %w[m n o],
  '7' => %w[p q r s],
  '8' => %w[t u v],
  '9' => %w[w x y z],


解码

要将222 25533 转换为cake,我首先要拆分连续的以空格分隔的数字。您可以使用正则表达式:

parts = '222 25533'.gsub(/(\d)\1*/).map(&:itself)
#=> ["222", "2", "55", "33"]

这可以转换为包含键/次数对的数组:

key_strokes = parts.map  |part| [part[0], part.length] 
#=> [["2", 3], ["2", 1], ["5", 2], ["3", 2]]

可以使用keypad 哈希转换为字母:

letters = key_strokes.map  |key, times| key_pad[key][times - 1] 
#=> ["c", "a", "k", "e"]

需要- 1,因为数组索引是从零开始的。最后,把字母变成单词:

letters.join
#=> "cake"

编码

要将字符转换为击键,我会创建一个基于键盘的哈希,它将每个字符映射到一个键/次数对:

mapping = 
key_pad.each do |key, values|
  values.each.with_index(1) do |char, times|
    mapping[char] = [key, times]
  end
end

mapping
#=> 
#     " "=>["0", 1], "a"=>["2", 1], "b"=>["2", 2], "c"=>["2", 3], "d"=>["3", 1],
#     "e"=>["3", 2], "f"=>["3", 3], "g"=>["4", 1], "h"=>["4", 2], "i"=>["4", 3],
#     "j"=>["5", 1], "k"=>["5", 2], "l"=>["5", 3], "m"=>["6", 1], "n"=>["6", 2],
#     "o"=>["6", 3], "p"=>["7", 1], "q"=>["7", 2], "r"=>["7", 3], "s"=>["7", 4],
#     "t"=>["8", 1], "u"=>["8", 2], "v"=>["8", 3], "w"=>["9", 1], "x"=>["9", 2],
#     "y"=>["9", 3], "z"=>["9", 4]
#   

在上面的哈希中,"c"=&gt;["2", 3] 表示要获得c,您必须按 2 键 3 次。要在 Ruby 中呈现单个键的序列,我们可以使用重复字符串的 String#*

key, times = mapping['c']

key   #=> '2'
times #=> 3

key * times
#=> '222'

获取整个单词(或句子)的击键是将每个字符映射到其各自的哈希值:

parts = 'cake'.each_char.map  |char| mapping[char] 
#=> [["2", 3], ["2", 1], ["5", 2], ["3", 2]]

要渲染实际序列,我们必须首先对同一键的连续运行进行分组:

chunks = parts.chunk_while  |(a, _), (b, _)| a == b .to_a
#=> [
#     [["2", 3], ["2", 1]],
#     [["5", 2]],
#     [["3", 2]]
#   ]

我们现在可以通过空格和没有空格的块连接相同的击键:

chunks.map  |chunk| chunk.map  |k, t| k * t .join(' ') .join
#=> "222 25533"

【讨论】:

我会在早上回来查看,但请看一下问题的最后一句话(我没有触及)。它向我表明,OP 可能想要解码而不是(或除了)编码。如果您有时间,您可能想在任何情况下进行解码。我 @CarySwoveland 你可能是对的,我完全忽略了这一点! (将其添加到我的答案中) @CarySwoveland 好点,但是这个答案已经花了太长时间了,我将把它作为“给读者的练习” :-)【参考方案2】:

给你:

arr = [
  ["0", [" "]],
  ["1", [""]],
  ["2", ["a", "b", "c"]],
  ["3", ["d", "e", "f"]],
  ["4", ["g", "h", "i"]],
  ["5", ["j", "k", "l"]],
  ["6", ["m", "n", "o"]],
  ["7", ["p", "q", "r", "s"]],
  ["8", ["t", "u", "v"]],
  ["9", ["w", "x", "y", "z"]]
]

我一直对包含以下内容感到困惑

  ["1", [""]],

这似乎没有任何用处。但是,如果不是

222 25533

我们用"cake"来表示字符串

222125533

也就是说,如果由相同数字的字符串表示的两个连续字符(例如"222""2")它们将由"1"分隔,而不是由“暂停”,表示作为空间。如果这样做了,我们可以如下编码和解码字符串。

编码

CHAR_TO_DIGITS = arr.each_with_object() do |(num, a),h|
  a.each.with_index(1)  |ltr,i| h[ltr] = num * i 
end
  #=> " "=>"0", ""=>"1", "a"=>"2", "b"=>"22", "c"=>"222",
  #    "d"=>"3", "e"=>"33", "f"=>"333", "g"=>"4", "h"=>"44",
  #    "i"=>"444", "j"=>"5", "k"=>"55", "l"=>"555", "m"=>"6",
  #    "n"=>"66", "o"=>"666", "p"=>"7", "q"=>"77", "r"=>"777",
  #    "s"=>"7777", "t"=>"8", "u"=>"88", "v"=>"888", "w"=>"9",
  #    "x"=>"99", "y"=>"999", "z"=>"9999" 

def encode(plain_text)
  plain_text.each_char.with_object('') do |c,s|
    digits = CHAR_TO_DIGITS[c]
    s << '1' if !s.empty? && digits[0] == s[-1]
    s << digits
  end
end

然后

encoded_1 = encode "cake"
  #=> "222125533"
encoded_2 = encode "my dog has fleas"
  #=> "69990366640442777703335553327777" 

解码

解码更容易。

DIGITS_TO_CHAR = CHAR_TO_DIGITS.invert
  #=> "0"=>" ", "1"=>"", "2"=>"a", "22"=>"b", "222"=>"c",
  #    "3"=>"d", "33"=>"e", "333"=>"f", "4"=>"g", "44"=>"h",
  #    "444"=>"i", "5"=>"j", "55"=>"k", "555"=>"l", "6"=>"m",
  #    "66"=>"n", "666"=>"o", "7"=>"p", "77"=>"q", "777"=>"r",
  #    "7777"=>"s", "8"=>"t", "88"=>"u", "888"=>"v", "9"=>"w",
  #    "99"=>"x", "999"=>"y", "9999"=>"z" 

def decode(encoded_text)
  encoded_text.gsub(/(\d)\1*/, DIGITS_TO_CHAR)
end

然后

decode encoded_1
  #=> "cake"
decode encoded_2
  #=> "my dog has fleas"

这使用String#gsub 的形式,它使用散列来进行替换。另见Hash#invert。

【讨论】:

【参考方案3】:

我首先将“222 25533”转换为数组[[2,3],[2,1],[5,2],[3,2]],其中第一个数字代表一个数字,第二个数字是它的出现次数。 有了这个,你可以很容易地从键盘上找到字母。

【讨论】:

以上是关于如何将电话簿号码转换为字母[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何从纬度和经度获取电话号码 [关闭]

结帐后如何将摩洛哥国家代码添加到 wp woocommerce 中的电话号码? [关闭]

如何在电话号码格式的范围内生成随机数 Postman [关闭]

使用 phonegap 将电话号码和电子邮件添加到 iOS 中的联系人 [关闭]

验证英国电话号码[关闭]

从电话联系人中获取姓名、电话号码和电子邮件地址[关闭]