确定字符串是否为数字并在Java中转换?
我知道这个问题的变体以前经常被问到(例如,请参见和),但这是而不是一个精确的重复 我想检查确定字符串是否为数字并在Java中转换?,java,numbers,bigdecimal,string-parsing,Java,Numbers,Bigdecimal,String Parsing,我知道这个问题的变体以前经常被问到(例如,请参见和),但这是而不是一个精确的重复 我想检查字符串是否是数字,如果是,我想将其存储为双精度。有几种方法可以做到这一点,但它们似乎都不适合我的目的 一种解决方案是使用Double.parseDouble或类似的新的BigDecimal。但是,如果存在逗号,则这些解决方案不起作用(因此“1234”将导致异常)。在使用这些技术之前,我当然可以去掉所有逗号,但这在其他地区似乎会带来很多问题 我查看了ApacheCommonsNumberUtils.isNum
字符串
是否是数字,如果是,我想将其存储为双精度
。有几种方法可以做到这一点,但它们似乎都不适合我的目的
一种解决方案是使用Double.parseDouble
或类似的新的BigDecimal
。但是,如果存在逗号,则这些解决方案不起作用(因此“1234”将导致异常)。在使用这些技术之前,我当然可以去掉所有逗号,但这在其他地区似乎会带来很多问题
我查看了ApacheCommonsNumberUtils.isNumber
,但它也存在相同的逗号问题
我考虑过NumberFormat
或DecimalFormat
,但这些似乎太宽大了。例如,“1A”被格式化为“1”,而不是表示它不是一个数字。此外,类似“127.0.0.1”的内容将被计算为数字127,而不是表示它不是一个数字
我觉得我的需求并不是第一个这么做的,但没有一个解决方案能完全满足我的需求。我想甚至我也不知道我需要什么(否则我可以编写自己的解析器),但是我知道上述解决方案不起作用,原因如下。是否存在任何解决方案,或者我是否需要准确了解我需要什么,并为其编写自己的代码?如果您设置了正确的区域设置,内置的
parseDouble
将使用逗号。例如。如果您不愿意接受DecimalFormat的结果或已链接的答案,我认为您需要使用自定义解决方案处理多步骤流程
1) 识别小数和分组分隔符。您可能需要识别其他格式符号(如科学符号指示器)
()
2) 去掉所有分组符号(或者创建一个正则表达式,如果接受,请小心其他符号,如十进制)。然后去掉第一个十进制符号。其他需要的符号
3) 调用
parse
或isNumber
您可以指定所需的区域设置:
NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN);
double myNumber = nf.parse(myString).doubleValue();
这应该在您的示例中起作用,因为德语区域设置中有逗号作为十进制分隔符。您可以使用ParsePosition检查NumberFormat.parse操作中字符串的完整使用情况。如果字符串已被使用,则不会出现“1A”情况。如果没有,你可以这样做,也可以这样做。请参阅,了解解决方案的简要说明以及由于ParsePosition选项而无法修复的相关JDK错误。一个简单的破解方法是对您获得的字符串使用
replaceFirst
,并检查新字符串是否为双精度字符串。如果是双转换回(如果需要的话)听起来很奇怪,但我会尝试遵循并使用java.util.Scanner
Scanner scanner = new Scanner(input);
if (scanner.hasNextInt())
System.out.println(scanner.nextInt());
else if (scanner.hasNextDouble())
System.out.println(scanner.nextDouble());
else
System.out.println("Not a number");
对于输入,如1A
,127.0.0.1
,1234
,6.02e-23
,我得到以下输出:
Not a number
Not a number
1234
6.02E-23
Scanner.useLocale
可用于更改为所需的区域设置。不确定它是否满足您的所有要求,但找到的代码可能会为您指明正确的方向
从文章中:
总之,正确输入处理的步骤如下:
如果要将逗号分隔的十进制字符串数转换为双精度,可以使用DecimalSeparator+DecimalFormalSymbols:
final double strToDouble(String str, char separator){
DecimalFormatSymbols s = new DecimalFormatSymbols();
s.setDecimalSeparator(separator);
DecimalFormat df = new DecimalFormat();
double num = 0;
df.setDecimalFormatSymbols(s);
try{
num = ((Double) df.parse(str)).doubleValue();
}catch(ClassCastException | ParseException ex){
// if you want, you could add something here to
// indicate the string is not double
}
return num;
}
那么,让我们测试一下:
String a = "1.2";
String b = "2,3";
String c = "A1";
String d = "127.0.0.1";
System.out.println("\"" + a + "\" = " + strToDouble(a, ','));
System.out.println("\"" + a + "\" (with '.' as separator) = "
+ strToDouble(a, '.'));
System.out.println("\"" + b + "\" = " + strToDouble(b, ','));
System.out.println("\"" + c + "\" = " + strToDouble(c, ','));
System.out.println("\"" + d + "\" = " + strToDouble(d, ','));
如果运行上述代码,您将看到:
"1.2" = 0.0
"1.2" (with '.' as separator) = 1.2
"2,3" = 2.3
"A1" = 0.0
"127.0.0.1" = 0.0
不幸的是,Double.parseDouble或新的BigDecimal似乎是您最好的选择 您提到了本地化方面的问题,但不幸的是,无论如何都无法可靠地支持用户不使用规范的所有区域设置。这是不可能的 有时,您可以通过查看是否首先使用逗号或句点(如果两者都使用)来推断所使用的方案,但这并不总是可能的,所以为什么还要尝试呢?最好有一个系统,你知道它在某些情况下工作可靠,而不是试图依赖一个可能在更多情况下工作,但也可能产生不良结果 数字123456代表什么?123456还是123.456 根据用户指定的语言环境,只需去掉逗号、空格或句点。默认为剥离空格和逗号。如果要使其更严格,请仅使用带逗号或空格,而不能同时使用这两个逗号或空格,如果有逗号或空格,则仅在句点之前使用。也应该很容易手动检查,如果他们是正确的间隔在三个。事实上,在这里定制解析器可能是最简单的 这里有一点概念证明。这有点(非常)混乱,但我认为它是有效的,而且你无论如何都能理解:)
公共类StrictNumberParser{
公共双解析(String numberString)抛出NumberFormatException{
numberString=numberString.trim();
char[]numbercars=numberString.toCharArray();
字符分隔符=null;
int-separatorCount=0;
布尔noMoreSeparators=false;
for(int index=1;indexpublic class StrictNumberParser {
public double parse(String numberString) throws NumberFormatException {
numberString = numberString.trim();
char[] numberChars = numberString.toCharArray();
Character separator = null;
int separatorCount = 0;
boolean noMoreSeparators = false;
for (int index = 1; index < numberChars.length; index++) {
char character = numberChars[index];
if (noMoreSeparators || separatorCount < 3) {
if (character == '.') {
if (separator != null) {
throw new NumberFormatException();
} else {
noMoreSeparators = true;
}
} else if (separator == null && (character == ',' || character == ' ')) {
if (noMoreSeparators) {
throw new NumberFormatException();
}
separator = new Character(character);
separatorCount = -1;
} else if (!Character.isDigit(character)) {
throw new NumberFormatException();
}
separatorCount++;
} else {
if (character == '.') {
noMoreSeparators = true;
} else if (separator == null) {
if (Character.isDigit(character)) {
noMoreSeparators = true;
} else if (character == ',' || character == ' ') {
separator = new Character(character);
} else {
throw new NumberFormatException();
}
} else if (!separator.equals(character)) {
throw new NumberFormatException();
}
separatorCount = 0;
}
}
if (separator != null) {
if (!noMoreSeparators && separatorCount != 3) {
throw new NumberFormatException();
}
numberString = numberString.replaceAll(separator.toString(), "");
}
return Double.parseDouble(numberString);
}
public void testParse(String testString) {
try {
System.out.println("result: " + parse(testString));
} catch (NumberFormatException e) {
System.out.println("Couldn't parse number!");
}
}
public static void main(String[] args) {
StrictNumberParser p = new StrictNumberParser();
p.testParse("123 45.6");
p.testParse("123 4567.8");
p.testParse("123 4567");
p.testParse("12 45");
p.testParse("123 456 45");
p.testParse("345.562,346");
p.testParse("123 456,789");
p.testParse("123,456,789");
p.testParse("123 456 789.52");
p.testParse("23,456,789");
p.testParse("3,456,789");
p.testParse("123 456.12");
p.testParse("1234567.8");
}
}
/* A number using thousand separator must have
groups of 3 digits, except the first one.
Numbers following the decimal separator can
of course be unlimited. */
private final static int GROUP_SIZE=3;
public static boolean isNumber(String input) {
boolean inThousandSep = false;
boolean inDecimalSep = false;
boolean endsWithDigit = false;
char thousandSep = '\0';
int prevDigits = 0;
for(int i=0; i < input.length(); i++) {
char c = input.charAt(i);
switch(c) {
case ',':
case '.':
case ' ':
endsWithDigit = false;
if(inDecimalSep)
return false;
else if(inThousandSep) {
if(c != thousandSep)
inDecimalSep = true;
if(prevDigits != GROUP_SIZE)
return false; // Invalid use of separator
}
else {
if(prevDigits > GROUP_SIZE || prevDigits == 0)
return false;
thousandSep = c;
inThousandSep = true;
}
prevDigits = 0;
break;
default:
if(Character.isDigit(c)) {
prevDigits++;
endsWithDigit = true;
}
else {
return false;
}
}
}
return endsWithDigit;
}
public static void main(String[] args) {
System.out.println(isNumber("100")); // true
System.out.println(isNumber("100.00")); // true
System.out.println(isNumber("1,5")); // true
System.out.println(isNumber("1,000,000.00.")); // false
System.out.println(isNumber("100,00,2")); // false
System.out.println(isNumber("123.123.23.123")); // false
System.out.println(isNumber("123.123.123.123")); // true
}
public double convertStoD(string s,bool isUS){
//string s = "some string or number, something dynamic";
bool isNegative = false;
if(s.charAt(0)== '-')
{
s = s.subString(1);
isNegative = true;
}
string ValidNumberArguements = new string();
if(isUS)
{
ValidNumberArguements = ",.";
}else{
ValidNumberArguements = ".,";
}
int length = s.length;
int currentCommas = 0;
int currentDecimals = 0;
for(int i = 0; i < length; i++){
if(s.charAt(i) == ValidNumberArguements.charAt(0))//charAt(0) = ,
{
currentCommas++;
continue;
}
if(s.charAt(i) == ValidNumberArguements.charAt(1))//charAt(1) = .
{
currentDec++;
continue;
}
if(s.charAt(i).matches("\D"))return null;//remove 1 A
}
if(currentDecimals > 1)return null;//remove 1.00.00
string decimalValue = "";
if(currentDecimals > 0)
{
int index = s.indexOf(ValidNumberArguements.charAt(1));
decimalValue += s.substring(index);
s = s.substring(0,index);
if(decimalValue.indexOf(ValidNumberArguements.charAt(0)) != -1)return null;//remove 1.00,000
}
int allowedCommas = (s.length-1) / 3;
if(currentCommas > allowedCommas)return null;//remove 10,00,000
String[] NumberParser = s.split(ValidNumberArguements.charAt(0));
length = NumberParser.length;
StringBuilder returnString = new StringBuilder();
for(int i = 0; i < length; i++)
{
if(i == 0)
{
if(NumberParser[i].length > 3 && length > 1)return null;//remove 1234,0,000
returnString.append(NumberParser[i]);
continue;
}
if(NumberParser[i].length != 3)return null;//ensure proper 1,000,000
returnString.append(NumberParser[i]);
}
returnString.append(decimalValue);
double answer = Double.parseDouble(returnString);
if(isNegative)answer *= -1;
return answer;
}
public static boolean isNumber(String s){
try{
Locale l = Locale.getDefault();
DecimalFormat df = new DecimalFormat("###.##;-##.##");
Number n = df.parse(s);
String sb = df.format(n);
return sb.equals(s);
}
catch(Exception e){
return false;
}
}
import java.util.Locale;
import java.text.DecimalFormatSymbols;
public class StrictNumberFormat {
public static boolean isDouble(String s, Locale l) {
String clean = convertLocaleCharacters(s,l);
try {
Double.valueOf(clean);
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
public static double doubleValue(String s, Locale l) {
return Double.valueOf(convertLocaleCharacters(s,l));
}
public static boolean isDouble(String s) {
return isDouble(s,Locale.getDefault());
}
public static double doubleValue(String s) {
return doubleValue(s,Locale.getDefault());
}
private static String convertLocaleCharacters(String number, Locale l) {
DecimalFormatSymbols symbols = new DecimalFormatSymbols(l);
String grouping = getUnicodeRepresentation( symbols.getGroupingSeparator() );
String decimal = getUnicodeRepresentation( symbols.getDecimalSeparator() );
String negative = getUnicodeRepresentation( symbols.getMinusSign() );
String zero = getUnicodeRepresentation( symbols.getZeroDigit() );
String clean = number.replaceAll(grouping, "");
clean = clean.replaceAll(decimal, ".");
clean = clean.replaceAll(negative, "-");
clean = clean.replaceAll(zero, "0");
return clean;
}
private static String getUnicodeRepresentation(char ch) {
String unicodeString = Integer.toHexString(ch); //ch implicitly promoted to int
while(unicodeString.length()<4) unicodeString = "0"+unicodeString;
return "\\u"+unicodeString;
}
}
import java.lang.NumberFormatException;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class ParseDouble {
public static void main(String[] argv) {
String line = "$$$|%|#|1A|127.0.0.1|1,344|95|99.64";
for (String s : line.split("\\|")) {
try {
System.out.println("parsed: " +
any2double(s)
);
}catch (NumberFormatException ne) {
System.out.println(ne.getMessage());
}
}
}
public static double any2double(String input) throws NumberFormatException {
double out =0d;
Pattern special = Pattern.compile("[^a-zA-Z0-9\\.,]+");
Pattern letters = Pattern.compile("[a-zA-Z]+");
Pattern comma = Pattern.compile(",");
Pattern allDigits = Pattern.compile("^[0-9]+$");
Pattern singleDouble = Pattern.compile("^[0-9]+\\.[0-9]+$");
Matcher[] goodCases = new Matcher[]{
allDigits.matcher(input),
singleDouble.matcher(input)
};
Matcher[] nanCases = new Matcher[]{
special.matcher(input),
letters.matcher(input)
};
// maybe cases
if (comma.matcher(input).find()){
out = Double.parseDouble(
comma.matcher(input).replaceFirst("."));
return out;
}
for (Matcher m : nanCases) {
if (m.find()) {
throw new NumberFormatException("Bad input "+input);
}
}
for (Matcher m : goodCases) {
if (m.find()) {
try {
out = Double.parseDouble(input);
return out;
} catch (NumberFormatException ne){
System.out.println(ne.getMessage());
}
}
}
throw new NumberFormatException("Could not parse "+input);
}
}