Implementacja String do int (atoi) w Javie

Funkcja najpierw odrzuca tyle białych znaków, ile potrzeba, aż zostanie znaleziony pierwszy znak niebędący białą spacją. Następnie, zaczynając od tego znaku, pobiera opcjonalny początkowy znak plus lub minus, po którym następuje jak najwięcej cyfr numerycznych i interpretuje je jako wartość liczbową.

Ciąg może zawierać dodatkowe znaki po tych, które tworzą liczby całkowite, które są ignorowane i nie mają wpływu na zachowanie tej funkcji.

Jeśli pierwsza sekwencja znaków niebiałych w str nie jest prawidłową liczbą całkowitą lub jeśli taka sekwencja nie istnieje, ponieważ albo str jest pusty lub zawiera tylko białe znaki, żadna konwersja nie jest wykonywana.

Jeśli nie można było przeprowadzić żadnej prawidłowej konwersji, zwracana jest wartość zerowa. Jeśli prawidłowa wartość jest poza zakresem możliwych do przedstawienia wartości, zwracana jest INT_MAX (2147483647) lub INT_MIN (-2147483648).

Nie mam pewności o moich kontrolach przed przepełnieniem liczb całkowitych, ale oto moja implementacja:

public int myAtoi(String str) { int i = 0; while (i < str.length() && Character.isWhitespace(str.charAt(i))) { ++i; } if (i == str.length()) { return 0; } boolean isNegative = false; if (str.charAt(i) == "+" || str.charAt(i) == "-") { isNegative = str.charAt(i) == "-"; ++i; } int result = 0; while (i < str.length() && Character.isDigit(str.charAt(i))) { try { result = Math.multiplyExact(result, 10); result = Math.addExact(result, Character.getNumericValue(str.charAt(i))); } catch (ArithmeticException e) { return isNegative ? Integer.MIN_VALUE : Integer.MAX_VALUE; } ++i; } if (isNegative) { result = -result; } return result; } 

Odpowiedź

Podsumowując, jest to „całkiem dobra implementacja w wielu kluczowych szczegółach.

Używając Character.isDigit() i Character.getNumericValue() dobrze jest zobaczyć.

Math.* metody, które obsługują warunki przepełnienia, też są dobre.

Nie jestem pewien jeśli miałeś takie zamierzenie, ale poprawnie obsłużysz niejasne przypadki krawędziowe w 32-bitowych systemach liczb całkowitych ze znakiem (nie tylko w Javie), gdzie Integer.MIN_VALUE to nie to samo co - Integer.MAX_VALUE … a Twój kod właściwie to robi przy dokładnym wprowadzeniu tekstu „-2147483648”

Więc masz dobre szczegóły w swoim kodzie …. i Nie widzę żadnych zepsutych przypadków krawędzi.

Moją jedyną rekomendacją byłoby to, że maszyna stanu może uprościć sprawę … z tylko jedną pętlą ….. ale maszyna stanu może być również trochę niechlujna, chociaż myślę, że działa lepiej w na dłuższą metę …

public static int rlAtoi(String str) { boolean started = false; boolean negative = false; int result = 0; try { for (char c : str.toCharArray()) { if (!started && Character.isWhitespace(c)) { // great, ignore it. } else if (!started && (c == "+" || c == "-")) { // great, a sign negative = c == "-"; started = true; } else if (Character.isDigit(c)) { result = Math.multiplyExact(result, 10); result = Math.addExact(result, Character.getNumericValue(c)); started = true; } else { // done.... break; } } } catch (ArithmeticException e) { return negative ? Integer.MIN_VALUE : Integer.MAX_VALUE; } return negative ? -result : result; } 

Zauważ, że w surowym teście wydajności, podejrzewam, że twoje rozwiązanie będzie (nieco) szybsze, ale wolę czytelność niż małe przyrostowy wzrost wydajności, chyba że wydajność jest niezwykle krytyczna.

Komentarze

  • +1 dla automatu stanów, ponieważ jest to znacznie łatwiejsze, prawie zawsze szybsze i dużo łatwiejsze do debugowania / rozszerzenia.

Odpowiedź

Istnieje zduplikowany test dla znaku „-”. I „d przepisać

boolean isNegative = false; if (str.charAt(i) == "+" || str.charAt(i) == "-") { isNegative = str.charAt(i) == "-"; ++i; } 

as

boolean isNegative = false; if (str.charAt(i) == "-") { isNegative= true; ++i; } else if (str.charAt(i) == "+") ++i; 

Dodałbym również obsługę szesnastkowego numery.

Komentarze

  • Blok switch również dobrze by tu działał.
  • Ach, to ' jest prawdą. A switch z opadem prawdopodobnie miałby najmniejszą duplikację.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *