代码之家  ›  专栏  ›  技术社区  ›  Bill the Lizard

检查字符串是否表示Java中的整数最好的方法是什么?

  •  188
  • Bill the Lizard  · 技术社区  · 16 年前

    我通常使用下面的习惯用法来检查字符串是否可以转换为整数。

    public boolean isInteger( String input ) {
        try {
            Integer.parseInt( input );
            return true;
        }
        catch( Exception e ) {
            return false;
        }
    }
    

    是我一个人,还是这看起来有点老土?更好的方法是什么?


    查看我的答案(带基准,基于 earlier answer 通过 CodingWithSpike )看看我为什么改变立场接受了 Jonas Klemming's answer 对于这个问题。我认为这个原始代码将被大多数人使用,因为它实现起来更快,而且更易于维护,但是当提供非整数数据时,它的速度要慢很多。

    35 回复  |  直到 6 年前
        1
  •  152
  •   Community CDub    6 年前

    如果您不关心潜在的溢出问题,此函数的执行速度将比使用 Integer.parseInt() .

    public static boolean isInteger(String str) {
        if (str == null) {
            return false;
        }
        if (str.isEmpty()) {
            return false;
        }
        int i = 0;
        if (str.charAt(0) == '-') {
            if (length == 1) {
                return false;
            }
            i = 1;
        }
        for (; i < length; i++) {
            char c = str.charAt(i);
            if (c < '0' || c > '9') {
                return false;
            }
        }
        return true;
    }
    
        2
  •  56
  •   Subhrajyoti Majumder MGPJ    11 年前

    你有,但你只能抓住 NumberFormatException .

        3
  •  35
  •   LarsH    8 年前

    做了一个快速的基准测试。异常实际上并不是那么昂贵,除非您开始返回多个方法,并且JVM必须做大量工作才能使执行堆栈就位。当保持同样的方法时,他们并不是表现不佳的人。

     public void RunTests()
     {
         String str = "1234567890";
    
         long startTime = System.currentTimeMillis();
         for(int i = 0; i < 100000; i++)
             IsInt_ByException(str);
         long endTime = System.currentTimeMillis();
         System.out.print("ByException: ");
         System.out.println(endTime - startTime);
    
         startTime = System.currentTimeMillis();
         for(int i = 0; i < 100000; i++)
             IsInt_ByRegex(str);
         endTime = System.currentTimeMillis();
         System.out.print("ByRegex: ");
         System.out.println(endTime - startTime);
    
         startTime = System.currentTimeMillis();
         for(int i = 0; i < 100000; i++)
             IsInt_ByJonas(str);
         endTime = System.currentTimeMillis();
         System.out.print("ByJonas: ");
         System.out.println(endTime - startTime);
     }
    
     private boolean IsInt_ByException(String str)
     {
         try
         {
             Integer.parseInt(str);
             return true;
         }
         catch(NumberFormatException nfe)
         {
             return false;
         }
     }
    
     private boolean IsInt_ByRegex(String str)
     {
         return str.matches("^-?\\d+$");
     }
    
     public boolean IsInt_ByJonas(String str)
     {
         if (str == null) {
                 return false;
         }
         int length = str.length();
         if (length == 0) {
                 return false;
         }
         int i = 0;
         if (str.charAt(0) == '-') {
                 if (length == 1) {
                         return false;
                 }
                 i = 1;
         }
         for (; i < length; i++) {
                 char c = str.charAt(i);
                 if (c <= '/' || c >= ':') {
                         return false;
                 }
         }
         return true;
     }
    

    输出:

    旁白:31

    Byregex:453(注:每次重新编译模式)

    ByJonas:16

    我同意乔纳斯·K的解决方案也是最有力的。看起来他赢了:)

        4
  •  34
  •   community wiki 2 revs, 2 users 83% Felipe    12 年前

    因为有可能人们仍然访问这里,在基准测试后会对regex产生偏见…所以我将给出基准测试的更新版本,以及regex的编译版本。与之前的基准相比,这一个显示了regex解决方案实际上具有始终如一的良好性能。

    复制自《蜥蜴比尔》并用编译版本更新:

    private final Pattern pattern = Pattern.compile("^-?\\d+$");
    
    public void runTests() {
        String big_int = "1234567890";
        String non_int = "1234XY7890";
    
        long startTime = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++)
                IsInt_ByException(big_int);
        long endTime = System.currentTimeMillis();
        System.out.print("ByException - integer data: ");
        System.out.println(endTime - startTime);
    
        startTime = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++)
                IsInt_ByException(non_int);
        endTime = System.currentTimeMillis();
        System.out.print("ByException - non-integer data: ");
        System.out.println(endTime - startTime);
    
        startTime = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++)
                IsInt_ByRegex(big_int);
        endTime = System.currentTimeMillis();
        System.out.print("\nByRegex - integer data: ");
        System.out.println(endTime - startTime);
    
        startTime = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++)
                IsInt_ByRegex(non_int);
        endTime = System.currentTimeMillis();
        System.out.print("ByRegex - non-integer data: ");
        System.out.println(endTime - startTime);
    
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++)
                IsInt_ByCompiledRegex(big_int);
        endTime = System.currentTimeMillis();
        System.out.print("\nByCompiledRegex - integer data: ");
        System.out.println(endTime - startTime);
    
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++)
                IsInt_ByCompiledRegex(non_int);
        endTime = System.currentTimeMillis();
        System.out.print("ByCompiledRegex - non-integer data: ");
        System.out.println(endTime - startTime);
    
    
        startTime = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++)
                IsInt_ByJonas(big_int);
        endTime = System.currentTimeMillis();
        System.out.print("\nByJonas - integer data: ");
        System.out.println(endTime - startTime);
    
        startTime = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++)
                IsInt_ByJonas(non_int);
        endTime = System.currentTimeMillis();
        System.out.print("ByJonas - non-integer data: ");
        System.out.println(endTime - startTime);
    }
    
    private boolean IsInt_ByException(String str)
    {
        try
        {
            Integer.parseInt(str);
            return true;
        }
        catch(NumberFormatException nfe)
        {
            return false;
        }
    }
    
    private boolean IsInt_ByRegex(String str)
    {
        return str.matches("^-?\\d+$");
    }
    
    private boolean IsInt_ByCompiledRegex(String str) {
        return pattern.matcher(str).find();
    }
    
    public boolean IsInt_ByJonas(String str)
    {
        if (str == null) {
                return false;
        }
        int length = str.length();
        if (length == 0) {
                return false;
        }
        int i = 0;
        if (str.charAt(0) == '-') {
                if (length == 1) {
                        return false;
                }
                i = 1;
        }
        for (; i < length; i++) {
                char c = str.charAt(i);
                if (c <= '/' || c >= ':') {
                        return false;
                }
        }
        return true;
    }
    

    结果:

    ByException - integer data: 45
    ByException - non-integer data: 465
    
    ByRegex - integer data: 272
    ByRegex - non-integer data: 131
    
    ByCompiledRegex - integer data: 45
    ByCompiledRegex - non-integer data: 26
    
    ByJonas - integer data: 8
    ByJonas - non-integer data: 2
    
        5
  •  28
  •   community wiki Łukasz Bownik    16 年前
    org.apache.commons.lang.StringUtils.isNumeric 
    

    虽然Java的标准LIB确实忽略了这样的效用函数。

    我认为Apache Calm是每个Java程序员必须具备的。

    可惜还没有移植到Java5上

        6
  •  22
  •   Jon Skeet    16 年前

    这部分取决于您所说的“可以转换为整数”。

    如果你的意思是“可以用Java转换成int”,那么乔纳斯的回答是一个很好的开始,但并不能很好地完成这项工作。例如,它将通过999999999999999999999999999。我将在该方法的末尾添加来自您自己问题的正常try/catch调用。

    字符按字符检查将有效地拒绝“不是整数”的情况下,留下“它是一个整数,但Java不能处理它”的情况下,会被更慢的异常路由所捕获。你 能够 也可以用手来做,但这是一个 许多 更复杂。

        7
  •  14
  •   rtruszk David Brunelle    8 年前

    关于regexp只有一条评论。这里提供的每个示例都是错误的!。如果要使用regexp,请不要忘记编译模式需要花费大量时间。这是:

    str.matches("^-?\\d+$")
    

    还有:

    Pattern.matches("-?\\d+", input);
    

    导致在每个方法调用中编译模式。要正确使用它,请执行以下操作:

    import java.util.regex.Pattern;
    
    /**
     * @author Rastislav Komara
     */
    public class NaturalNumberChecker {
        public static final Pattern PATTERN = Pattern.compile("^\\d+$");
    
        boolean isNaturalNumber(CharSequence input) {
            return input != null && PATTERN.matcher(input).matches();
        }
    }
    
        8
  •  12
  •   Community CDub    7 年前

    我复制了Rally25rs答案中的代码,并添加了一些非整数数据的测试。不可否认的是,结果支持乔纳斯·克莱明发表的方法。当您有整数数据时,我最初发布的exception方法的结果非常好,但如果没有,它们是最差的,而regex解决方案的结果(我敢打赌很多人会使用)是 一贯地 坏的。见 Felipe's answer 对于已编译的regex示例,这要快得多。

    public void runTests()
    {
        String big_int = "1234567890";
        String non_int = "1234XY7890";
    
        long startTime = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++)
            IsInt_ByException(big_int);
        long endTime = System.currentTimeMillis();
        System.out.print("ByException - integer data: ");
        System.out.println(endTime - startTime);
    
        startTime = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++)
            IsInt_ByException(non_int);
        endTime = System.currentTimeMillis();
        System.out.print("ByException - non-integer data: ");
        System.out.println(endTime - startTime);
    
        startTime = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++)
            IsInt_ByRegex(big_int);
        endTime = System.currentTimeMillis();
        System.out.print("\nByRegex - integer data: ");
        System.out.println(endTime - startTime);
    
        startTime = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++)
            IsInt_ByRegex(non_int);
        endTime = System.currentTimeMillis();
        System.out.print("ByRegex - non-integer data: ");
        System.out.println(endTime - startTime);
    
        startTime = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++)
            IsInt_ByJonas(big_int);
        endTime = System.currentTimeMillis();
        System.out.print("\nByJonas - integer data: ");
        System.out.println(endTime - startTime);
    
        startTime = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++)
            IsInt_ByJonas(non_int);
        endTime = System.currentTimeMillis();
        System.out.print("ByJonas - non-integer data: ");
        System.out.println(endTime - startTime);
    }
    
    private boolean IsInt_ByException(String str)
    {
        try
        {
            Integer.parseInt(str);
            return true;
        }
        catch(NumberFormatException nfe)
        {
            return false;
        }
    }
    
    private boolean IsInt_ByRegex(String str)
    {
        return str.matches("^-?\\d+$");
    }
    
    public boolean IsInt_ByJonas(String str)
    {
        if (str == null) {
                return false;
        }
        int length = str.length();
        if (length == 0) {
                return false;
        }
        int i = 0;
        if (str.charAt(0) == '-') {
                if (length == 1) {
                        return false;
                }
                i = 1;
        }
        for (; i < length; i++) {
                char c = str.charAt(i);
                if (c <= '/' || c >= ':') {
                        return false;
                }
        }
        return true;
    }
    

    结果:

    ByException - integer data: 47
    ByException - non-integer data: 547
    
    ByRegex - integer data: 390
    ByRegex - non-integer data: 313
    
    ByJonas - integer data: 0
    ByJonas - non-integer data: 16
    
        9
  •  8
  •   abalcerek    8 年前

    有番石榴版本:

    import com.google.common.primitives.Ints;
    
    Integer intValue = Ints.tryParse(stringValue);
    

    如果无法分析字符串,它将返回空值,而不是引发异常。

        10
  •  6
  •   Community CDub    7 年前

    这是更短的,但更短并不一定更好(它不会捕获超出范围的整数值, as pointed out in danatel's comment ):

    input.matches("^-?\\d+$");
    

    就个人而言,由于实现是在一个助手方法中进行的,而正确性胜过长度,所以我将使用类似于您所拥有的(减去捕获基 Exception 类而不是 NumberFormatException )

        11
  •  6
  •   Kaitie    12 年前

    可以使用String类的matches方法。[0-9]表示它可以是的所有值,+表示它必须至少有一个字符长,*表示它可以是零个或多个字符长。

    boolean isNumeric = yourString.matches("[0-9]+"); // 1 or more characters long, numbers only
    boolean isNumeric = yourString.matches("[0-9]*"); // 0 or more characters long, numbers only
    
        12
  •  3
  •   realPK    11 年前

    如果字符串数组包含纯整数和字符串,那么下面的代码应该可以工作。你只需要看第一个角色。 例如,[“4”,“44”,“ABC”,“77”,“Bond”]

    if (Character.isDigit(string.charAt(0))) {
        //Do something with int
    }
    
        13
  •  3
  •   Derek Mahar    10 年前

    您也可以使用 Scanner 类及其使用 hasNextInt() -这也允许您测试其他类型,如float等。

        14
  •  2
  •   duggu Neeraj Nama    11 年前

    你只要检查一下 数字格式异常 -

     String value="123";
     try  
     {  
        int s=Integer.parseInt(any_int_val);
        // do something when integer values comes 
     }  
     catch(NumberFormatException nfe)  
     {  
              // do something when string values comes 
     }  
    
        15
  •  2
  •   borjab    11 年前

    你可以试试apache-utils

    NumberUtils.isNumber( myText)
    

    See the javadoc here

        16
  •  2
  •   gil.fernandes    8 年前

    这是Jonas Klemming回答的Java 8变体:

    public static boolean isInteger(String str) {
        return str != null && str.length() > 0 &&
             IntStream.range(0, str.length()).allMatch(i -> i == 0 && (str.charAt(i) == '-' || str.charAt(i) == '+')
                      || Character.isDigit(str.charAt(i)));
    }
    

    测试代码:

    public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        Arrays.asList("1231231", "-1232312312", "+12313123131", "qwqe123123211", "2", "0000000001111", "", "123-", "++123",
                "123-23", null, "+-123").forEach(s -> {
            System.out.printf("%15s %s%n", s, isInteger(s));
        });
    }
    

    测试代码的结果:

            1231231 true
        -1232312312 true
       +12313123131 true
      qwqe123123211 false
                  2 true
      0000000001111 true
                    false
               123- false
              ++123 false
             123-23 false
               null false
              +-123 false
    
        17
  •  1
  •   Kristian    16 年前

    怎么样:

    return Pattern.matches("-?\\d+", input);
    
        18
  •  1
  •   community wiki mobra66    13 年前

    您可能还需要考虑用例:

    如果大多数时候您希望数字是有效的,那么捕获异常只会在尝试转换无效数字时造成性能开销。但是打电话给 isInteger() 方法,然后使用 Integer.parseInt() 总是 导致有效数字的性能开销-字符串被分析两次,一次通过检查,一次通过转换。

        19
  •  1
  •   Wayne    10 年前

    这是对 乔纳斯 '检查字符串是否在要转换为整数的范围内的代码。

    public static boolean isInteger(String str) {
        if (str == null) {
            return false;
        }
        int length = str.length();
        int i = 0;
    
        // set the length and value for highest positive int or lowest negative int
        int maxlength = 10;
        String maxnum = String.valueOf(Integer.MAX_VALUE);
        if (str.charAt(0) == '-') { 
            maxlength = 11;
            i = 1;
            maxnum = String.valueOf(Integer.MIN_VALUE);
        }  
    
        // verify digit length does not exceed int range
        if (length > maxlength) { 
            return false; 
        }
    
        // verify that all characters are numbers
        if (maxlength == 11 && length == 1) {
            return false;
        }
        for (int num = i; num < length; num++) {
            char c = str.charAt(num);
            if (c < '0' || c > '9') {
                return false;
            }
        }
    
        // verify that number value is within int range
        if (length == maxlength) {
            for (; i < length; i++) {
                if (str.charAt(i) < maxnum.charAt(i)) {
                    return true;
                }
                else if (str.charAt(i) > maxnum.charAt(i)) {
                    return false;
                }
            }
        }
        return true;
    }
    
        20
  •  1
  •   timxyz    9 年前

    如果您使用的是Android API,则可以使用:

    TextUtils.isDigitsOnly(str);
    
        21
  •  1
  •   Radiodef    7 年前

    另一种选择:

    private boolean isNumber(String s) {
        boolean isNumber = true;
        for (char c : s.toCharArray()) {
            isNumber = isNumber && Character.isDigit(c);
        }
        return isNumber;
    }
    
        22
  •  1
  •   user8513960    7 年前

    如果你想检查字符串是否代表一个整型的整型,我对jonas的答案做了一些修改,这样那些代表大于integer.max_value或小于integer.min_value的整型的字符串将返回false。例如:“3147483647”将返回false,因为3147483647大于2147483647,同样,“-2147483649”也将返回false,因为-2147483649小于-2147483648。

    public static boolean isInt(String s) {
      if(s == null) {
        return false;
      }
      s = s.trim(); //Don't get tricked by whitespaces.
      int len = s.length();
      if(len == 0) {
        return false;
      }
      //The bottom limit of an int is -2147483648 which is 11 chars long.
      //[note that the upper limit (2147483647) is only 10 chars long]
      //Thus any string with more than 11 chars, even if represents a valid integer, 
      //it won't fit in an int.
      if(len > 11) {
        return false;
      }
      char c = s.charAt(0);
      int i = 0;
      //I don't mind the plus sign, so "+13" will return true.
      if(c == '-' || c == '+') {
        //A single "+" or "-" is not a valid integer.
        if(len == 1) {
          return false;
        }
        i = 1;
      }
      //Check if all chars are digits
      for(; i < len; i++) {
        c = s.charAt(i);
        if(c < '0' || c > '9') {
          return false;
        }
      }
      //If we reached this point then we know for sure that the string has at
      //most 11 chars and that they're all digits (the first one might be a '+'
      // or '-' thought).
      //Now we just need to check, for 10 and 11 chars long strings, if the numbers
      //represented by the them don't surpass the limits.
      c = s.charAt(0);
      char l;
      String limit;
      if(len == 10 && c != '-' && c != '+') {
        limit = "2147483647";
        //Now we are going to compare each char of the string with the char in
        //the limit string that has the same index, so if the string is "ABC" and
        //the limit string is "DEF" then we are gonna compare A to D, B to E and so on.
        //c is the current string's char and l is the corresponding limit's char
        //Note that the loop only continues if c == l. Now imagine that our string
        //is "2150000000", 2 == 2 (next), 1 == 1 (next), 5 > 4 as you can see,
        //because 5 > 4 we can guarantee that the string will represent a bigger integer.
        //Similarly, if our string was "2139999999", when we find out that 3 < 4,
        //we can also guarantee that the integer represented will fit in an int.
        for(i = 0; i < len; i++) {
          c = s.charAt(i);
          l = limit.charAt(i);
          if(c > l) {
            return false;
          }
          if(c < l) {
            return true;
          }
        }
      }
      c = s.charAt(0);
      if(len == 11) {
        //If the first char is neither '+' nor '-' then 11 digits represent a 
        //bigger integer than 2147483647 (10 digits).
        if(c != '+' && c != '-') {
          return false;
        }
        limit = (c == '-') ? "-2147483648" : "+2147483647";
        //Here we're applying the same logic that we applied in the previous case
        //ignoring the first char.
        for(i = 1; i < len; i++) {
          c = s.charAt(i);
          l = limit.charAt(i);
          if(c > l) {
            return false;
          }
          if(c < l) {
            return true;
          }
        }
      }
      //The string passed all tests, so it must represent a number that fits
      //in an int...
      return true;
    }
    
        23
  •  0
  •   Ricardo Acras    16 年前
    is_number = true;
    try {
      Integer.parseInt(mystr)
    } catch (NumberFormatException  e) {
      is_number = false;
    }
    
        24
  •  0
  •   lucas    16 年前

    你所做的是有效的,但你可能不应该总是这样检查。抛出异常应该为“异常”情况保留(也许这适合您的情况,但是),并且在性能方面非常昂贵。

        25
  •  0
  •   Ran Biron    16 年前
    Number number;
    try {
        number = NumberFormat.getInstance().parse("123");
    } catch (ParseException e) {
        //not a number - do recovery.
        e.printStackTrace();
    }
    //use number
    
        26
  •  0
  •   community wiki 2 revs callejero    13 年前

    这只对正整数有效。

    public static boolean isInt(String str) {
        if (str != null && str.length() != 0) {
            for (int i = 0; i < str.length(); i++) {
                if (!Character.isDigit(str.charAt(i))) return false;
            }
        }
        return true;        
    }
    
        27
  •  0
  •   emmanuel    10 年前

    这对我有用。只需标识字符串是基元还是数字。

    private boolean isPrimitive(String value){
            boolean status=true;
            if(value.length()<1)
                return false;
            for(int i = 0;i<value.length();i++){
                char c=value.charAt(i);
                if(Character.isDigit(c) || c=='.'){
    
                }else{
                    status=false;
                    break;
                }
            }
            return status;
        }
    
        28
  •  0
  •   Roger F. Gay    10 年前

    要检查所有int字符,只需使用双负。

    如果(!)searchString.matches(“[^0-9]+$”)…

    [^0-9]+$检查是否有非整数字符,如果为真,则测试失败。但不是那样,你就会成功。

        29
  •  0
  •   shellbye    9 年前

    发现这可能有帮助:

    public static boolean isInteger(String self) {
        try {
            Integer.valueOf(self.trim());
            return true;
        } catch (NumberFormatException nfe) {
            return false;
        }
    }
    
        30
  •  0
  •   mark_infinite    9 年前

    我相信发生异常的风险是零的,因为正如您在下面看到的,您总是安全地分析 int String 而不是反过来。

    所以:

    1. 检查 如果字符串中的每个字符槽至少匹配 其中一个角色 “0”、“1”、“2”、“3”、“4”、“5”、“6”、“7”、“8”、“9” .

      if(aString.substring(j, j+1).equals(String.valueOf(i)))
      
    2. 总和 你在上面的插槽中遇到的所有时间 字符。

      digits++;
      
    3. 最后你 检查 如果遇到整数的次数为 字符等于给定字符串的长度。

      if(digits == aString.length())
      

    实际上,我们有:

        String aString = "1234224245";
        int digits = 0;//count how many digits you encountered
        for(int j=0;j<aString.length();j++){
            for(int i=0;i<=9;i++){
                if(aString.substring(j, j+1).equals(String.valueOf(i)))
                        digits++;
            }
        }
        if(digits == aString.length()){
            System.out.println("It's an integer!!");
            }
        else{
            System.out.println("It's not an integer!!");
        }
    
        String anotherString = "1234f22a4245";
        int anotherDigits = 0;//count how many digits you encountered
        for(int j=0;j<anotherString.length();j++){
            for(int i=0;i<=9;i++){
                if(anotherString.substring(j, j+1).equals(String.valueOf(i)))
                        anotherDigits++;
            }
        }
        if(anotherDigits == anotherString.length()){
            System.out.println("It's an integer!!");
            }
        else{
            System.out.println("It's not an integer!!");
        }
    

    结果是:

    它是一个整数!!

    不是整数!!

    同样,您可以验证 是一个 float 或A double 但在这种情况下,你必须面对 只有一个。 (点)在字符串中,当然检查 digits == (aString.length()-1)

    同样,这里也没有遇到解析异常的风险,但是如果您计划解析一个已知包含数字的字符串(比如 int 数据类型)必须首先检查它是否适合数据类型。否则你必须铸造它。

    我希望我帮助