String to Number转换中的性能问题

我有空格分隔的字符串,其中包含数字,如:

"abc123 ws32wd3 y3tg43 5tga89 a1a"

我必须解析字符串以获取每个标记的数字,然后总结从标记中提取的所有数字。 我写了下面的代码,但我认为,如果有大字符串,那么可能存在性能问题。

所以,我的问题是:

  1. 我们如何改进以下代码的性能?

  2. 我们是否有另一种方法来编写以下代码来解决问题?

码:

 public class TestSum { public static int doSum(String str){ String[] sArray = str.split(" "); char[] chr = null; String temp; String number = ""; int sum=0; for(String s : sArray){ chr = s.toCharArray(); for(char c : chr){ temp = String.valueOf(c); if(isNum(temp)){ number = number + temp; } } sum = sum + Integer.parseInt(number); number=""; } return sum; } public static boolean isNum(String nStr){ try{ Integer.parseInt(nStr); return true; }catch(NumberFormatException nfe){ return false; } } public static void main(String[] args) { System.out.println("Sum is "+ TestSum.doSum("abc123 ws32wd3 y3tg43 5tga89 a1a")); } } 

这是我能想到的最快的:

 public static int getSum(String str) { int sum = 0; int exp = 1; for (int i = str.length() - 1; i >= 0; i--) { final char c = str.charAt(i); if (c >= '0' && c <= '9') { sum += (c - '0') * exp; exp *= 10; } else { exp = 1; } } return sum; } 

它从右到左迭代字符串。 多亏了这一点,当它“看到”一个数字时,它可以添加适当的值,具体取决于数字中“看到”的小数位。

使用Caliper进行 基准测试

结果与davecom的基准不同 :

 AUTHOR RUNTIME (NS) HOW MANY TIMES FASTER THAN JUNS ----------------------------------------------------------- Adam 66.221 600 Old 579.873 70 Prabhakaran 20,012.750 2 (2x faster than Juns) Juns 39,681.074 1 

您可以通过消除isNum()方法并使用内置的Character.isDigit()方法来开始提高代码的速度。

您可以通过使用正则表达式从每个标记中提取数字而不是使用循环来进一步提高速度。

祝你好运。

编辑

比较一些答案的表现,似乎@ Prabhakaran的答案比原来慢,而@ OldCurmudgeon的答案更快,而@Adam Stelmaszczyk的答案最快:

 import java.util.*; public class TestSum { public static int doSum(String str){ String[] sArray = str.split(" "); char[] chr = null; String temp; String number = ""; int sum=0; for(String s : sArray){ chr = s.toCharArray(); for(char c : chr){ temp = String.valueOf(c); if(isNum(temp)){ number = number + temp; } } sum = sum + Integer.parseInt(number); number=""; } return sum; } public static boolean isNum(String nStr){ try{ Integer.parseInt(nStr); return true; }catch(NumberFormatException nfe){ return false; } } public static void testSum1(){ String str = "abc123 ws32wd3 y3tg43 5tga89 a1a"; str = str.replaceAll("[^0-9]+", " "); List asList = Arrays.asList(str.trim().split(" ")); int sum=0; for (String string : asList) { sum+=Integer.parseInt(string); } System.out.println(sum); } public static int doSum2(String str) { int sum = 0; // -1 means not started. int start = -1; for ( int i = 0; i < str.length(); i++ ) { char ch = str.charAt(i); if ( Character.isDigit(ch)) { if ( start == -1 ) { // Start of a number. start = i; } } else { if ( start != -1 ) { // End of a number. sum += Integer.parseInt(str.substring(start, i)); start = -1; } } } if ( start != -1 ) { // A number at the end of the string. sum += Integer.parseInt(str.substring(start, str.length())); } return sum; } public static int getSum(String str) { int sum = 0; int exp = 1; for (int i = str.length() - 1; i >= 0; i--) { final char c = str.charAt(i); if (c >= '0' && c <= '9'){ sum += (c - '0') * exp; exp *= 10; } else{ exp = 1; } } return sum; } public static void main(String[] args) { long startTime = System.nanoTime(); TestSum.testSum1(); long endTime = System.nanoTime(); System.out.println("testSum1 took " + (endTime - startTime) + " nanoseconds"); startTime = System.nanoTime(); System.out.println(TestSum.doSum("abc123 ws32wd3 y3tg43 5tga89 a1a")); endTime = System.nanoTime(); System.out.println("doSum took " + (endTime - startTime) + " nanoseconds"); startTime = System.nanoTime(); System.out.println(TestSum.doSum2("abc123 ws32wd3 y3tg43 5tga89 a1a")); endTime = System.nanoTime(); System.out.println("doSum2 took " + (endTime - startTime) + " nanoseconds"); startTime = System.nanoTime(); System.out.println(TestSum.getSum("abc123 ws32wd3 y3tg43 5tga89 a1a")); endTime = System.nanoTime(); System.out.println("getSum took " + (endTime - startTime) + " nanoseconds"); } } 

这是输出

 Davids-MacBook-Air:desktop dave$ javac TestSum.java Davids-MacBook-Air:desktop dave$ java TestSum 299 testSum1 took 1790000 nanoseconds 1379 doSum took 373000 nanoseconds 299 doSum2 took 173000 nanoseconds 299 getSum took 45000 nanoseconds 

为了获得最佳性能,您可以尝试以下方法:

 public static int doSum(String str) { int sum = 0; // -1 means not started. int start = -1; for ( int i = 0; i < str.length(); i++ ) { char ch = str.charAt(i); if ( Character.isDigit(ch)) { if ( start == -1 ) { // Start of a number. start = i; } } else { if ( start != -1 ) { // End of a number. sum += Integer.parseInt(str.substring(start, i)); start = -1; } } } if ( start != -1 ) { // A number at the end of the string. sum += Integer.parseInt(str.substring(start, str.length())); } return sum; } 

我的计算器确认的打印299是123 + 32 + 3 + 3 + 43 + 5 + 89 + 1

  String str = "abc123 ws32wd3 y3tg43 5tga89 a1a"; str = str.replaceAll("[^0-9]+", " "); List asList = Arrays.asList(str.trim().split(" ")); int sum=0; for (String string : asList) { sum+=Integer.parseInt(string); } System.out.println(asList); System.out.println(sum); 

产量

str = [123,32,3,3,43,5,89,1]

sum = 299

更简单的解决方案是解析具有正则表达式\d查找数字的字符串,然后遍历新字符串(仅包含数字)并总结该字符串中的每个符号(数字)。

你甚至不必检查你是否正在总结数字,因为正则表达式会为你做。

我认为为了加快转换速度,您可以使用以下技巧:
数字的int表示=数字的字符表示 – ‘0’

所以int 5 = char 5 – ‘0’
或换句话说
int 5 =’5′ – ‘0’

这是因为ASCII表的索引方式。

我写的一些(未经测试的)代码超级快速地说明:

 for(int i=0; i