簡體   English   中英

如何確定字符串中包含的值是否為double

[英]How to find out if the value contained in a string is double or not

在Java中,我試圖找出字符串中包含的值是否為double?

    boolean isDouble(String str) {
        try {
            Double.parseDouble(str);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

Double來源中有一個關於此的說明:

[...] 為了避免在無效字符串上調用此方法並拋出NumberFormatException ,下面的正則表達式可用於篩選輸入字符串: [...]

后面的正則表達式的最終形式很長:

[\x00-\x20]*[+-]?(NaN|Infinity|((((\p{Digit}+)(\.)?((\p{Digit}+)?)([eE][+-]?(\p{Digit}+))?)|(\.((\p{Digit}+))([eE][+-]?(\p{Digit}+))?)|(((0[xX](\p{XDigit}+)(\.)?)|(0[xX](\p{XDigit}+)?(\.)(\p{XDigit}+)))[pP][+-]?(\p{Digit}+)))[fFdD]?))[\x00-\x20]*

但是,使用此方法,您可以輕松地排除Double.parseDouble接受的一些特殊雙精度,如InfinityNaN 例如這樣:

String regExp = "[\\x00-\\x20]*[+-]?(((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)([eE][+-]?(\\p{Digit}+))?)|(\\.((\\p{Digit}+))([eE][+-]?(\\p{Digit}+))?)|(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)?(\\.)(\\p{XDigit}+)))[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*";
boolean matches = yourString.matches(regExp);

您可以創建一個Scanner(String)並使用hasNextDouble()方法。 從它的javadoc:

如果使用nextDouble()方法可以將此掃描器輸入中的下一個標記解釋為double值,則返回true 掃描儀不會超過任何輸入。

例如,這個片段:

List<String> values = Arrays.asList("foo", "1", "2.3", "1f", "0.2d", "3.14");
for (String source : values) {
    Scanner scanner = new Scanner(source);
    System.out.println(String.format("%4s: %s", source, scanner.hasNextDouble()));
}

會產生以下輸出:

foo: false
   1: true
 2.3: true
  1f: false
0.2d: false
3.14: true

使用Scanner將比使用Double.parseDouble(String s)慢得多。

private static Random rand = new Random();
private static final String regExp = "[\\x00-\\x20]*[+-]?(((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)([eE][+-]?(\\p{Digit}+))?)|(\\.((\\p{Digit}+))([eE][+-]?(\\p{Digit}+))?)|(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)?(\\.)(\\p{XDigit}+)))[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*";
private static final Pattern pattern = Pattern.compile(regExp);

public static void main(String[] args) {

    int trials = 50000;
    String[] values = new String[trials];

    // initialize the array
    // about half the values will be parsable as double
    for( int i = 0; i < trials; ++i ) {
        double d = rand.nextDouble();
        boolean b = rand.nextBoolean();

        values[i] = (b ? "" : "abc") + d;
    }

    long start = System.currentTimeMillis();

    int parseCount = 0;
    for( int i = 0; i < trials; ++i ) {
        if( isDoubleParse(values[i]) ) {
            parseCount++;
        }
    }

    long end = System.currentTimeMillis();
    long elapsed = end - start;

    System.out.println("Elapsed time parsing: " + elapsed + " ms");
    System.out.println("Doubles: " + parseCount);

    // reset the timer for the next run
    start = System.currentTimeMillis();

    int scanCount = 0;
    for( int i = 0; i < trials; ++i ) {
        if( isDoubleScan(values[i]) ) {
            scanCount++;
        }
    }

    end = System.currentTimeMillis();
    elapsed = end - start;

    System.out.println("Elapsed time scanning: " + elapsed + " ms");
    System.out.println("Doubles: " + scanCount);


    // reset the timer for the next run
    start = System.currentTimeMillis();

    int regexCount = 0;
    for( int i = 0; i < trials; ++i ) {
        if( isDoubleRegex(values[i]) ) {
            regexCount++;
        }
    }

    end = System.currentTimeMillis();
    elapsed = end - start;

    System.out.println("Elapsed time regex (naive): " + elapsed + " ms");
    System.out.println("Doubles: " + naiveRegexCount);


    // reset the timer for the next run
    start = System.currentTimeMillis();

    int compiledRegexCount = 0;
    for( int i = 0; i < trials; ++i ) {
        if( isDoubleCompiledRegex(values[i]) ) {
            compiledRegexCount++;
        }
    }

    end = System.currentTimeMillis();
    elapsed = end - start;

    System.out.println("Elapsed time regex (compiled): " + elapsed + " ms");
    System.out.println("Doubles: " + compiledRegexCount);
}


public static boolean isDoubleParse(String s) {
    if( s == null ) return false;
    try {
        Double.parseDouble(s);
        return true;
    } catch (NumberFormatException e) {
        return false;
    }
}

public static boolean isDoubleScan(String s) {
    Scanner scanner = new Scanner(s);
    return scanner.hasNextDouble();
}

public static boolean isDoubleRegex(String s) {
    return s.matches(regExp);
}

public static boolean isDoubleCompiledRegex(String s) {
    Matcher m = pattern.matcher(s);
    return m.matches();
}

當我運行上面的代碼時,我得到以下輸出:

經過時間解析:235毫秒
雙打:24966
經過時間掃描:31358毫秒
雙打:24966
經過時間正則表達式(天真):1829毫秒
雙打:24966
經過時間正則表達式(已編譯):109毫秒
雙打:24966

鑒於正則表達式的復雜性,正則表達式方法運行得相當快,但仍然不如使用Double.parseDouble(s)簡單解析那么快。 正如評論中指出的那樣,有一些像NaN這樣的值可以通過解析器,但可能不應該這樣。

更新:

按照@ Gabe的建議預編譯正則表達式會有所不同。 編譯的正則表達式方法現在是明顯的贏家。

public boolean isDouble(String value) {
    try {
        Double.parseDouble(value);
        return true;
    } catch (NumberFormatException e) {
        return false;
    }
}

您可以使用Apache Commons Lang的util類:

NumberUtils.isNumber(aString);

它是null安全的,不需要使用try-catch塊。

注意:對於解析雙精度數,如果小數點分隔符是點,則它可以工作.

編輯: isNumber已棄用,將從Lang 4.0中刪除

更好用:

NumberUtils.isCreatable(aString);

您可以嘗試使用Double.parseDouble(String s)解析它

如果解析成功則返回double,如果不可解析則返回異常。

所以你可以把整個東西包裝在一個包含try-catch的函數中,如果有異常則返回false,如果你得到一個實際值則返回true。

我建議這樣:

try {
  d = Double.parseDouble(myString);
}
catch (NumberFormatException ex) {
    // Do something smart here...
}

其他人推測您可能還想知道輸入不是表示為整數。 根據您的要求,這可能會使作業快速而骯臟:

public static void main(String[] args) throws Exception {
    System.out.println(isNonIntegerDouble("12"));  //false
    System.out.println(isNonIntegerDouble("12.1")); //true
    System.out.println(isNonIntegerDouble("12.0")); //true
}

public static boolean isNonIntegerDouble(String in) {
    try {
        Double.parseDouble(in);
    } catch (NumberFormatException nfe) {
        return false;
    }
    try {
        new BigInteger(in);
    } catch (NumberFormatException nfe) {
        return true;
    }
    return false;
}

在這一點上,我覺得字符串匹配將是一個更合適的選擇。

您可以在字符串上使用以下正則表達式:

[-+]?[0-9]*\.?[0-9]*

並查看它是否匹配。

我修改了Jonas的isInteger()方法,為我自己的項目提出了方法isDecimal(),我列出了下面的代碼。

可能有人可以更改添加更多代碼來區分double和float。

雖然我沒有檢查,它應該很快出來,可能比正則表達更好。 唯一的缺陷是在溢出情況等情況下行為不端。

請注意,我參考Bill的帖子是什么是檢查String是否代表Java中的整數的最佳方法?

    public boolean isDecimal(String str) {
        if (str == null) {
            return false;
        }
        int length = str.length();
        if (length == 1 ) {
            return false;
        }
        int i = 0;
        if (str.charAt(0) == '-') {
            if (length < 3) {
                return false;
            }
            i = 1;
        }
        int numOfDot = 0;
        for (; i < length; i++) {
            char c = str.charAt(i);
            if (c == '.')
                numOfDot++;
            else if (c == '/')
                return false;
            else if (c < '.' || c > '9') {
                return false;
            }
        }
        if (numOfDot != 1 )
            return false;

        return true;
    }

如果您可以找到一種方法將數字與字符串隔離,可以使用split方法。 讓我們說num[1] = 25; 然后你可以做這樣的事情來檢查它是否是一個雙倍。

boolean isDouble;
if(num[1].contains(".")){
isDouble = true;
}
else{
isDouble = false;
}
    public boolean isDouble( String input )  
    {  
       try  
       {  
          Double.parseDouble( input );  
          return true;  
       }  
       catch( Exception e)  
       {  
         return false;  
      }  
  }  

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM