2012-01-27 16 views
7

Jak mogę sprawdzić, czy ciąg znaków reprezentuje długi, podwójny lub zwykły ciąg znaków? Muszę to zrobić, ponieważ ta wartość musi zostać zaindeksowana w bazie danych zgodnie z jej typem. Obecnie robię to, próbując parsować ciąg i sprawdzając wyjątki, ale ponieważ kod jest wywoływany bardzo często, zastanawiam się, czy jest na to skuteczniejszy sposób. Mój kod aktualnie wygląda tak:Jak sprawdzić, czy i jaki typ numeru reprezentuje ciąg?

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 
    } 
} 

EDIT:

Właśnie zrobiłem szybkie benchmarkingu zgodnie użytkownika @ user949300 sugestii korzystania regex wzorów i wykonywane nieco lepiej niż wyjątkiem kodu obsługi powyżej. Oto kod, w przypadku gdy ktoś inny znajdzie przydatne:

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 
} 

Oto wyniki testów porównawczych dla sprawdzenia 50.000 wpisów w którym przybliżona podział typów wynosi 50% tęskni, 10% dwuosobowych, 40% ciągi (przedstawiciela obciążenia że moje procesy aplikacyjne):

--- 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

Jeśli używasz 'Java 7' niż spojrzeć na [Multi-catch-bloków-for-wyjątkami] (http://extreme-java.blogspot.com/2011/05/jdk-7 -multi-catch-blocks-for-exceptions.html) – RanRag

+0

@RanRag Nie widzę, w jaki sposób blokowanie wielu bloków jest pomocne w tej sytuacji. Drugi połów znajduje się wewnątrz - nie po - pierwszym bloku catch. – emory

+0

Masz rację, nie widziałem tego. – RanRag

Odpowiedz

3

Czy brałeś pod uwagę wyrażenia regularne?

Jeśli ciąg zawiera coś innego niż - (na początku) i 0-9 lub., Jest to ciąg. (Uwaga - to ignoruje internacjonalizację i notację naukową - czy są problemy?)

W przeciwnym razie zawiera a., Jest podwójna. (Cóż, powinieneś przetestować tylko dla jednego., ale to jest początek)

W przeciwnym razie jest długa.

Po paranoi, nadal mogę sprawdzić wyjątki, ale to może być szybszy sposób.

UWAGA DODAĆ Zgaduję, że testowanie wyrażeń regularnych jest szybsze niż wyrzucanie wyjątków z różnych procedur parse, ale to może nie być prawdą. Powinieneś zrobić kilka testów.

+0

Miałem wrażenie, że regex będzie wolniejszy, ale wykonałem szybkie ćwiczenie porównawcze, które pasuje do długich i podwójnych przy użyciu wzorów regex i okazuje się, że jest nieco szybsze. Dodałem ten kod do mojego pytania wraz z wynikami testu porównawczego. – Dawood

+0

Dzięki za wykonanie miłego testu porównawczego. – user949300

2

O ile mi wiadomo, nie ma eleganckiego sposobu na zrobienie tego poza tym. Zaleciłbym, aby przeanalizować je w kolejności od najczęstszych do najmniej powszechnych, aby uczynić to tak szybko, jak to możliwe.

Jeśli masz więcej niż 3 możliwe typy, będziesz mieć głębokie i brzydkie gniazdo try-catch, ale technicznie będzie to szybsze niż w przypadku, gdy każda próba parse zostanie wykonana we własnej metodzie; kompromisem tutaj jest to, czy chcesz klarowności kodu, czy szybszego wykonania - brzmi to tak, jakbyś chciał tego drugiego.

+0

Jeśli zrozumiałem poprawnie, to parsowanie w kolejności występowania częstotliwości nie będzie działać, ponieważ ** String ** reprezentacje będą ścisłym nadzorem ** Double **, co z kolei będzie ścisłym nadzwykiem ** Long * *. Jeśli wartość ma być długa, nadal będzie pomyślnie parsować jako podwójną bez zgłaszania wyjątku. – Dawood

+0

@Dawood: Masz rację. Chodzi mi o to, że należy zastanowić się nad kolejnością analizowania, aby (miejmy nadzieję) uniknąć pracy. –

1

Być może uda się uzyskać poprawę (szczególnie, jeśli można wykluczyć notację naukową, np. 1e12), po prostu sprawdzając, czy nie ma cyfr, aby wykryć długą.

Long.parseLong() deleguje do ogólnej metody działającej w dowolnej liczbie cyfr, więc metoda dziesiętna może być nieco szybsza.

Nie zapomnij minus znaki, jeśli są możliwe w danych ...

Doubles są trudniejsze, ponieważ 654.1236871 jest ważny, ale 654.12.36.87...1 nie jest, choć zawierają one ten sam zestaw znaków. Tak więc prawdopodobnie potrzebne jest pełne przetwarzanie.

1

Twój kod wygląda dobrze.

Wykonaj pewne profilowanie, a jeśli na podstawie tego znajdziesz zbyt wolny kod, możesz pomyśleć o potencjalnych optymalizacjach (takich jak prosta pętla, aby zobaczyć, czy wszystkie znaki są cyframi).

Nie próbuj optymalizować kodu przed profilowaniem. Zwłaszcza w językach takich jak Java.

1

Jedną z możliwości jest 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; 
} 

Może to być rodzaj kłopotliwe w użyciu chociaż.

0

Jeśli nie musisz się martwić, że Twój Longs jest ujemny, prawdopodobnie możesz użyć NumberUtils.isDigits() i NumberUtils.isNumber() z biblioteki Apache Commons Lang.

if(NumberUtils.isDidgets(string)){ 
    //Index long 
} else if(NumberUtils.isNumber(string)){ 
    //Index double 
} else { 
    //Index string 
} 
Powiązane problemy