在解析字符串之前如何检查字符串是否为数字?
40 回答
这通常通过一个简单的用户定义函数来完成(即滚动你自己的“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) {
ParsePosition pos = new ParsePosition(0);
NumberFormat.getInstance().parse(str, pos);
return str.length() == pos.getIndex();
}
使用Apache Commons Lang 3.5 及更高版本:NumberUtils.isCreatable
或StringUtils.isNumeric
.
使用Apache Commons Lang 3.4 及以下版本:NumberUtils.isNumber
或StringUtils.isNumeric
.
您还可以使用StringUtils.isNumericSpace
which 返回true
空字符串并忽略字符串中的内部空格。另一种方法是使用NumberUtils.isParsable
which 基本上检查数字是否可以根据 Java 解析。(链接的 javadocs 包含每种方法的详细示例。)
Java 8 lambda 表达式。
String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );
如果你在安卓上,那么你应该使用:
android.text.TextUtils.isDigitsOnly(CharSequence str)
保持简单。大多数人都可以“重新编程”(同样的事情)。
正如@CraigTP 在他的出色回答中提到的那样,我对使用异常来测试字符串是否为数字也有类似的性能问题。所以我最终拆分字符串并使用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;
}
Google 的 Guava 库提供了一个很好的辅助方法来做到这一点:Ints.tryParse
. 您可以像使用它一样使用它,Integer.parseInt
但如果字符串未解析为有效整数,它会返回null
而不是抛出异常。请注意,它返回整数,而不是整数,因此您必须将其转换/自动装箱回整数。
例子:
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 的答案相似,但略有不同。在它们的实现中没有异常处理开销。
不要使用异常来验证您的值。 使用 Util 库,而不是像 apache NumberUtils:
NumberUtils.isNumber(myStringValue);
编辑:
请注意,如果您的字符串以 0 开头,NumberUtils 会将您的值解释为十六进制。
NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false
为什么每个人都在推动异常/正则表达式解决方案?
虽然我可以理解大多数人都可以使用 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 用于程序流。这是一个例子。
有趣的是,简单的 if 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() 的测试
public static boolean isNumeric(String str)
{
return str.matches("-?\\d+(.\\d+)?");
}
CraigTP 的正则表达式(如上所示)会产生一些误报。例如,“23y4”将被视为一个数字,因为 '.' 匹配任何非小数点的字符。
它还将拒绝任何带有前导“+”的数字
避免这两个小问题的替代方法是
public static boolean isNumeric(String str)
{
return str.matches("[+-]?\\d*(\\.\\d+)?");
}
我们可以尝试用 ("") 替换给定字符串中的所有数字,即空格,如果之后字符串的长度为零,那么我们可以说给定字符串只包含数字。例子:
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;
}
您可以使用NumberFormat#parse
:
try
{
NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
// Not a number.
}
如果您使用 java 开发 Android 应用程序,您可以使用TextUtils.isDigitsOnly函数。
这是我对这个问题的回答。
一个包罗万象的便捷方法,您可以使用它来使用任何类型的解析器解析任何字符串:isParsable(Object parser, String str)
。解析器可以是 aClass
或object
. 这也将允许您使用您编写的自定义解析器,并且应该适用于任何场景,例如:
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;
}
}
一种性能良好的方法,避免了 try-catch 和处理负数和科学记数法。
Pattern PATTERN = Pattern.compile( "^(-?0|-?[1-9]\\d*)(\\.\\d+)?(E\\d+)?$" );
public static boolean isNumeric( String value )
{
return value != null && PATTERN.matcher( value ).matches();
}
要仅匹配仅包含 ASCII 数字的以十为基数的正整数,请使用:
public static boolean isNumeric(String maybeNumeric) {
return maybeNumeric != null && maybeNumeric.matches("[0-9]+");
}
正则表达式匹配
这是另一个升级“CraigTP”正则表达式匹配更多验证的例子。
public static boolean isNumeric(String str)
{
return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
- 只允许一个负号-并且必须在开头。
- 负号后必须有数字。
- .只允许一个十进制符号。
- 十进制符号后必须有数字。
正则表达式测试
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
这是我检查字符串是否为数字的课程。它还修复了数字字符串:
特征:
- 删除不必要的零 ["12.0000000" -> "12"]
- 删除不必要的零 ["12.0580000" -> "12.058"]
- 删除非数字字符 ["12.00sdfsdf00" -> "12"]
- 处理负字符串值 ["-12,020000" -> "-12.02"]
- 删除多个点 ["-12.0.20.000" -> "-12.02"]
- 没有额外的库,只有标准的 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;
}
}
例外是昂贵的,但在这种情况下,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;
}
您可以使用 java.util.Scanner 对象。
public static boolean isNumeric(String inputData) {
Scanner sc = new Scanner(inputData);
return sc.hasNextInt();
}
// 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;
}
}
这是此检查的一个简单示例:
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;
}
我已经说明了一些在不使用任何 API 的情况下检查数字和小数的条件,
检查固定长度 1 位数字
Character.isDigit(char)
检查固定长度编号(假设长度为 6)
String number = "132452";
if(number.matches("([0-9]{6})"))
System.out.println("6 digits number identified");
检查 Varying Length number between(假设 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");
检查 Varying Length 之间的十进制数(假设 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");
希望它会帮助很多人。
根据我自己编写的其他答案,它不使用模式或解析异常检查。
它最多检查一个减号并检查最多一个小数点。
以下是一些示例及其结果:
“1”、“-1”、“-1.5”和“-1.556”返回真
“1..5”、“1A.5”、“1.5D”、“-”和“--1”返回假
注意:如果需要,您可以修改它以接受 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;
}
解析它(即用Integer#parseInt
)并简单地捕获异常。=)
澄清一下: parseInt 函数检查它是否可以在任何情况下(显然)解析数字,如果你想解析它,你不会因为实际进行解析而受到任何性能影响。
如果您不想解析它(或非常非常少地解析它),您当然可能希望以不同的方式进行。
这就是我喜欢 .NET 中的 Try* 方法的原因。除了类似于 Java 的传统 Parse 方法之外,您还有一个 TryParse 方法。我不擅长Java语法(out参数?),所以请将以下内容视为某种伪代码。不过,它应该使概念清晰。
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.
}
我修改了 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
Java 8 Stream、lambda 表达式、函数式接口
处理的所有情况(字符串为空,字符串为空等)
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();
您可以使用Apache Commons Lang的 NumberUtils.isCreatable() 。
由于 NumberUtils.isNumber 将在 4.0 中弃用,因此请改用 NumberUtils.isCreatable()。
我认为可靠地判断字符串是否为数字的唯一方法是解析它。所以我只是解析它,如果它是一个数字,你可以免费获得 int 中的数字!
BigDecimal
如果字符串可能包含小数,您可以使用:
try {
new java.math.BigInteger(testString);
} catch(NumberFormatException e) {
throw new RuntimeException("Not a valid number");
}
这里有两种可能有效的方法。(不使用异常)。注意: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;
}
如果您想使用正则表达式进行检查,您应该创建一个最终的静态 Pattern 对象,这样正则表达式只需要编译一次。编译正则表达式的时间与执行匹配的时间差不多,因此通过采取这种预防措施,您可以将方法的执行时间减半。
final static Pattern NUMBER_PATTERN = Pattern.compile("[+-]?\\d*\\.?\\d+");
static boolean isNumber(String input) {
Matcher m = NUMBER_PATTERN.matcher(input);
return m.matches();
}
我假设一个数字是一个字符串,其中只有十进制数字,开头可能有 + 或 - 号,最多有一个小数点(不是结尾),没有其他字符(包括逗号、空格、数字其他计数系统、罗马数字、象形文字)。
此解决方案简洁且非常快,但您可以通过这样做每百万次调用减少几毫秒
static boolean isNumber(String s) {
final int len = s.length();
if (len == 0) {
return false;
}
int dotCount = 0;
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
if (c < '0' || c > '9') {
if (i == len - 1) {//last character must be digit
return false;
} else if (c == '.') {
if (++dotCount > 1) {
return false;
}
} else if (i != 0 || c != '+' && c != '-') {//+ or - allowed at start
return false;
}
}
}
return true;
}
试试这个:
public boolean isNumber(String str)
{
short count = 0;
char chc[] = {'0','1','2','3','4','5','6','7','8','9','.','-','+'};
for (char c : str.toCharArray())
{
for (int i = 0;i < chc.length;i++)
{
if( c == chc[i]){
count++;
}
}
}
if (count != str.length() )
return false;
else
return true;
}
这是我知道检查字符串是否为数字的最快方法:
public static boolean isNumber(String str){
int i=0, len=str.length();
boolean a=false,b=false,c=false, d=false;
if(i<len && (str.charAt(i)=='+' || str.charAt(i)=='-')) i++;
while( i<len && isDigit(str.charAt(i)) ){ i++; a=true; }
if(i<len && (str.charAt(i)=='.')) i++;
while( i<len && isDigit(str.charAt(i)) ){ i++; b=true; }
if(i<len && (str.charAt(i)=='e' || str.charAt(i)=='E') && (a || b)){ i++; c=true; }
if(i<len && (str.charAt(i)=='+' || str.charAt(i)=='-') && c) i++;
while( i<len && isDigit(str.charAt(i)) ){ i++; d=true;}
return i==len && (a||b) && (!c || (c && d));
}
static boolean isDigit(char c){
return c>='0' && c<='9';
}
使用IntStream并行检查很长的字符串
在 Java 8 中,以下测试给定的所有字符string
是否在 '0' 到 '9' 之间。请注意,接受空字符串:
string.chars().unordered().parallel().allMatch( i -> '0' <= i && '9' >= i )
String text="hello 123";
if(Pattern.matches([0-9]+))==true
System.out.println("String"+text);
如果你们使用以下方法来检查:
public static boolean isNumeric(String str) {
NumberFormat formatter = NumberFormat.getInstance();
ParsePosition pos = new ParsePosition(0);
formatter.parse(str, pos);
return str.length() == pos.getIndex();
}
那么输入很长的String会发生什么,比如我调用这个方法:
System.out.println(isNumeric("94328948243242352525243242524243425452342343948923"));
结果是“真的”,也是一个太大的数字!如果您使用正则表达式进行检查,也会发生同样的事情!所以我宁愿使用“解析”的方法来检查,像这样:
public static boolean isNumeric(String str) {
try {
int number = Integer.parseInt(str);
return true;
} catch (Exception e) {
return false;
}
}
结果是我所期望的!
private static Pattern p = Pattern.compile("^[0-9]*$");
public static boolean isNumeric(String strNum) {
if (strNum == null) {
return false;
}
return p.matcher(strNum).find();
}
import java.util.Scanner;
public class TestDemo {
public static void main(String[] args) {
boolean flag = true;
Scanner sc = new Scanner(System.in);
System.out.println("Enter the String:");
String str = sc.nextLine();
for (int i = 0; i < str.length(); i++) {
if(str.charAt(i) > 48 && str.charAt(i) < 58) {
flag = false;
break;
}
}
if(flag == true) {
System.out.println("String is a valid String.");
} else {
System.out.println("String contains number.");
}
}
}