Самый изящный способ обнаружить, если Строка является числом?

Если вы хотите вычислить максимум двух чисел, стандартный подход в сборке ARM выглядит примерно так:

cmp   r0, r1  @ if r0 > r1
movgt r2, r0  @ then r2 = r0
movle r2, r1  @ else r2 = r1

Чтобы добавить максимум r0, r1 и [114 ] до r3 вы можете захотеть что-то вроде этого:

cmp   r0, r1      @ if r0 < r1
movlt r0, r1      @ then r0 = r1 (i.e. r0 = max(r0, r1))
cmp   r0, r2      @ if r0 < r2
movlt r0, r2      @ then r0 = r2 (i.e. r0 = max(max(r0, r1), r2))
add   r3, r0, r3  @ r3 += r0

реализовать это так, чтобы вы не загромождали какие-либо регистры, оставляя читателю в качестве упражнения.

Всегда имейте в виду, что почти каждая инструкция может быть выполнена условно на ARM. В этом вся сила набора инструкций.

8
задан Epaga 26 January 2009 в 09:05
поделиться

11 ответов

Я не полагаю, что существует что-либо встроенное в Java, чтобы сделать это быстрее и все еще надежно, предполагая, что позже Вы захотите на самом деле проанализировать его с Double.valueOf (или подобный).

Я использовал бы Double.parseDouble вместо Double.valueOf, чтобы не создавать Двойное излишне, и можно также избавиться от очевидно глупых чисел, более быстрых, чем исключение будет путем проверки на цифры, e/E, - и. заранее. Так, что-то как:

public boolean isDouble(String value)
{        
    boolean seenDot = false;
    boolean seenExp = false;
    boolean justSeenExp = false;
    boolean seenDigit = false;
    for (int i=0; i < value.length(); i++)
    {
        char c = value.charAt(i);
        if (c >= '0' && c <= '9')
        {
            seenDigit = true;
            continue;
        }
        if ((c == '-' || c=='+') && (i == 0 || justSeenExp))
        {
            continue;
        }
        if (c == '.' && !seenDot)
        {
            seenDot = true;
            continue;
        }
        justSeenExp = false;
        if ((c == 'e' || c == 'E') && !seenExp)
        {
            seenExp = true;
            justSeenExp = true;
            continue;
        }
        return false;
    }
    if (!seenDigit)
    {
        return false;
    }
    try
    {
        Double.parseDouble(value);
        return true;
    }
    catch (NumberFormatException e)
    {
        return false;
    }
}

Обратите внимание, что несмотря на взятие нескольких попыток, это все еще не покрывает "NaN" или преобразовывает значения в шестнадцатеричную систему. Хотите ли Вы, чтобы они передали, или не зависит от контекста.

По моему опыту, регулярные выражения медленнее, чем трудно кодированная проверка выше.

10
ответ дан 5 December 2019 в 04:43
поделиться

Вы могли использовать regex, т.е. что-то как String.matches("^[\\d\\-\\.]+$"); (если Вы не тестируете на отрицательные числа или числа с плавающей точкой, Вы могли бы упростить немного).

Не уверенный, было ли это быстрее, чем метод, который Вы обрисовали в общих чертах все же.

Править: в свете всего этого противоречия я решил сделать тест и получить некоторые данные о том, как быстро каждый из этих методов был. Не так правильность, но как быстро они работали.

Можно читать о моих результатах на моем блоге. (Подсказка: Jon Skeet FTW).

9
ответ дан 5 December 2019 в 04:43
поделиться

Корректный regex на самом деле подан Двойной javadocs:

Чтобы постараться не называть этот метод на недопустимой строке и иметь NumberFormatException быть брошенным, регулярное выражение ниже может использоваться для экранирования входной строки:

    final String Digits     = "(\\p{Digit}+)";
    final String HexDigits  = "(\\p{XDigit}+)";
    // an exponent is 'e' or 'E' followed by an optionally 
    // signed decimal integer.
    final String Exp        = "[eE][+-]?"+Digits;
    final String fpRegex    =
        ("[\\x00-\\x20]*"+  // Optional leading "whitespace"
         "[+-]?(" + // Optional sign character
         "NaN|" +           // "NaN" string
         "Infinity|" +      // "Infinity" string

         // A decimal floating-point string representing a finite positive
         // number without a leading sign has at most five basic pieces:
         // Digits . Digits ExponentPart FloatTypeSuffix
         // 
         // Since this method allows integer-only strings as input
         // in addition to strings of floating-point literals, the
         // two sub-patterns below are simplifications of the grammar
         // productions from the Java Language Specification, 2nd 
         // edition, section 3.10.2.

         // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
         "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+

         // . Digits ExponentPart_opt FloatTypeSuffix_opt
         "(\\.("+Digits+")("+Exp+")?)|"+

   // Hexadecimal strings
   "((" +
    // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
    "(0[xX]" + HexDigits + "(\\.)?)|" +

    // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
    "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +

    ")[pP][+-]?" + Digits + "))" +
         "[fFdD]?))" +
         "[\\x00-\\x20]*");// Optional trailing "whitespace"

    if (Pattern.matches(fpRegex, myString))
        Double.valueOf(myString); // Will not throw NumberFormatException
    else {
        // Perform suitable alternative action
    }

Это не допускает локализованные представления, однако:

Для интерпретации представлений локализованной строки значения с плавающей точкой используйте подклассы NumberFormat.

5
ответ дан 5 December 2019 в 04:43
поделиться

См. java.text. NumberFormat (javadoc).

NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
Number myNumber = nf.parse(myString);
int myInt = myNumber.intValue();
double myDouble = myNumber.doubleValue();
8
ответ дан 5 December 2019 в 04:43
поделиться

Использовать StringUtils.isDouble(String) в Apache палата общин.

3
ответ дан 5 December 2019 в 04:43
поделиться

Я использовал бы Джакарту Ленг свободного городского населения, как всегда! Но я понятия не имею, быстра ли их реализация или нет. Это не полагается на Исключения, которые могли бы быть хорошей мудрой производительностью бедра...

2
ответ дан 5 December 2019 в 04:43
поделиться

Большинство этих ответов является несколько приемлемыми решениями. Все regex решения имеют проблему того, чтобы не быть корректным для всех случаев, о которых можно заботиться.

Если Вы действительно хотите удостовериться, что Строка является верным номером, то я использовал бы Ваше собственное решение. Не забывайте, что, я воображаю, что большую часть времени Строка будет верным номером и не повысит исключение. Таким образом, большую часть времени производительность будет идентична производительности Double.valueOf ().

Я предполагаю, что это действительно не ответ, за исключением того, что он проверяет Ваш начальный инстинкт.

Randy

2
ответ дан 5 December 2019 в 04:43
поделиться

Усиление от г-на Skeet:

private boolean IsValidDoubleChar(char c)
{
    return "0123456789.+-eE".indexOf(c) >= 0;
}

public boolean isDouble(String value)
{
    for (int i=0; i < value.length(); i++)
    {
        char c = value.charAt(i);
        if (IsValidDoubleChar(c))
            continue;
        return false;
    }
    try
    {
        Double.parseDouble(value);
        return true;
    }
    catch (NumberFormatException e)
    {
        return false;
    }
}
3
ответ дан 5 December 2019 в 04:43
поделиться

Ответ следующего Phill я могу предложить другой regex?

String.matches("^-?\\d+(\\.\\d+)?$");
1
ответ дан 5 December 2019 в 04:43
поделиться

Я предпочитаю использовать цикл по символу Строк [] представление и использовать Character.isDigit () метод. Если элегантность желаема, я думаю, что это является самым читаемым:

package tias;

public class Main {
  private static final String NUMERIC = "123456789";
  private static final String NOT_NUMERIC = "1L5C";

  public static void main(String[] args) {
    System.out.println(isStringNumeric(NUMERIC));
    System.out.println(isStringNumeric(NOT_NUMERIC));
  }

  private static boolean isStringNumeric(String aString) {
    if (aString == null || aString.length() == 0) {
      return false;
    }
    for (char c : aString.toCharArray() ) {
      if (!Character.isDigit(c)) {
        return false;
      }
    }
    return true;
  }

}

1
ответ дан 5 December 2019 в 04:43
поделиться

Если Вы хотите что-то, что это горячо быстро, и у Вас есть очень четкое представление о том, какие форматы Вы хотите принять, можно создать конечный автомат DFA вручную. Это по существу, как regexes работают под капотом так или иначе, но можно избежать regex шага компиляции этот путь, и это может быть быстрее, чем универсальный regex компилятор.

-1
ответ дан 5 December 2019 в 04:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: