在解析字符串之前,如何检查它是否是一个数字?
当前回答
我认为唯一可靠地判断字符串是否是数字的方法是解析它。所以我只是解析它,如果它是一个数字,你可以免费得到整数形式的数字!
其他回答
异常开销很大,但在这种情况下,RegEx需要更长的时间。下面的代码显示了两个函数的简单测试——一个使用异常,一个使用正则表达式。在我的机器上,RegEx版本比异常慢10倍。
import java.util.Date;
public class IsNumeric {
public static boolean isNumericOne(String s) {
return s.matches("-?\\d+(\\.\\d+)?"); //match a number with optional '-' and decimal.
}
public static boolean isNumericTwo(String s) {
try {
Double.parseDouble(s);
return true;
} catch (Exception e) {
return false;
}
}
public static void main(String [] args) {
String test = "12345.F";
long before = new Date().getTime();
for(int x=0;x<1000000;++x) {
//isNumericTwo(test);
isNumericOne(test);
}
long after = new Date().getTime();
System.out.println(after-before);
}
}
//请检查下面的代码
public static boolean isDigitsOnly(CharSequence str) {
final int len = str.length();
for (int i = 0; i < len; i++) {
if (!Character.isDigit(str.charAt(i))) {
return false;
}
}
return true;
}
正如@CraigTP在他的精彩回答中提到的,我也有类似的性能问题,使用exception来测试字符串是否是数值。因此,我最终分割字符串并使用java.lang.Character.isDigit()。
public static boolean isNumeric(String str)
{
for (char c : str.toCharArray())
{
if (!Character.isDigit(c)) return false;
}
return true;
}
根据Javadoc, Character.isDigit(char)将正确识别非拉丁数字。在性能方面,我认为简单的N次比较(其中N是字符串中的字符数)在计算上比正则表达式匹配更有效。
更新:正如Jean-François Corbett在评论中指出的那样,上面的代码只验证正整数,这涵盖了我的大部分用例。下面是更新后的代码,它根据系统中使用的默认区域设置正确验证十进制数,假设十进制分隔符只在字符串中出现一次。
public static boolean isStringNumeric( String str )
{
DecimalFormatSymbols currentLocaleSymbols = DecimalFormatSymbols.getInstance();
char localeMinusSign = currentLocaleSymbols.getMinusSign();
if ( !Character.isDigit( str.charAt( 0 ) ) && str.charAt( 0 ) != localeMinusSign ) return false;
boolean isDecimalSeparatorFound = false;
char localeDecimalSeparator = currentLocaleSymbols.getDecimalSeparator();
for ( char c : str.substring( 1 ).toCharArray() )
{
if ( !Character.isDigit( c ) )
{
if ( c == localeDecimalSeparator && !isDecimalSeparatorFound )
{
isDecimalSeparatorFound = true;
continue;
}
return false;
}
}
return true;
}
这里有两种可能有效的方法。(不使用异常)。 注意:Java默认是值传递,String的值是String对象数据的地址。 所以,当你在做
stringNumber = stringNumber.replaceAll(" ", "");
您已将输入值更改为没有空格。 如果你愿意,可以去掉这条线。
private boolean isValidStringNumber(String stringNumber)
{
if(stringNumber.isEmpty())
{
return false;
}
stringNumber = stringNumber.replaceAll(" ", "");
char [] charNumber = stringNumber.toCharArray();
for(int i =0 ; i<charNumber.length ;i++)
{
if(!Character.isDigit(charNumber[i]))
{
return false;
}
}
return true;
}
这里是另一个方法,以防你想允许浮动 据称,这种方法允许表单中的数字通过 1123123123123123年.123 我刚做好,我想还需要进一步测试以确保它能正常工作。
private boolean isValidStringTrueNumber(String stringNumber)
{
if(stringNumber.isEmpty())
{
return false;
}
stringNumber = stringNumber.replaceAll(" ", "");
int countOfDecimalPoint = 0;
boolean decimalPointPassed = false;
boolean commaFound = false;
int countOfDigitsBeforeDecimalPoint = 0;
int countOfDigitsAfterDecimalPoint =0 ;
int commaCounter=0;
int countOfDigitsBeforeFirstComma = 0;
char [] charNumber = stringNumber.toCharArray();
for(int i =0 ; i<charNumber.length ;i++)
{
if((commaCounter>3)||(commaCounter<0))
{
return false;
}
if(!Character.isDigit(charNumber[i]))//Char is not a digit.
{
if(charNumber[i]==',')
{
if(decimalPointPassed)
{
return false;
}
commaFound = true;
//check that next three chars are only digits.
commaCounter +=3;
}
else if(charNumber[i]=='.')
{
decimalPointPassed = true;
countOfDecimalPoint++;
}
else
{
return false;
}
}
else //Char is a digit.
{
if ((commaCounter>=0)&&(commaFound))
{
if(!decimalPointPassed)
{
commaCounter--;
}
}
if(!commaFound)
{
countOfDigitsBeforeFirstComma++;
}
if(!decimalPointPassed)
{
countOfDigitsBeforeDecimalPoint++;
}
else
{
countOfDigitsAfterDecimalPoint++;
}
}
}
if((commaFound)&&(countOfDigitsBeforeFirstComma>3))
{
return false;
}
if(countOfDecimalPoint>1)
{
return false;
}
if((decimalPointPassed)&&((countOfDigitsBeforeDecimalPoint==0)||(countOfDigitsAfterDecimalPoint==0)))
{
return false;
}
return true;
}
谷歌的Guava库提供了一个很好的辅助方法:你可以像使用Integer一样使用它。parseInt,但如果字符串没有解析为有效整数,它将返回null而不是抛出异常。注意,它返回的是Integer,而不是int,所以你必须将它转换/自动装箱回int。
例子:
String s1 = "22";
String s2 = "22.2";
Integer oInt1 = Ints.tryParse(s1);
Integer oInt2 = Ints.tryParse(s2);
int i1 = -1;
if (oInt1 != null) {
i1 = oInt1.intValue();
}
int i2 = -1;
if (oInt2 != null) {
i2 = oInt2.intValue();
}
System.out.println(i1); // prints 22
System.out.println(i2); // prints -1
但是,在当前发行版(Guava r11)中,它仍然被标记为@Beta。
我还没有对它进行基准测试。查看源代码,有一些开销来自大量的完整性检查,但最终他们使用Character.digit(string.charAt(idx)),类似,但略有不同,从@Ibrahim上面的答案。在它们的实现中没有异常处理开销。
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- Printf与std::字符串?
- 在Jar文件中运行类
- 带参数的可运行?
- 不区分大小写的“in”
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- 如何在PHP中截断字符串最接近于一定数量的字符?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作