如何在Java中检查字符串是否为数字


886

在解析字符串之前,如何检查字符串是否为数字?


36
用正则表达式提出的所有解决方案都不适用于十六进制数。
奥斯卡·卡斯蒂布兰科

并在matchs(...)函数中传递空字符串将引发NullPointer异常。
Hitesh Sahu

有关没有第三方库的简洁Java 8解决方案,请参见Max Malysh的答案。
安迪·托马斯

@HiteshSahu空字符串在最新版本(包括Java 6.x和7.x)中似乎得到了很好的处理
Lifebalance 2013年

建议使用的所有解决方案Integer.parseInt()都无法使用解析移动电话号码NumberFormatException
不是bug,

Answers:


691

使用Apache Commons Lang 3.5及更高版本:NumberUtils.isCreatableStringUtils.isNumeric

使用Apache Commons Lang 3.4及以下版本:NumberUtils.isNumberStringUtils.isNumeric

您还可以使用StringUtils.isNumericSpacewhich返回true空字符串,并忽略字符串中的内部空格。另一种方法是使用NumberUtils.isParsable根据Java基本检查数字是否可解析的方法。(链接的javadocs包含每种方法的详细示例。)


59
StringUtils.isNumeric()在这里可能不合适,因为它仅检查字符串是否为数字序列。将适用于大部分的整数,但没有那么对于小数,组分隔符等数
杰夫·梅尔卡多

42
重新设计轮子,因为您不包括整个库,因为您需要在一个地方放置3行函数。
dalvarezmartinez1 2014年

12
是否真的值得为此功能添加整个库?显然,如果将它与其他很棒的东西一起使用,但是考虑到人们已经在一行代码中解决了这个问题,这可能是过大了。

7
不适用于底片。而且所有数字的一半都是负数,所以.....
Paul Draper

6
@PaulDraper:是的,StringUtils不支持前导符号,但您应该检查NumberUtils.isCreatable,它正确支持负值。
palacsint

904

通常使用简单的用户定义函数即可完成此操作(例如,自带的“ isNumeric”函数)。

就像是:

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

但是,如果您经常调用此函数,并且您期望许多检查由于不为数字而失败,则该机制的性能将不佳,因为您依赖于每次失败都引发异常,这是一个相当昂贵的操作。

一种替代方法是使用正则表达式检查作为数字的有效性:

public static boolean isNumeric(String str) {
  return str.matches("-?\\d+(\\.\\d+)?");  //match a number with optional '-' and decimal.
}

但是,请谨慎使用上述RegEx机制,因为如果您使用非阿拉伯数字(即0到9以外的数字),它将失败。这是因为RegEx的“ \ d”部分仅与[0-9]匹配,实际上并没有国际上的数字意识。(感谢OregonGhost指出这一点!)

甚至另一种替代方法是使用Java的内置java.text.NumberFormat对象来查看解析字符串后解析器位置是否位于字符串的末尾。如果是这样,我们可以假定整个字符串是数字:

public static boolean isNumeric(String str) {
  NumberFormat formatter = NumberFormat.getInstance();
  ParsePosition pos = new ParsePosition(0);
  formatter.parse(str, pos);
  return str.length() == pos.getIndex();
}

7
Java Regex中的\ d仅匹配拉丁数字吗?如果像.NET正则表达式一样,您将遇到其他(例如阿拉伯)数字的问题,如下所述:blogs.msdn.com/oldnewthing/archive/2004/03/09/86555.aspx
OregonGhost

3
numberFormatter解决方案可能仅比捕获NumberFormatException一个略好。我怀疑最好的方法是使用正则表达式之一。
CHII

11
请注意,.您的正则表达式中的会匹配任何字符,而不仅仅是十进制分隔符。
jqno

9
+1用于实现尝试/捕获的费用。从长远来看,这实际上是一种可怕的方法,需要重复使用,但实际上我们在Java中仍然坚持这种方法。
demongolem 2011年

5
注意,没有诸如“拉丁数字”之类的东西,并且数字0-9实际上是阿拉伯数字。人们可能familar与罗马数字,这是使用谁讲拉丁语,形式I,II,III,IV,V,VI等人en.wikipedia.org/wiki/Arabic_numerals ; en.wikipedia.org/wiki/Roman_numerals
丹迪斯顿

152

如果您使用的是Android,则应使用:

android.text.TextUtils.isDigitsOnly(CharSequence str)

文档可以在这里找到

保持简单。大多数人都可以“重新编程”(同一件事)。


4
@ kape123 :)确保“ 123.456”不包含数字。
艾哈迈德·阿莱霍

8
注意:这将导致NPE输入空值。另外,不适用于负数或小数。
gMale 2014年

2
我喜欢!!我认为这绝对是数字。不是.-
illusionJJ

这就是我想要的。仅需检查数字0-9即可轻松完成的操作。我在EditText的声明中设置了一个过滤器,但是以防万一get被更改或替换,最好也进行简单的编程检查。
jwehrle

127

Java 8 Lambda表达式。

String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );

4
您也可以使用方法引用:someString.chars()。allMatch(Character :: isDigit)
Wienczny

3
很好,但它仍然是在将车轮几乎所有“解决方案”重新发明。同样,失败为“ null”(几乎所有其他)。
qben

8
这个答案简明扼要,简单易读。您几乎可以像英语一样阅读它-“将所有匹配的数字都匹配在一起”。它不需要第三方库。在非例外情​​况下,它不使用例外。这应该成为公认的答案。
安迪·托马斯

14
对于“ -1”,它将产生什么?
巴拉兹内梅特

2
没有正确的答案。数字字符串可以包含非数字字符(例如“。”或“-”),并且仍然是完美的数字。例如0.5,-1和1,000都将因此答案而失败,但是它们是完美的数值。
Simeon G

125

正如@CraigTP在他的出色回答中提到的那样,在使用Exceptions测试字符串是否为数字时,我也有类似的性能问题。所以我最终将字符串拆分并使用java.lang.Character.isDigit()

public static boolean isNumeric(String str)
{
    for (char c : str.toCharArray())
    {
        if (!Character.isDigit(c)) return false;
    }
    return true;
}

根据JavadocCharacter.isDigit(char)将正确识别非拉丁数字。从性能角度来看,我认为简单的N个比较(其中N是字符串中的字符数)会比进行正则表达式匹配更具计算效率。

更新:正如Jean-FrançoisCorbett在评论中指出的那样,以上代码仅会验证正整数,这涵盖了我的大部分用例。下面是更新的代码,该代码根据系统中使用的默认语言环境正确验证十进制数字,并假定十进制分隔符在字符串中仅出现一次。

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;
}

4
小数点分隔符还会导致此操作失败吗?
让·弗朗索瓦·科贝特

1
@Jean-FrançoisCorbett:好的,我已经用一个接受小数点分隔符的新代码更新了代码。
Ibrahim Arief 2012年

2
-ve号会使该功能失效吗?
java_mouse

3
调用toCharArray()将在String对象中创建数组的副本,因为String是不可变的。charAt(int index)直接在String对象上使用该方法可能更快。
Mike Kucera 2014年

2
StringIndexOutOfBoundsException传递长度为0的字符串时将生成。可以用if(str.length() == 0) return false;
samgak

43

谷歌的番石榴库提供了一个很好的辅助方法来做到这一点:Ints.tryParse。您可以像使用它一样使用它,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的答案类似但略有不同的方法。在其实现的幕后,没有异常处理开销。


注意,如果参数为null,这会抛出NPE。
Vadzim

30

不要使用“例外”来验证您的值。 改用Util库,例如apache NumberUtils:

NumberUtils.isNumber(myStringValue);

编辑

请注意,如果您的字符串以0开头,NumberUtils会将您的值解释为十六进制。

NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false

7
三年前接受的答案已经涵盖了Number.isNumber()
安迪·托马斯

我不这么认为。已更新或操作更改了接受的答案。我记得接受的答案没有涵盖NumberUtils,这就是为什么我添加了答案。但是,感谢您的评论

2
@Goot-接受答案的历史记录显示出该答案Number.isNumber()的第一版(日期为12年9月24日17:01)。
安迪·托马斯

@Goot,这非常好,因为它还涵盖了十进制值检查,这与StringUtils不同。
Heena Hussain '18

24

为什么每个人都在寻求例外/正则表达式解决方案?

虽然我可以理解大多数人都可以使用try / catch,但是如果您想经常使用它,可能会非常麻烦。

我在这里所做的就是使用正则表达式,parseNumber()方法和数组搜索方法来查看哪种方法最有效。这次,我只看了整数。

public static boolean isNumericRegex(String str) {
    if (str == null)
        return false;
    return str.matches("-?\\d+");
}

public static boolean isNumericArray(String str) {
    if (str == null)
        return false;
    char[] data = str.toCharArray();
    if (data.length <= 0)
        return false;
    int index = 0;
    if (data[0] == '-' && data.length > 1)
        index = 1;
    for (; index < data.length; index++) {
        if (data[index] < '0' || data[index] > '9') // Character.isDigit() can go here too.
            return false;
    }
    return true;
}

public static boolean isNumericException(String str) {
    if (str == null)
        return false;
    try {  
        /* int i = */ Integer.parseInt(str);
    } catch (NumberFormatException nfe) {  
        return false;  
    }
    return true;
}

我得到的速度结果是:

Done with: for (int i = 0; i < 10000000; i++)...

With only valid numbers ("59815833" and "-59815833"):
    Array numeric took 395.808192 ms [39.5808192 ns each]
    Regex took 2609.262595 ms [260.9262595 ns each]
    Exception numeric took 428.050207 ms [42.8050207 ns each]
    // Negative sign
    Array numeric took 355.788273 ms [35.5788273 ns each]
    Regex took 2746.278466 ms [274.6278466 ns each]
    Exception numeric took 518.989902 ms [51.8989902 ns each]
    // Single value ("1")
    Array numeric took 317.861267 ms [31.7861267 ns each]
    Regex took 2505.313201 ms [250.5313201 ns each]
    Exception numeric took 239.956955 ms [23.9956955 ns each]
    // With Character.isDigit()
    Array numeric took 400.734616 ms [40.0734616 ns each]
    Regex took 2663.052417 ms [266.3052417 ns each]
    Exception numeric took 401.235906 ms [40.1235906 ns each]

With invalid characters ("5981a5833" and "a"):
    Array numeric took 343.205793 ms [34.3205793 ns each]
    Regex took 2608.739933 ms [260.8739933 ns each]
    Exception numeric took 7317.201775 ms [731.7201775 ns each]
    // With a single character ("a")
    Array numeric took 291.695519 ms [29.1695519 ns each]
    Regex took 2287.25378 ms [228.725378 ns each]
    Exception numeric took 7095.969481 ms [709.5969481 ns each]

With null:
    Array numeric took 214.663834 ms [21.4663834 ns each]
    Regex took 201.395992 ms [20.1395992 ns each]
    Exception numeric took 233.049327 ms [23.3049327 ns each]
    Exception numeric took 6603.669427 ms [660.3669427 ns each] if there is no if/null check

免责声明:我并不是说这些方法都是100%优化的,它们只是为了演示数据

当且仅当数字为4个字符或更少且每个字符串始终为数字时,才会赢得例外...在这种情况下,为什么还要进行检查?

简而言之,如果您经常使用try / catch遇到无效数字,这将非常痛苦,这很有意义。我始终遵循的一个重要规则是,切勿对程序流使用try / catch。这是一个例子。

有趣的是,如果char <0 || > 9的编写极其简单,易于记忆(并且应该以多种语言工作),并且赢得了几乎所有的测试场景。

唯一的缺点是我猜测Integer.parseInt()可能处理非ASCII数字,而数组搜索方法却不能。


对于那些想知道为什么我说容易记住一个字符数组的人来说,如果您知道没有负号,那么您可以轻松地摆脱浓缩的东西:

public static boolean isNumericArray(String str) {
    if (str == null)
        return false;
    for (char c : str.toCharArray())
        if (c < '0' || c > '9')
            return false;
    return true;

最后,作为最后的提示,我对接受的示例中的分配操作员充满了好奇,并表示赞成。添加的分配

double d = Double.parseDouble(...)

不仅没有用,因为甚至不使用该值,它浪费了处理时间,并使运行时间增加了几纳秒(这导致测试增加了100-200毫秒)。我看不到为什么有人会这样做,因为这实际上是降低性能的额外工作。

您可能会认为它会被优化……尽管也许我应该检查字节码并查看编译器在做什么。这并不能解释为什么它总是对我来说显得冗长,尽管如果以某种方式对其进行了优化……因此我想知道发生了什么。请注意:更长一点,我的意思是运行测试10000000次迭代,并且多次运行该程序(10x +)始终表明它较慢。

编辑:更新了Character.isDigit()的测试


4
这不是每次都编译一个新的正则表达式吗?看来效率不高。
塞缪尔·埃德温·沃德2015年

1
@SamuelEdwinWard这就是我发表这篇文章的全部原因...正则表达式示例使用了其他人提供的答案,并显示了它的效率如何。即使您尝试使用正则表达式进行预编译并且仅使用它,时差也是如此:我从其他提供的人员发布的正则表达式为2587毫秒,提前编译为950毫秒,作为正则表达式为144毫秒数字数组(同一字符串的100万次迭代)。提前编译显然会有所帮助,但可悲的是,它仍然不如数组方法……除非有一些我不知道的疯狂优化。

相信正则表达式可以使事情变得更快几乎是一个谬论。如果是一次性搜索,是的,我明白了...但是我注意到有效编写的代码实际上超过了正则表达式,足以震惊您!很棒的帖子@Water
Yo Apps

19
public static boolean isNumeric(String str)
{
    return str.matches("-?\\d+(.\\d+)?");
}

CraigTP的正则表达式(如上所示)会产生一些误报。例如,“ 23y4”将被计为数字,因为“。” 匹配任何非小数点的字符。

此外,它还会拒绝任何以“ +”开头的数字

避免这两个小问题的替代方法是

public static boolean isNumeric(String str)
{
    return str.matches("[+-]?\\d*(\\.\\d+)?");
}

这将返回true单个加"+"或减"-",并false"0."
user85421

单加号或减号都不错。是“ 0”。一个有效的数字?
user872985 2011年

"0."Double.parseDouble()根据JLS(§3.10.2)是有效的,并且是有效的文字!
user85421 2011年

创建正则表达式也很昂贵。正则表达式必须一旦被创建和再利用
丹尼尔Nuriyev

1
您应该将其更改为matches("-?\\d+([.]\\d+)?")
Bobs,2013年

13

我们可以尝试用(“”)即空格替换给定字符串中的所有数字,如果之后字符串的长度为零,则可以说给定字符串仅包含数字。[如果您认为此答案有帮助,请考虑对其进行投票]示例:

boolean isNumber(String str){
        if(str.length() == 0)
            return false; //To check if string is empty

        if(str.charAt(0) == '-')
            str = str.replaceFirst("-","");// for handling -ve numbers

        System.out.println(str);

        str = str.replaceFirst("\\.",""); //to check if it contains more than one decimal points

        if(str.length() == 0)
            return false; // to check if it is empty string after removing -ve sign and decimal point
        System.out.println(str);

        return str.replaceAll("[0-9]","").length() == 0;
    }

所以""是一个数字,但"3.14""-1"没有?
Eric Duminil

显然,这并不适用于所有数字形式,但这是一种不同思维方式的支持...如果原始思维是您的,那就是。
gbenroscience

12

您可以使用NumberFormat#parse

try
{
     NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
    // Not a number.
}

提供了一个编辑-.getInstance()丢失。+1,因为这是我找到此问题时的答案。
8bitjunkie 2012年

5
如果可扩展使用,则
成本很高

1
如果末尾有垃圾字符,它也会通过value
布莱恩·怀特

如果您不记录异常,将产生声纳问题
jmhostalet

1
这适用于数字格式0x0001,其中Double.parseDouble不起作用。+1
Seabass77


8

这是我对问题的回答。

方便快捷的方法,可用于使用任何类型的解析器解析任何String isParsable(Object parser, String str)。解析器可以是Classobject。这也将允许您使用您编写的自定义解析器,并且应该在任何情况下都可以使用,例如:

isParsable(Integer.class, "11");
isParsable(Double.class, "11.11");
Object dateFormater = new java.text.SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
isParsable(dateFormater, "2001.07.04 AD at 12:08:56 PDT");

这是我的代码,并附有方法说明。

import java.lang.reflect.*;

/**
 * METHOD: isParsable<p><p>
 * 
 * This method will look through the methods of the specified <code>from</code> parameter
 * looking for a public method name starting with "parse" which has only one String
 * parameter.<p>
 * 
 * The <code>parser</code> parameter can be a class or an instantiated object, eg:
 * <code>Integer.class</code> or <code>new Integer(1)</code>. If you use a
 * <code>Class</code> type then only static methods are considered.<p>
 * 
 * When looping through potential methods, it first looks at the <code>Class</code> associated
 * with the <code>parser</code> parameter, then looks through the methods of the parent's class
 * followed by subsequent ancestors, using the first method that matches the criteria specified
 * above.<p>
 * 
 * This method will hide any normal parse exceptions, but throws any exceptions due to
 * programmatic errors, eg: NullPointerExceptions, etc. If you specify a <code>parser</code>
 * parameter which has no matching parse methods, a NoSuchMethodException will be thrown
 * embedded within a RuntimeException.<p><p>
 * 
 * Example:<br>
 * <code>isParsable(Boolean.class, "true");<br>
 * isParsable(Integer.class, "11");<br>
 * isParsable(Double.class, "11.11");<br>
 * Object dateFormater = new java.text.SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");<br>
 * isParsable(dateFormater, "2001.07.04 AD at 12:08:56 PDT");<br></code>
 * <p>
 * 
 * @param parser    The Class type or instantiated Object to find a parse method in.
 * @param str   The String you want to parse
 * 
 * @return true if a parse method was found and completed without exception
 * @throws java.lang.NoSuchMethodException If no such method is accessible 
 */
public static boolean isParsable(Object parser, String str) {
    Class theClass = (parser instanceof Class? (Class)parser: parser.getClass());
    boolean staticOnly = (parser == theClass), foundAtLeastOne = false;
    Method[] methods = theClass.getMethods();

    // Loop over methods
    for (int index = 0; index < methods.length; index++) {
        Method method = methods[index];

        // If method starts with parse, is public and has one String parameter.
        // If the parser parameter was a Class, then also ensure the method is static. 
        if(method.getName().startsWith("parse") &&
            (!staticOnly || Modifier.isStatic(method.getModifiers())) &&
            Modifier.isPublic(method.getModifiers()) &&
            method.getGenericParameterTypes().length == 1 &&
            method.getGenericParameterTypes()[0] == String.class)
        {
            try {
                foundAtLeastOne = true;
                method.invoke(parser, str);
                return true; // Successfully parsed without exception
            } catch (Exception exception) {
                // If invoke problem, try a different method
                /*if(!(exception instanceof IllegalArgumentException) &&
                   !(exception instanceof IllegalAccessException) &&
                   !(exception instanceof InvocationTargetException))
                        continue; // Look for other parse methods*/

                // Parse method refuses to parse, look for another different method
                continue; // Look for other parse methods
            }
        }
    }

    // No more accessible parse method could be found.
    if(foundAtLeastOne) return false;
    else throw new RuntimeException(new NoSuchMethodException());
}


/**
 * METHOD: willParse<p><p>
 * 
 * A convienence method which calls the isParseable method, but does not throw any exceptions
 * which could be thrown through programatic errors.<p>
 * 
 * Use of {@link #isParseable(Object, String) isParseable} is recommended for use so programatic
 * errors can be caught in development, unless the value of the <code>parser</code> parameter is
 * unpredictable, or normal programtic exceptions should be ignored.<p>
 * 
 * See {@link #isParseable(Object, String) isParseable} for full description of method
 * usability.<p>
 * 
 * @param parser    The Class type or instantiated Object to find a parse method in.
 * @param str   The String you want to parse
 * 
 * @return true if a parse method was found and completed without exception
 * @see #isParseable(Object, String) for full description of method usability 
 */
public static boolean willParse(Object parser, String str) {
    try {
        return isParsable(parser, str);
    } catch(Throwable exception) {
        return false;
    }
}

5

要仅匹配仅包含ASCII数字的正十进制整数,请使用:

public static boolean isNumeric(String maybeNumeric) {
    return maybeNumeric != null && maybeNumeric.matches("[0-9]+");
}

5

一种性能良好的方法,避免尝试捕获并处理负数和科学计数法。

Pattern PATTERN = Pattern.compile( "^(-?0|-?[1-9]\\d*)(\\.\\d+)?(E\\d+)?$" );

public static boolean isNumeric( String value ) 
{
    return value != null && PATTERN.matcher( value ).matches();
}

5

这是我的类,用于检查字符串是否为数字。它还修复了数字字符串:

特征:

  1. 删除不必要的零[“ 12.0000000”->“ 12”]
  2. 删除不必要的零[“ 12.0580000”->“ 12.058”]
  3. 删除非数字字符[“ 12.00sdfsdf00”->“ 12”]
  4. 处理负字符串值[“ -12,020000”->“ -12.02”]
  5. 删除多个点[“ -12.0.20.000”->“ -12.02”]
  6. 没有额外的库,只有标准的Java

干得好...

public class NumUtils {
    /**
     * Transforms a string to an integer. If no numerical chars returns a String "0".
     *
     * @param str
     * @return retStr
     */
    static String makeToInteger(String str) {
        String s = str;
        double d;
        d = Double.parseDouble(makeToDouble(s));
        int i = (int) (d + 0.5D);
        String retStr = String.valueOf(i);
        System.out.printf(retStr + "   ");
        return retStr;
    }

    /**
     * Transforms a string to an double. If no numerical chars returns a String "0".
     *
     * @param str
     * @return retStr
     */
    static String makeToDouble(String str) {

        Boolean dotWasFound = false;
        String orgStr = str;
        String retStr;
        int firstDotPos = 0;
        Boolean negative = false;

        //check if str is null
        if(str.length()==0){
            str="0";
        }

        //check if first sign is "-"
        if (str.charAt(0) == '-') {
            negative = true;
        }

        //check if str containg any number or else set the string to '0'
        if (!str.matches(".*\\d+.*")) {
            str = "0";
        }

        //Replace ',' with '.'  (for some european users who use the ',' as decimal separator)
        str = str.replaceAll(",", ".");
        str = str.replaceAll("[^\\d.]", "");

        //Removes the any second dots
        for (int i_char = 0; i_char < str.length(); i_char++) {
            if (str.charAt(i_char) == '.') {
                dotWasFound = true;
                firstDotPos = i_char;
                break;
            }
        }
        if (dotWasFound) {
            String befDot = str.substring(0, firstDotPos + 1);
            String aftDot = str.substring(firstDotPos + 1, str.length());
            aftDot = aftDot.replaceAll("\\.", "");
            str = befDot + aftDot;
        }

        //Removes zeros from the begining
        double uglyMethod = Double.parseDouble(str);
        str = String.valueOf(uglyMethod);

        //Removes the .0
        str = str.replaceAll("([0-9])\\.0+([^0-9]|$)", "$1$2");

        retStr = str;

        if (negative) {
            retStr = "-"+retStr;
        }

        return retStr;

    }

    static boolean isNumeric(String str) {
        try {
            double d = Double.parseDouble(str);
        } catch (NumberFormatException nfe) {
            return false;
        }
        return true;
    }

}

5

正则表达式匹配

这是另一个带有更多验证的升级“ CraigTP”正则表达式示例。

public static boolean isNumeric(String str)
{
    return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
  1. 只有一个负号 -并且必须在开始处。
  2. 负号后必须有数字。
  3. 只有一个十进制符号 .允许。
  4. 十进制符号后必须有数字。

正则表达式测试

1                  --                   **VALID**
1.                 --                   INVALID
1..                --                   INVALID
1.1                --                   **VALID**
1.1.1              --                   INVALID

-1                 --                   **VALID**
--1                --                   INVALID
-1.                --                   INVALID
-1.1               --                   **VALID**
-1.1.1             --                   INVALID

5

异常的代价很高,但是在这种情况下,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);

}

}

通常,我认为这类代码将用于检查类似输入的内容。在那种情况下,速度不是一个考虑因素,并且做一些像抛出异常来检查数字或非数字之类的丑陋操作是错误的。
user872985

也许不会。键入的输入通常由UI组件检查,其中可以在提交值之前立即显示错误。验证大型输入文本文件中的字符串可能更常见-在这种情况下,性能至关重要。我在这里回答的目的是解决公认的答案中的“异常缓慢”语句。复杂的正则表达式要昂贵得多。而且我的代码中根本没有“丑陋的抛出”-只是一种检测违规的更快方法。使用先检查再计算的方法,您需要两次通过输入:一次进行验证,然后进行另一次转换。
ChrisCantrell

5

//请检查以下代码

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;
}

问题是“数字”,其中可能包含非整数值。
rghome

3
// only int
public static boolean isNumber(int num) 
{
    return (num >= 48 && c <= 57); // 0 - 9
}

// is type of number including . - e E 
public static boolean isNumber(String s) 
{
    boolean isNumber = true;
    for(int i = 0; i < s.length() && isNumber; i++) 
    {
        char c = s.charAt(i);
        isNumber = isNumber & (
            (c >= '0' && c <= '9') || (c == '.') || (c == 'e') || (c == 'E') || (c == '')
        );
    }
    return isInteger;
}

// is type of number 
public static boolean isInteger(String s) 
{
    boolean isInteger = true;
    for(int i = 0; i < s.length() && isInteger; i++) 
    {
        char c = s.charAt(i);
        isInteger = isInteger & ((c >= '0' && c <= '9'));
    }
    return isInteger;
}

public static boolean isNumeric(String s) 
{
    try
    {
        Double.parseDouble(s);
        return true;
    }
    catch (Exception e) 
    {
        return false;
    }
}

3

这个检查的简单示例:

public static boolean isNumericString(String input) {
    boolean result = false;

    if(input != null && input.length() > 0) {
        char[] charArray = input.toCharArray();

        for(char c : charArray) {
            if(c >= '0' && c <= '9') {
                // it is a digit
                result = true;
            } else {
                result = false;
                break;
            }
        }
    }

    return result;
}

3

您可以使用java.util.Scanner对象。

public static boolean isNumeric(String inputData) {
      Scanner sc = new Scanner(inputData);
      return sc.hasNextInt();
    }

2

我修改了CraigTP的解决方案,以接受科学计数法,同时也将点和逗号作为小数点分隔符

^-?\d+([,\.]\d+)?([eE]-?\d+)?$

var re = new RegExp("^-?\d+([,\.]\d+)?([eE]-?\d+)?$");
re.test("-6546"); // true
re.test("-6546355e-4456"); // true
re.test("-6546.355e-4456"); // true, though debatable
re.test("-6546.35.5e-4456"); // false
re.test("-6546.35.5e-4456.6"); // false

2

这就是为什么我喜欢.NET中的Try *方法的原因。除了类似于Java的传统Parse方法外,您还可以使用TryParse方法。我的Java语法不好(没有参数?),因此请将以下内容视为某种伪代码。它应该使概念变得清晰。

boolean parseInteger(String s, out int number)
{
    try {
        number = Integer.parseInt(myString);
        return true;
    } catch(NumberFormatException e) {
        return false;
    }
}

用法:

int num;
if (parseInteger("23", out num)) {
    // Do something with num.
}

是的,Java中没有“输出参数”,并且由于Integer包装器是不可变的(因此不能用作存储输出的有效引用),明智的惯用选项是返回一个Integer对象,如果解析则该对象为null失败了 一个更丑陋的选择可能是传递一个int [1]作为输出参数。
fortran

是的,我记得有关Java为什么没有输出参数的讨论。但是我想返回一个整数(如果需要,为null)也可以,尽管我不知道Java在装箱/拆箱方面的性能。
OregonGhost,2009年

4
我和下一个家伙一样喜欢C#,但是当Java中不存在该功能时,为Java问题添加.NET C#代码片段是没有用的
Shane 2015年

如果您不记录异常,将产生声纳问题
jmhostalet

2

解析它(即 Integer#parseInt)并简单地捕获异常。=)

需要澄清的是:parseInt函数检查它是否可以在任何情况下(显然)都可以解析该数字,并且无论如何您都想对其进行解析,那么实际进行解析不会对性能造成任何影响。

如果您不想解析它(或者非常非常很少地解析它),那么您当然可能希望以不同的方式来做。


1
如果可扩展使用,则
成本很高

如果您不记录异常,将产生声纳问题
jmhostalet

Double.parseDouble
Alex78191

2

您可以从Apache Commons Lang使用NumberUtils.isCreatable()。

由于NumberUtils.isNumber将在4.0中弃用,因此请改用NumberUtils.isCreatable()。


2

Java 8 Stream,lambda表达式,功能接口

处理所有情况(字符串为null,字符串为空等

String someString = null; // something="", something="123abc", something="123123"

boolean isNumeric = Stream.of(someString)
            .filter(s -> s != null && !s.isEmpty())
            .filter(Pattern.compile("\\D").asPredicate().negate())
            .mapToLong(Long::valueOf)
            .boxed()
            .findAny()
            .isPresent();

2

我已经说明了一些不使用任何API即可检查数字和小数的条件,

检查固定长度1位数字

Character.isDigit(char)

检查“固定长度”编号(假设长度为6)

String number = "132452";
if(number.matches("([0-9]{6})"))
System.out.println("6 digits number identified");

检查之间的可变长度数(假设长度为4到6)

//  {n,m}  n <= length <= m
String number = "132452";
if(number.matches("([0-9]{4,6})"))
System.out.println("Number Identified between 4 to 6 length");

String number = "132";
if(!number.matches("([0-9]{4,6})"))
System.out.println("Number not in length range or different format");

检查之间的可变长度十进制数(假设长度为4到7)

//  It will not count the '.' (Period) in length
String decimal = "132.45";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "1.12";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "1234";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "-10.123";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "123..4";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

String decimal = "132";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

String decimal = "1.1";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

希望对大家有帮助。


2

基于其他答案,我编写了自己的答案,它不使用模式或使用异常检查进行解析。

它最多检查一个负号,最多检查一个小数点。

以下是一些示例及其结果:

“ 1”,“-1”,“-1.5”和“ -1.556”返回true

“ 1..5”,“ 1A.5”,“ 1.5D”,“-”和“ --1”返回false

注意:如果需要,您可以修改它以接受Locale参数,并将其传递给DecimalFormatSymbols.getInstance()调用,以使用特定的Locale代替当前的Locale。

 public static boolean isNumeric(final String input) {
    //Check for null or blank string
    if(input == null || input.isBlank()) return false;

    //Retrieve the minus sign and decimal separator characters from the current Locale
    final var localeMinusSign = DecimalFormatSymbols.getInstance().getMinusSign();
    final var localeDecimalSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();

    //Check if first character is a minus sign
    final var isNegative = input.charAt(0) == localeMinusSign;
    //Check if string is not just a minus sign
    if (isNegative && input.length() == 1) return false;

    var isDecimalSeparatorFound = false;

    //If the string has a minus sign ignore the first character
    final var startCharIndex = isNegative ? 1 : 0;

    //Check if each character is a number or a decimal separator
    //and make sure string only has a maximum of one decimal separator
    for (var i = startCharIndex; i < input.length(); i++) {
        if(!Character.isDigit(input.charAt(i))) {
            if(input.charAt(i) == localeDecimalSeparator && !isDecimalSeparatorFound) {
                isDecimalSeparatorFound = true;
            } else return false;
        }
    }
    return true;
}

1

这是两种可能有效的方法。(不使用异常)。注意: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;
}

如果您想允许浮点数,则这是另一种方法,据称此方法允许表单中的数字通过1,123,123,123,123,123.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;
}

哦,好问题。我猜这只适用于普通类型的整数。该方法最初是为了过滤输入的电话号码和计数电话号码而创建的。
XForCE07
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.