2012-01-27 59 views
7

如何檢查一個字符串是代表一個長整數,一個雙整數還是一個常規字符串?我需要這樣做,因爲此值需要根據其類型在數據庫中編入索引。目前我正在通過嘗試解析字符串和檢查異常來做到這一點,但由於代碼被非常頻繁地調用,所以我想知道是否有更高效的方法來執行此操作。我的代碼目前看起來是這樣的:如何檢查字符串是否代表什麼類型的數字?

String value = ...; 
// For example, could be "213678", "654.1236781", or "qwerty12345" 

try { 
    Long longValue = Long.parseLong(value); 
    // Index 'longValue' in the database 
} catch (NumberFormatException parseLongException) { 
    try { 
     Double doubleValue = Double.parseDouble(value); 
     // Index 'doubleValue' in the database 
    } catch (NumberFormatException parseDoubleException) { 
     // Index 'value' in the database 
    } 
} 

編輯:

我只是做了一個快速的基準測試按@ user949300的建議,使用正則表達式的模式,它的性能比上面的異常處理代碼略勝一籌。下面是萬一別人的代碼,發現它有用:

Pattern longPattern = Pattern.compile("^[-+]?[0-9]+$"); 
Pattern doublePattern = Pattern.compile("^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"); 

// Check for long regex pattern before the double regex pattern 
// since the former is a strict subset of the latter 
if (longPattern.matcher(value).matches()) { 
    // Perform indexing for long in the database 
} else if (doublePattern.matcher(value).matches()) { 
    // Perform indexing for double in the database 
} else { 
    // Perform indexing for string in the database 
} 

這裏是檢查了50 000個,其中的類型大致細分爲50個%多頭,10個%雙打,40名%的字符串(代表工作量的基準測試結果我的應用程序進程):

--- Exception handling code --- 
STRING - actual: 19861, found: 19861 
DOUBLE - actual: 4942, found: 4942 
LONG - actual: 25197, found: 25197 
Time taken: 2561 ms 

--- Regex pattern matching code --- 
STRING - actual: 19861, found: 19861 
DOUBLE - actual: 4942, found: 4942 
LONG - actual: 25197, found: 25197 
Time taken: 1565 ms 
+0

如果您正在使用'java 7'而不是看看[multi-catch-blocks-for-exceptions](http://extreme-java.blogspot.com/2011/05/jdk-7 -multi-catch-blocks-for-exceptions.html) – RanRag 2012-01-27 23:38:16

+0

@RanRag我看不出在這種情況下multi-catch-blocks是如何有用的。第二個捕獲是在第一個catch塊之內 - 而不是在之後。 – emory 2012-01-27 23:54:53

+0

你是對的我沒有看到。 – RanRag 2012-01-27 23:55:28

回答

3

您是否考慮過正則表達式?

如果字符串包含比其他任何東西 - (開頭)和0-9或者,它是一個字符串。 (注 - 這忽略國際化和科學記數法 - 他們問題?)

否則,它包含了一個,它是一個雙。 (那麼,你應該只測試一個。,但這是一個開始)

否則,它是一個長。

出於偏執狂,我仍然可能會檢查異常,但這可能是一種更快的方法。

補充說明我猜測測試正則表達式比拋出各種解析例程的異常更快,但這可能並不是真的。你應該做一些測試。

+0

我的印象是,正則表達式會更慢,但只是做了一個快速的基準測試練習,它使用正則表達式模式匹配多個長度和雙精度,結果會稍微快一點。我已經將此代碼與基準測試結果一起添加到了我的問題中。 – Dawood 2012-01-28 05:18:38

+0

謝謝你做了一個很好的基準。 – user949300 2012-01-28 05:41:34

2

據我所知,除此之外,沒有其他的方法可以做到。我建議你按照最常見到最不常見的順序對它們進行解析,以儘可能快地做到這一點。

如果你有超過3種可能的類型,你將會有一個深邃而醜陋的try-catch巢,但從技術上講,它比將每個解析嘗試分解成自己的方法要快;這裏的權衡是你想要代碼清晰還是更快執行 - 這聽起來像你可能想要後者。

+0

如果我正確地理解了你,那麼按照出現頻率的順序進行解析將不起作用,因爲** String **表示將是** Double **的嚴格超集,而這又將是** Long * *。如果一個值應該很長,它仍然會成功解析爲double而不會引發異常。 – Dawood 2012-01-28 01:46:26

+0

@達伍德:你說得對。我的觀點是,應該考慮你解析的順序,以便你可以(希望)避免一些工作。 – 2012-01-28 01:51:10

1

你也許能夠得到一些改善的只是檢查非數字來檢測長(特別是如果你能排除科學記數法例如1e12)。

Long.parseLong()代表們,在任何數量的基礎工作,所以小數,唯一的方法可能會快一點的一般方法。

不要忘了減號,如果這些是你的數據可能......

雙打是很難,因爲654.1236871是有效的,但654.12.36.87...1不大,但它們包含相同的字符集。因此可能需要完整解析。

1

你的代碼看起來不錯。

做一些分析,如果在此基礎上你會發現你的代碼速度太慢,那麼你可以考慮一下潛在的優化(如簡單的循環,看看是否所有字符是數字)。

不要試圖剖析前,優化你的代碼。特別是在像java這樣的語言中。

1

一種可能性是java.io.StreamTokenizer中:

Reader r = new StringReader(value); 
StreamTokenizer st = new StreamTokenizer(r); 
int tokenType = st.nextToken(); 
double number; 
String word; 
switch (tokenType) { 
    case StreamTokenizer.TT_NUMBER: // it's a number 
     number = st.nval; break; 
    case StreamTokenizer.TT_WORD: // it's a string 
     word = st.sval; break; 
} 

它可以是一種棘手,雖然使用。

0

如果你不需要擔心你Longs被否定,你也許可以使用NumberUtils.isDigits()NumberUtils.isNumber()從Apache下議院Lang庫。

if(NumberUtils.isDidgets(string)){ 
    //Index long 
} else if(NumberUtils.isNumber(string)){ 
    //Index double 
} else { 
    //Index string 
} 
相關問題