如何将字母数字电话号码转换为数字

更新:

我的实用程序的最终版本如下所示:

StringBuilder b = new StringBuilder(); for(char c : inLetters.toLowerCase().toCharArray()) { switch(c) { case '0': b.append("0"); break; case '1': b.append("1"); break; case '2': case 'a': case 'b': case 'c': b.append("2"); break; case '3': case 'd': case 'e': case 'f': b.append("3"); break; case '4': case 'g': case 'h': case 'i': b.append("4"); break; case '5': case 'j': case 'k': case 'l': b.append("5"); break; case '6': case 'm': case 'n': case 'o': b.append("6"); break; case '7': case 'p': case 'q': case 'r': case 's': b.append("7"); break; case '8': case 't': case 'u': case 'v': b.append("8"); break; case '9': case 'w': case 'x': case 'y': case 'z': b.append("9"); break; } } return builder.toString(); 

原始问题:

我正在承担将字母数字电话号码转换为数字串的简单任务。 例如,1-800-HI-HAXOR将变为1-800-44-42967。 我最初的尝试是创建一个令人讨厌的开关声明,但我喜欢更优雅,更有效的解决方案。 这是我得到的:

 for(char c : inLetters.toLowerCase().toCharArray()) { switch(c) { case '0': result+="0"; break; case '1': result+="1"; break; case '2': case 'a': case 'b': case 'c': result+="2"; break; case '3': case 'd': case 'e': case 'f': result+="3"; break; case '4': case 'g': case 'h': case 'i': result+="4"; break; case '5': case 'j': case 'k': case 'l': result+="5"; break; case '6': case 'm': case 'n': case 'o': result+="6"; break; case '7': case 'p': case 'q': case 'r': case 's': result+="7"; break; case '8': case 't': case 'u': case 'v': result+="8"; break; case '9': case 'w': case 'x': case 'y': case 'z': result+="9"; break; } } 

谢谢!

switch语句并不是那么糟糕。 您的算法与电话号码的长度成线性关系。 代码是可读的,很容易通过检查validation。 除了添加处理错误的default情况之外,我不会惹它。 (我不是Java程序员,所以请原谅我,如果它被称为其他东西。)

如果必须加快速度,则按字符索引的预初始化表将避免除基本错误检查之外的任何比较。 您甚至可以通过复制表格中的值来避免大小写转换( digit['A'] = digit['a'] = "2"; )。 初始化表的成本将按总转化次数摊销。

您可以使用Apache Commons Lang StringUtils执行此操作,如下所示:

 String output = StringUtils.replaceChars(StringUtils.lowerCase(input), "abcdefghijklmnopqrstuvwxyz", "22233344455566677778889999"); 

当然,假设速度不是您主要考虑的问题,而您需要一个紧凑的解决方案;)

使用Map ,其中键是字母和数字,值是键盘上的数字。 (因此每个键盘编号将被三个或四个字母和一个数字编入索引)。

 Map keypad = new HashMap(); ... StringBuilder buf = new StringBuilder(inLetters.length()); for (int idx = 0; idx < inLetters.length(); ++idx) { Character ch = keypad.get(inLetters.charAt(idx)); if (ch != null) buf.append(ch); } 

更新:我很好奇手动编码的查找表是否比密集的switch案例表现更好。 在我的临时测试中,我发现以下代码是我能想到的最快的代码:

  private static final char[] lut = "0123456789:;<=>?@22233344455566677778889999[\\]^_`22233344455566677778889999".toCharArray(); private static final char min = lut[0]; String fastest(String letters) { int n = letters.length(); char[] buf = new char[n]; while (n-- > 0) { int ch = letters.charAt(n) - min; buf[n] = ((ch < 0) || (ch >= lut.length)) ? letters.charAt(n) : lut[ch]; } return new String(buf); } 

令人惊讶的是,它的速度是使用switch语句(编译为tableswitch指令)的类似代码的两倍多。 这只是为了好玩,请注意,但是在我的笔记本电脑上,在单个线程中运行,我可以在大约1.3秒内转换1000万个10个字母的“数字”。 我真的很惊讶,因为据我所知,一个tableswitch以基本相同的方式运行,但我预计它会更快,因为它是一个JVM指令。

当然,除非我只收到我可以转换的无限电话号码的每一笔付款,否则我绝不会写这样的代码。 交换机更具可读性,运行良好,并且可能在未来的某些JVM中获得免费的性能提升。

远远地,对原始代码的最大改进来自于使用StringBuilder而不是连接字符串,并且这不会损害代码的可读性。 使用charAt而不是将输入转换为char[]也使代码更简单,更容易理解提高性能。 最后,附加char文字而不是String文字( '1'而不是"1" )是一种性能改进,有助于提高可读性。

怎么样简单:

  String convert(String inLetters) { String digits = "22233344455566677778889999"; String alphas = "abcdefghijklmnopqrstuvwxyz"; String result = ""; for (char c : inLetters.toLowerCase().toCharArray()) { int pos = alphas.indexOf(c); result += (pos == -1 ? c : digits.charAt(pos)); } return result; } 

如果你想要一个不强迫你枚举所有字母的解决方案,你可以这样做:

 char convertedChar = c; if (Character.isLetter(c)) { //lowercase alphabet ASCII codes: 97 (a)-122 (z) int charIndex = ((int)c) - 97; //make adjustments to account for 's' and 'z' if (charIndex >= 115) { //'s' charIndex--; } if (charIndex == 121) { //'z'-1 charIndex--; } convertedChar = (char)(2 + (charIndex/3)); } result += convertedChar; 

如果你在一个紧密的循环中运行这个10 ^ 9次并且按住它几次,我的赌注是几乎每次它都会在字符串类中深入尝试完成其中一个无辜的“+ =”运算符。

切换语句被编译成与if-else语句类似的forms(每个case语句本质上是伪装的if (c == '...')测试),所以虽然这在视觉上比级联更紧凑,如果是每个测试角色,可能有也可能没有任何真正的表现益处。

您可以通过消除一些比较来简化它。 关键是char是一个整数类型(这就是为什么你可以打开一个char ),所以你可以使用数字比较运算符。 并且’aAssuming你的inLetters字符串只包含字母数字字符,这应该有效…(所有其他字符将保持不变。)

 String result = ""; for (char c : letters.toLowerCase().toCharArray()) { if (c <= '9') result += c; else if (c <= 'c') result += "2"; else if (c <= 'f') result += "3"; else if (c <= 'i') result += "4"; else if (c <= 'l') result += "5"; else if (c <= 'o') result += "6"; else if (c <= 's') result += "7"; else if (c <= 'v') result += "8"; else if (c <= 'z') result += "9"; else result += c; } 

感兴趣的字符具有hex值:'0'= 0x30,'9'= 0x39,'a'= 0x61,以及'z'= 0x7a。

编辑:最好使用StringBuilder和append()来创建字符串,但对于小字符串,它的速度可能不会快得多。 ( Amdahl定律表明,优化代码可以获得的实际加速速度受到在该代码中实际花费的时间百分比的限制。)我只使用连接字符串使算法对OP清晰。