Implementando String para int (atoi) em Java

A função primeiro descarta quantos caracteres de espaço em branco forem necessários até o primeiro caractere diferente de espaço em branco é encontrado. Então, começando com este caractere, pega um sinal de mais ou menos inicial opcional seguido por tantos dígitos numéricos quanto possível e os interpreta como um valor numérico.

A string pode conter caracteres adicionais após aqueles que formam o número integral, que são ignorados e não têm efeito no comportamento desta função.

Se a primeira sequência de caracteres sem espaço em str não for um número inteiro válido, ou se essa sequência não existir porque também str está vazio ou contém apenas caracteres de espaço em branco, nenhuma conversão é realizada.

Se nenhuma conversão válida puder ser realizada, um valor zero será retornado. Se o valor correto estiver fora do intervalo de valores representáveis, INT_MAX (2147483647) ou INT_MIN (-2147483648) será retornado.

Não tenho certeza sobre minhas verificações contra estouro de inteiro, mas aqui está minha implementação:

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

Resposta

Resumindo, essa “implementação é muito boa em uma série de detalhes importantes.

Usando Character.isDigit() e Character.getNumericValue().

Os métodos Math.* que lidam com as condições de estouro também são bons.

Não tenho certeza se você pretendia isso, mas também lida corretamente com um caso obscuro em sistemas inteiros assinados de 32 bits (não apenas Java), onde Integer.MIN_VALUE não é o mesmo que - Integer.MAX_VALUE … e seu código realmente acerta para uma entrada exata do texto “-2147483648”

Então, você tem bons detalhes em seu código … e Não consigo ver nenhum caso extremo quebrado.

Minha única recomendação seria que uma máquina de estado pode tornar as coisas mais simples … com apenas um loop … mas a máquina de estado pode ser um pouco confusa também, embora eu ache que funciona melhor em a longo prazo …

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

Observe que em um benchmark de desempenho bruto, eu suspeito que sua solução será (um pouco) mais rápida, mas eu prefiro a legibilidade em vez de pequena ganhos incrementais de desempenho, a menos que o desempenho seja extremamente crítico.

Comentários

  • +1 para máquina de estado, pois isso é muito mais fácil, quase sempre mais rápido e muito mais fácil de depurar / estender.

Resposta

Há um teste duplicado para o caractere “-“. I “d reescrever

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

como

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

Também adicionaria suporte para hexadecimal números.

Comentários

  • Um bloco switch também funcionaria bem aqui.
  • Ah, isso ' é verdade. Um switch com fall-through provavelmente teria menos duplicação.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *