Implementere streng til int (atoi) i Java

Funksjonen forkaster først så mange tegn i mellomrom som nødvendig til den første karakteren som ikke er mellomrom er funnet. Fra dette tegnet tar du deretter et valgfritt pluss- eller minustegn etterfulgt av så mange numeriske sifre som mulig, og tolker dem som en numerisk verdi.

Strengen kan inneholde flere tegn etter de som danner integralt nummer, som ignoreres og ikke har noen innvirkning på oppførselen til denne funksjonen.

Hvis den første sekvensen med ikke-hvite mellomromstegn i str ikke er et gyldig integralt tall, eller hvis ingen slik sekvens eksisterer fordi enten str er tom eller den inneholder bare mellomromstegn, det utføres ingen konvertering.

Hvis ingen gyldig konvertering kunne utføres, returneres en nullverdi. Hvis den riktige verdien er utenfor området representable verdier, returneres INT_MAX (2147483647) eller INT_MIN (-2147483648).

Jeg er ikke sikker om sjekkene mine mot heltalloverløp, men her er implementeringen min:

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

Svar

Alt i alt er det «en ganske god implementering i en rekke sentrale detaljer.

Ved hjelp av Character.isDigit() og Character.getNumericValue() metoder er gode å se.

Math.* metodene som håndterer overløpsforholdene er også gode.

Jeg er ikke sikker hvis du hadde tenkt deg det, men du også håndterer riktig en obskur edge-case i 32-bits signerte heltallsystemer (ikke bare Java), der Integer.MIN_VALUE ikke er det samme som - Integer.MAX_VALUE … og koden din får det riktig for en nøyaktig inntasting av teksten «-2147483648»

Så, du har gode detaljer i koden din …. og Jeg kan ikke se noen ødelagte kantsaker.

Min eneste anbefaling vil være at en statsmaskin kan gjøre ting enklere … med bare en sløyfe ….. men statsmaskinen kan også være litt rotete, selv om jeg synes det fungerer bedre i i det lange løp …

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

Legg merke til at i en rå ytelses benchmark, mistenker jeg løsningen din vil være (litt) raskere, men jeg foretrekker lesbarhet fremfor liten inkrementelle ytelsesgevinster, med mindre ytelse er ekstremt kritisk.

Kommentarer

  • +1 for statsmaskin, da dette er mye enklere, nesten alltid raskere og mye lettere å feilsøke / utvide.

Svar

Det er en duplikatest for «-» -tegnet. Jeg skrev om

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

som

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

Jeg vil også legge til støtte for heksadesimal tall.

Kommentarer

  • En switch -blokk vil også fungere bra her.
  • Ah, at ' er sant. En switch med gjennomslag ville trolig ha minst duplisering.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *