Java:如何从某个字符串位置解析double并获取其后的char的位置?

时间:2017-09-25 19:36:32

标签: java parsing precision decimalformat

我想要一些类似于C ++的std::stod。 我发现的最接近的是DecimalFormat类,但最重要的是它与Double.parseDouble()的行为不同。例如,它将3.14E+2解析为3.14而不是314。虽然Double.parseDouble()给出了两种情况相同的答案,但这是我想要的行为。用E+替换所有E并不是一个理想的选择(它可能会打破其他事情)。

所以基本上我希望Double.parseDouble()能够设置起始位置并返回结束位置。有没有办法在Java中实现这一点而不重新实现整个双解析例程?

1 个答案:

答案 0 :(得分:1)

扫描仪课程与您的要求非常接近:

import java.util.*;
import java.lang.reflect.*;

public class ScanFloat {
    public static void main(String args[]) throws Exception {
        String str = "foo 3.14E+2 xx";
        int startPos = 4;
        Scanner s = new Scanner(str.substring(4));
        s.useLocale(Locale.ENGLISH);
        System.out.println(s.nextDouble());
        System.out.println("endingPos: " + (startPos + getPos(s)));

    }
    static int getPos(Scanner s) throws Exception {
      Field f = Scanner.class.getDeclaredField("position");
      f.setAccessible(true);
      return (int) f.get(s);
    }
}

输出:

314.0
endingPos: 11

但是,输入"foo 3.14E+2xx"会抛出异常。根据您的使用情况,它可能会也可能不会。

使用正则表达式可以解决这个问题,并且它也不是那么难,只要你使用patterns from the documentation I linked

import java.util.regex.*;
import java.util.concurrent.atomic.AtomicInteger;

public class RegexFloat {
    public static void main(String args[]) {
        String testString = "foo 3.14E+2xx";
        AtomicInteger parsePos = new AtomicInteger(0);
        Double d = parseDouble(testString, parsePos);
        System.out.println(d);
        System.out.println(parsePos);
    }

    static Double parseDouble(String str, AtomicInteger parsePos) {
        Pattern pattern = Pattern.compile(fpRegex);
        Matcher m = pattern.matcher(str.substring(parsePos.get()));

        if (m.find()) {
            parsePos.set(m.end(1));
            return Double.parseDouble(m.group(1));
        }
        return null;
    }

    // or Pattern.compile(String.format(".{%d}%s", parsePos.get(), fpRegex));
    // if you want to avoid substring above for some reason and
    // want to add offset into the pattern


    static final String Digits     = "(\\p{Digit}+)";
    static final String HexDigits  = "(\\p{XDigit}+)";
    // an exponent is 'e' or 'E' followed by an optionally
    // signed decimal integer.
    static final String Exp        = "[eE][+-]?"+Digits;
    static 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 section 3.10.2 of
       // The Java™ Language Specification.

       // 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"    
}

输出:

314.0
11