2009-09-02 27 views
17

Trong kinh nghiệm hạn chế của tôi, tôi đã có một số dự án đã có một loại chuỗi tiện ích chuỗi với các phương thức để xác định xem một chuỗi ký tự có phải là một số hay không. Ý tưởng luôn luôn giống nhau, tuy nhiên, việc thực hiện đã khác nhau. Một số bao quanh một nỗ lực phân tích cú pháp với try/catchThực hiện tốt nhất cho phương thức isNumber (string)

public boolean isInteger(String str) { 
    try { 
     Integer.parseInt(str); 
     return true; 
    } catch (NumberFormatException nfe) {} 
    return false; 
} 

và những người khác phù hợp với regex

public boolean isInteger(String str) { 
    return str.matches("^-?[0-9]+(\\.[0-9]+)?$"); 
} 

Là một trong những phương pháp tốt hơn so với người kia? Cá nhân tôi thích sử dụng cách tiếp cận regex, vì nó ngắn gọn, nhưng nó sẽ thực hiện ngang bằng nếu được gọi trong khi lặp lại, nói, một danh sách của một vài trăm nghìn dây?

Lưu ý: Vì tôi khá mới với trang web, tôi không hiểu đầy đủ về hoạt động kinh doanh Wiki cộng đồng này, vì vậy nếu điều này thuộc về tôi, tôi sẽ sẵn sàng chuyển nó.

EDIT: Với tất cả các đề xuất TryParse tôi đã chuyển mã điểm chuẩn của Asaph (cảm ơn bài đăng tuyệt vời!) Cho C# và thêm phương thức TryParse. Và dường như, TryParse thắng tay. Tuy nhiên, cách tiếp cận cố gắng nắm lấy một khoảng thời gian điên rồ. Đến mức tôi nghĩ tôi đã làm điều gì đó sai! Tôi cũng đã cập nhật regex để xử lý các điểm âm và thập phân.

Kết quả cho cập nhật, C# mã chuẩn:

00:00:51.7390000 for isIntegerParseInt 
00:00:03.9110000 for isIntegerRegex 
00:00:00.3500000 for isIntegerTryParse 

Sử dụng:

static bool isIntegerParseInt(string str) { 
    try { 
     int.Parse(str); 
     return true; 
    } catch (FormatException e){} 
    return false; 
} 

static bool isIntegerRegex(string str) { 
    return Regex.Match(str, "^-?[0-9]+(\\.[0-9]+)?$").Success; 
} 

static bool isIntegerTryParse(string str) { 
    int bob; 
    return Int32.TryParse(str, out bob); 
} 
+0

Tôi nghĩ TryParse là cách tốt nhất –

+1

Đầu vào mong đợi của bạn là gì? Bạn có mong đợi rằng 99% thời gian chuỗi * sẽ * là một con số không, và chỉ 1% thời gian * * sẽ không *? Có còn đường nào khác không? Bạn muốn tối ưu hóa chi nhánh mã thực sự sẽ được thực hiện trong hầu hết các trường hợp. –

+0

Đã thêm, sau đó xóa thẻ C#. :) –

Trả lời

13

Tôi vừa chạy một số điểm chuẩn về hiệu suất của 2 phương pháp này (Trên Macbook Pro OSX Leopard Java 6). ParseInt nhanh hơn. Đây là kết quả:

This operation took 1562 ms. 
This operation took 2251 ms. 

Và đây là mã chuẩn của tôi:


public class IsIntegerPerformanceTest { 

    public static boolean isIntegerParseInt(String str) { 
     try { 
      Integer.parseInt(str); 
      return true; 
     } catch (NumberFormatException nfe) {} 
     return false; 
    } 

    public static boolean isIntegerRegex(String str) { 
     return str.matches("^[0-9]+$"); 
    } 

    public static void main(String[] args) { 
     long starttime, endtime; 
     int iterations = 1000000; 
     starttime = System.currentTimeMillis(); 
     for (int i=0; i<iterations; i++) { 
      isIntegerParseInt("123"); 
      isIntegerParseInt("not an int"); 
      isIntegerParseInt("-321"); 
     } 
     endtime = System.currentTimeMillis(); 
     System.out.println("This operation took " + (endtime - starttime) + " ms."); 
     starttime = System.currentTimeMillis(); 
     for (int i=0; i<iterations; i++) { 
      isIntegerRegex("123"); 
      isIntegerRegex("not an int"); 
      isIntegerRegex("-321"); 
     } 
     endtime = System.currentTimeMillis(); 
     System.out.println("This operation took " + (endtime - starttime) + " ms."); 
    } 
} 

Ngoài ra, lưu ý rằng regex của bạn sẽ từ chối số âm và phương pháp parseInt sẽ chấp nhận chúng.

+0

Điều gì về int.TryParse()? Chúng ta có thể giả định rằng nó là chính xác như nhau về hiệu suất như là thử/bắt đầu tiên? –

+0

Than ôi, đây không phải là mã C#! lol! –

+6

Sự hiểu biết của tôi rằng bạn chỉ nên biên dịch regex một lần, sau đó gọi pattern.matcher (s) .matches(). Điều đó nên nhanh hơn xây dựng regex mỗi lần. Ngoài ra, kiểm tra của bạn có thể hoạt động khác nhau tùy thuộc vào chuỗi đầu vào. Nếu hầu hết thời gian bạn không nhận được ints, tôi đoán là regex nên nhanh hơn. –

2

Một số ngôn ngữ, như C#, có một TryParse (hoặc tương đương) mà làm việc khá tốt cho một cái gì đó như thế này.

public boolean IsInteger(string value) 
{ 
    int i; 
    return Int32.TryParse(value, i); 
} 
2

Cá nhân tôi sẽ làm điều này nếu bạn thực sự muốn đơn giản hóa nó.

public boolean isInteger(string myValue) 
{ 
    int myIntValue; 
    return int.TryParse(myValue, myIntValue) 
} 
3

Nếu hiệu suất tuyệt đối là quan trọng, và nếu bạn đang chỉ kiểm tra cho số nguyên (không phải số dấu phảy) Tôi nghi ngờ rằng iterating trên mỗi nhân vật trong chuỗi, trả về false nếu bạn gặp phải một cái gì đó không nằm trong phạm vi 0- 9, sẽ nhanh nhất.

RegEx là giải pháp đa năng hơn nên có thể sẽ không hoạt động nhanh như vậy đối với trường hợp đặc biệt đó. Một giải pháp mà ném một ngoại lệ sẽ có một số chi phí phụ trong trường hợp đó. TryParse sẽ là hơi chậm hơn nếu bạn không thực sự quan tâm đến giá trị của số đó, dù đó có phải là số hay không, vì việc chuyển đổi sang một số cũng phải diễn ra.

Đối với bất kỳ điều gì ngoài vòng lặp bên trong được gọi nhiều lần, sự khác biệt giữa tất cả các tùy chọn này sẽ không đáng kể.

0

Tôi sử dụng điều này nhưng tôi thích sự khắt khe của Asaph trong bài đăng của anh ấy.

public static bool IsNumeric(object expression) 
{ 
if (expression == null) 
return false; 

double number; 
return Double.TryParse(Convert.ToString(expression, CultureInfo.InvariantCulture), NumberStyles.Any, 
NumberFormatInfo.InvariantInfo, out number); 
} 
1

Sử dụng .NET, bạn có thể làm một cái gì đó như:

private bool isNumber(string str) 
{ 
    return str.Any(c => !char.IsDigit(c)); 
} 
+3

Điều này sẽ cho bạn biết rằng -4 không phải là một số, nhưng tôi khá chắc chắn rằng nó là. –

2

Bạn có thể tạo ra một phương pháp mở rộng cho một chuỗi, và làm cho toàn bộ quá trình tìm sạch ...

public static bool IsInt(this string str) 
{ 
    int i; 
    return int.TryParse(str, out i); 
} 

Sau đó, bạn có thể thực hiện những điều sau trong mã thực tế của mình ...

if(myString.IsInt()).... 
4

Dưới đây là cách chúng ta làm điều này:

public boolean isNumeric(String string) throws IllegalArgumentException 
{ 
    boolean isnumeric = false; 

    if (string != null && !string.equals("")) 
    { 
     isnumeric = true; 
     char chars[] = string.toCharArray(); 

     for(int d = 0; d < chars.length; d++) 
     { 
     isnumeric &= Character.isDigit(chars[d]); 

     if(!isnumeric) 
     break; 
     } 
    } 
    return isnumeric; 
} 
+0

isNumeric không giống với isNumber. Do đó sự khác biệt trong việc thực hiện. –

1
public static boolean CheckString(String myString) { 

char[] digits; 

    digits = myString.toCharArray(); 
    for (char div : digits) {// for each element div of type char in the digits collection (digits is a collection containing div elements). 
     try { 
      Double.parseDouble(myString); 
      System.out.println("All are numbers"); 
      return true; 
     } catch (NumberFormatException e) { 

      if (Character.isDigit(div)) { 
       System.out.println("Not all are chars"); 

       return false; 
      } 
     } 
    } 

    System.out.println("All are chars"); 
    return true; 
} 
3

tôi cần phải refactor code như của bạn để thoát khỏi NumberFormatException. Bộ luật refactored:

public static Integer parseInteger(final String str) { 
    if (str == null || str.isEmpty()) { 
     return null; 
    } 
    final Scanner sc = new Scanner(str); 
    return Integer.valueOf(sc.nextInt()); 
} 

Là một chàng trai 1,4 Java, tôi không biết về java.util.Scanner. Tôi thấy bài viết thú vị này:

http://rosettacode.org/wiki/Determine_if_a_string_is_numeric#Java

Tôi personaly thích giải pháp với các máy quét, rất nhỏ gọn và vẫn có thể đọc được.

+0

Không chắc chắn bạn đang sử dụng phiên bản JDK nào, nhưng 'Scanner.nextInt()' dường như ném 'InputMismatchException'. (ngay cả trong 1.5) – ebyrob

0

Đối với số dài sử dụng này: (JAVA)

public static boolean isNumber(String string) { 
    try { 
     Long.parseLong(string); 
    } catch (Exception e) { 
     return false; 
    } 
    return true; 
} 
1

Đó là thực hiện của tôi để kiểm tra xem một chuỗi được làm bằng chữ số:

public static boolean isNumeric(String string) 
{ 
    if (string == null) 
    { 
     throw new NullPointerException("The string must not be null!"); 
    } 
    final int len = string.length(); 
    if (len == 0) 
    { 
     return false; 
    } 
    for (int i = 0; i < len; ++i) 
    { 
     if (!Character.isDigit(string.charAt(i))) 
     { 
      return false; 
     } 
    } 
    return true; 
} 
0
public static boolean isNumber(String str){ 
     return str.matches("[0-9]*\\.[0-9]+"); 
    } 

để kiểm tra xem số (bao gồm cả float, integer) hoặc không

1

Tôi thích mã:

public static boolean isIntegerRegex(String str) { 
    return str.matches("^[0-9]+$"); 
} 

Nhưng nó sẽ tốt hơn khi tạo mẫu trước khi sử dụng nó:

public static Pattern patternInteger = Pattern.compile("^[0-9]+$"); 
public static boolean isIntegerRegex(String str) { 
    return patternInteger.matcher(str).matches(); 
} 

Áp dụng bằng cách thử nghiệm chúng tôi có kết quả:

This operation isIntegerParseInt took 1313 ms. 
This operation isIntegerRegex took 1178 ms. 
This operation isIntegerRegexNew took 304 ms. 

Với:

public class IsIntegerPerformanceTest { 
    private static Pattern pattern = Pattern.compile("^[0-9]+$"); 

    public static boolean isIntegerParseInt(String str) { 
    try { 
     Integer.parseInt(str); 
     return true; 
    } catch (NumberFormatException nfe) { 
    } 
    return false; 
    } 

    public static boolean isIntegerRegexNew(String str) { 
    return pattern.matcher(str).matches(); 
    } 

    public static boolean isIntegerRegex(String str) { 
    return str.matches("^[0-9]+$"); 
    } 

    public static void main(String[] args) { 
     long starttime, endtime; 
    int iterations = 1000000; 
    starttime = System.currentTimeMillis(); 
    for (int i = 0; i < iterations; i++) { 
     isIntegerParseInt("123"); 
     isIntegerParseInt("not an int"); 
     isIntegerParseInt("-321"); 
    } 
    endtime = System.currentTimeMillis(); 
    System.out.println("This operation isIntegerParseInt took " + (endtime - starttime) + " ms."); 
    starttime = System.currentTimeMillis(); 
    for (int i = 0; i < iterations; i++) { 
     isIntegerRegex("123"); 
     isIntegerRegex("not an int"); 
     isIntegerRegex("-321"); 
    } 
    endtime = System.currentTimeMillis(); 
    System.out.println("This operation took isIntegerRegex " + (endtime - starttime) + " ms."); 
    starttime = System.currentTimeMillis(); 
    for (int i = 0; i < iterations; i++) { 
     isIntegerRegexNew("123"); 
     isIntegerRegexNew("not an int"); 
     isIntegerRegexNew("-321"); 
    } 
    endtime = System.currentTimeMillis(); 
    System.out.println("This operation took isIntegerRegexNew " + (endtime - starttime) + " ms."); 
    } 
} 
1

Tôi nghĩ Nó có thể nhanh hơn các giải pháp trước nếu bạn làm như sau (Java):

public final static boolean isInteger(String in) 
{ 
    char c; 
    int length = in.length(); 
    boolean ret = length > 0; 
    int i = ret && in.charAt(0) == '-' ? 1 : 0; 
    for (; ret && i < length; i++) 
    { 
     c = in.charAt(i); 
     ret = (c >= '0' && c <= '9'); 
    } 
    return ret; 
} 

Tôi chạy cùng mã mà Asaph chạy và kết quả là:

Thao tác này mất 28 ms.

Sự khác biệt rất lớn (so với 1691 ms và 2049 ms -trên máy tính của tôi). Đi trong tài khoản đó phương pháp này không xác nhận nếu chuỗi là null, vì vậy bạn nên làm điều đó trước đây (bao gồm cả chuỗi cắt tỉa)

0

Một phiên bản sửa đổi của câu trả lời trước của tôi:

public static boolean isInteger(String in) 
{ 
    if (in != null) 
    { 
     char c; 
     int i = 0; 
     int l = in.length(); 
     if (l > 0 && in.charAt(0) == '-') 
     { 
      i = 1; 
     } 
     if (l > i) 
     { 
      for (; i < l; i++) 
      { 
       c = in.charAt(i); 
       if (c < '0' || c > '9') 
        return false; 
      } 
      return true; 
     } 
    } 
    return false; 
} 
1

Tôi nghĩ mọi người ở đây thiếu một điểm. Việc sử dụng cùng một mẫu lặp lại có một sự tối ưu hóa rất dễ dàng. Chỉ cần sử dụng một singleton của mô hình. Làm như vậy, trong tất cả các thử nghiệm của tôi, phương pháp try-catch không bao giờ có điểm chuẩn tốt hơn so với phương pháp tiếp cận mẫu. Với một thử nghiệm thành công, try-catch mất gấp đôi thời gian, với một thử nghiệm thất bại, nó chậm hơn 6 lần.

public static final Pattern INT_PATTERN= Pattern.compile("^-?[0-9]+(\\.[0-9]+)?$"); 

public static boolean isInt(String s){ 
    return INT_PATTERN.matcher(s).matches(); 
} 
0

Tôi chỉ cần thêm lớp này để utils tôi:

public class TryParseLong { 
private boolean isParseable; 

private long value; 

public TryParseLong(String toParse) { 
    try { 
     value = Long.parseLong(toParse); 
     isParseable = true; 
    } catch (NumberFormatException e) { 
     // Exception set to null to indicate it is deliberately 
     // being ignored, since the compensating action 
     // of clearing the parsable flag is being taken. 
     e = null; 

     isParseable = false; 
    } 
} 

public boolean isParsable() { 
    return isParseable; 
} 

public long getLong() { 
    return value; 
} 
} 

Để sử dụng nó:

TryParseLong valueAsLong = new TryParseLong(value); 

if (valueAsLong.isParsable()) { 
    ... 
    // Do something with valueAsLong.getLong(); 
} else { 
    ... 
} 

này chỉ phân tích các giá trị một lần.

Nó vẫn sử dụng ngoại lệ và luồng điều khiển theo ngoại lệ, nhưng ít nhất nó đóng gói loại mã đó trong lớp tiện ích và mã sử dụng nó có thể hoạt động bình thường hơn.

Vấn đề với Java so với C#, là C# có giá trị và vượt qua tham chiếu, vì vậy nó có hiệu quả có thể trả về 2 mẩu thông tin; cờ để chỉ ra rằng một cái gì đó có thể phân tích cú pháp hay không, và giá trị được phân tích thực tế. Khi chúng ta reutrn> 1 giá trị trong Java, chúng ta cần phải tạo một đối tượng để giữ chúng, vì vậy tôi đã tiếp cận và đặt cờ và giá trị được phân tích cú pháp trong một đối tượng.

Phân tích thoát có khả năng xử lý hiệu quả và tạo giá trị và gắn cờ trên ngăn xếp và không bao giờ tạo đối tượng này trên heap, vì vậy tôi nghĩ điều này sẽ có tác động tối thiểu đến hiệu suất.

Để suy nghĩ của tôi, điều này mang lại sự thỏa hiệp tối ưu giữa việc kiểm soát lưu lượng-ngoại trừ mã của bạn, hiệu suất tốt và không phân tích cú pháp số nguyên nhiều lần.

0

public static boolean CheckIfNumber (String số) {

for(int i = 0; i < number.length(); i++){ 
     try{ 
      Double.parseDouble(number.substring(i)); 

     }catch(NumberFormatException ex){ 
      return false; 
     } 
    } 
    return true;  
} 

Tôi có vấn đề này trước đây nhưng khi tôi đã có đầu vào một số và sau đó một nhân vật, nó vẫn sẽ trở thành sự thật, tôi nghĩ rằng đây là cách tốt hơn để làm điều đó. Chỉ cần kiểm tra xem mỗi char là một số. Lâu hơn một chút nhưng bạn cần cẩn thận nếu bạn có tình huống người dùng nhập "1abc". Vì một lý do nào đó, khi tôi cố gắng nắm bắt mà không lặp lại, nó vẫn nghĩ đó là một con số như vậy ..

Các vấn đề liên quan