Bir String'in Java'da bir tamsayıyı temsil edip etmediğini kontrol etmenin en iyi yolu nedir?


214

Normalde bir dize bir tamsayı dönüştürülebilir olup olmadığını kontrol etmek için aşağıdaki deyimi kullanın.

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

Sadece ben mi, yoksa bu biraz acayip görünüyor mu? Daha iyi bir yol nedir?


(Dayalı kriterler, benim cevap bakınız önceki cevap tarafından CodingWithSpike buradaki konumumu ters ve kabul ettik neden) görmek Jonas Klemming yanıtını bu soruna. Bu orijinal kod çoğu insan tarafından kullanılacağını düşünüyorum çünkü uygulanması daha hızlı ve daha sürdürülebilir, ancak tamsayı olmayan veriler sağlandığında büyüklük sıralamaları daha yavaş.


Çözüm için RegExp hakkında ne düşünüyorsunuz?
Akshay Pethani

Yanıtlar:


171

Potansiyel taşma sorunlarıyla ilgilenmiyorsanız, bu işlev kullanmaktan yaklaşık 20-30 kat daha hızlı çalışacaktır Integer.parseInt().

public static boolean isInteger(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 < '0' || c > '9') {
            return false;
        }
    }
    return true;
}

50
(c <= '/' || c> = ':') biraz garip görünüyor. Ben kullanırım (c <'0' || c> '9') ... <= ve> = operatörleri Java'da daha hızlı mı?
Anonim

3
Neden regex kullanılmıyor? Return str.matches ("^ -? \\ d + $") yukarıdaki kodla aynı değil.
Maglob

15
Ben regex önce sorudan bu yöntemi veya orijinal yöntemi kullanabilirsiniz. Bu performans için, uygulama hızı ve saf sürdürülebilirlik için orijinal yöntem. Normal ifade çözümünün bunun için hiçbir şeyi yoktur.
Kertenkele Bill

4
Taşma konusunda endişeliyim, ancak bu yöntem BigInts için uyarlanabilir ve diğer yöntemlerden çok daha hızlı olabilir. Herhangi birinin neden bu kadar basit bir soruna bu kadar çaba harcadığımı merak etmesi durumunda, Project Euler problemlerini çözmeye yardımcı olacak bir kütüphane oluşturuyorum.
Kertenkele Bill

1
Dizeyi gerçekten bir int veya uzun olarak ayrıştırabileceğiniz konusunda endişeleriniz varsa, dizenin temsil ettiği tamsayının bu veri türlerine gerçekten uyup uymadığını da kontrol etmeniz gerekir.
Jonas K

65

Sende var, ama sadece yakalamalısın NumberFormatException.


7
Evet, ihtiyacınız olandan daha fazla istisna yakalamak kötü bir form olarak kabul edilir.
Chris

Haklısın. NFE atılabilen tek kişi, ama yine de içine girmek kötü bir alışkanlık.
Kertenkele Bill

Bence giriş null ise bir NPE atılabilir, bu nedenle yöntemi muhtemelen açıkça, hangi şekilde isterseniz işlemeli.
Dov Wasserman

@Dov: Haklısın NPE ve NFE'nin her ikisi de açıkça yakalanmalı.
Kertenkele Bill

Bu yanıt, bu sorunun gerçek cevabı olmalıdır.
Breedly

40

Hızlı bir kıyaslama yaptı. İstisnalar aslında bu kadar pahalı değildir, birden fazla yöntemi geri atmaya başlamadığınız ve JVM'nin yürütme yığınını yerine getirmek için çok fazla iş yapması gerekmiyorsa. Aynı yöntemle kalırken, kötü performans göstermezler.

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

Çıktı:

ByException: 31

ByRegex: 453 (not: kalıbı her seferinde yeniden derleme)

ByJonas: 16

Jonas K'nin çözümünün de en sağlam çözüm olduğuna katılıyorum. Kazanıyor gibi görünüyor :)


13
Üçünü de karşılaştırmak için harika bir fikir. Regex ve Jonas yöntemlerine adil olmak için, tamsayı olmayan dizelerle test etmelisiniz, çünkü Integer.parseInt yöntemi gerçekten yavaşlayacaktır.
Kertenkele Bill

4
Üzgünüz ama bu normal ifade testi iyi değil. (1) için düzenli ifade motoru kontrol yapmak gerekmez ^ve $içinde yana ikinci kez matchesregex eşleşmelidir tüm dize, (2) str.matchesher zaman kendi yaratmak zorunda kalacak Patternpahalı olduğu. Performans nedenleriyle, böyle bir Deseni bu yöntemin dışında bir kez oluşturmalı ve içinde kullanmalıyız. (3) Ayrıca yalnızca bir Matcher nesnesi oluşturabilir ve reset(CharSequence)bunu kullanıcı verilerini iletmek ve matches()sonucunu döndürmek için kullanabiliriz .
Pshemo

Yani böyle bir şey private final Matcher m = Pattern.compile("-?\\d+").matcher(""); private boolean byRegex(String str) { return m.reset(str).matches(); }daha iyi performansa sahip olmalıdır.
Pshemo

@Pshemo Integer.valueOf ("1") ve Integer.valueOf ("1") istisna atar, bu nedenle ^ ve $ denetimi makul görünür.
cquezel

1
@cquezel Evet, ama değil gerekli beri matchesisimli ekleyerek ^ve $dolaylı. Sonucu bir göz atın " 123".matches("\\d+")ve "123".matches("\\d+"). Göreceksin falseve true. falsedize, normal ifadeyle tamamen eşleştirilmesini engelleyen boşlukla başladığı için döndürülür.
Pshemo

37

İnsanların hala burayı ziyaret etmeleri ve kıyaslamalardan sonra Regex'e karşı önyargılı olma ihtimalleri olduğu için ... Ben de karşılaştırmanın güncellenmiş bir versiyonunu Regex'in derlenmiş bir versiyonuyla vereceğim. Önceki kıyaslamaların aksine, bu Regex çözümünün aslında sürekli olarak iyi bir performansa sahip olduğunu gösteriyor.

Bill the Lizard'dan kopyalandı ve derlenmiş sürümle güncellendi:

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

Sonuçlar:

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

1
ByCompiledRegex zamanı, regex'in zaman ölçümünde derlenmesini içermelidir.
Martin Carney

2
@MartinCarney Ben değiştirdim ve kıyaslama desen derleme. Açıkçası CPU / JIT'im daha hızlı, ancak geri enterpole edersem derleme zamanı 336.
ot kurutma makinesi42

2
açık olmak gerekirse, 336 (ms), diğer tüm satırlar gibi, desen derlemesi 100k kez yapıldığında olan şeydir. Sadece bir kez yapıldığına dair ima ile, zamanı temelde sıfırdır.
tedder42

Kaydı doğrudan derlenmiş normal ifadelere ayarladığınız için teşekkür ederiz.
LarsH

Belki "^[+-]?\\d+$"daha da iyi olurdu.
Adam

34
org.apache.commons.lang.StringUtils.isNumeric 

Java'nın standart lib'i bu tür yardımcı program işlevlerini gerçekten özlüyor olsa da

Apache Commons'ın her Java programcısı için "olması gerekir" olduğunu düşünüyorum

çok kötü, henüz Java5'e taşınmadı


1
Bununla ilgili tek sorun
taşmadır

2
Diğer sorun negatif sayılar, ama ben de +1, çünkü bence bu yaklaşım iyi bir çözüme en yakın geliyor.
sandris

22

Kısmen "tamsayıya dönüştürülebilir" ile ne demek istediğinize bağlıdır.

"Java'da int'e dönüştürülebilir" demek istiyorsanız, Jonas'ın cevabı iyi bir başlangıçtır, ancak işi oldukça bitirmez. Örneğin 999999999999999999999999999999'u geçecekti. Yöntemin sonunda kendi sorunuzdan normal try / catch çağrısını eklerdim.

Karakter karakter kontrolleri, "bir tamsayı değil" durumlarını etkin bir şekilde reddeder, bu da bir tamsayıdır, ancak Java bunu kaldıramaz. Sen olabilir de elle bu düşeni yapmak, ancak bir olurdu çok daha karmaşık.


17

Regexp hakkında sadece bir yorum. Burada verilen her örnek yanlış !. Regexp kullanmak istiyorsanız, desen derlemenin çok zaman aldığını unutmayın. Bu:

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

ve ayrıca bu:

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

her yöntem çağrısında desen derlemesine neden olur. Doğru bir şekilde kullanmak için şunları izleyin:

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

5
Eşleştiriciyi önceden de oluşturarak ve girdiye uygulamak için reset () yöntemini kullanarak biraz daha fazla performans elde edebilirsiniz.
Alan Moore

13

Guava sürümü var:

import com.google.common.primitives.Ints;

Integer intValue = Ints.tryParse(stringValue);

Dize ayrıştırılamazsa istisna atmak yerine null değerini döndürür.


3
En iyi cevap IMHO. Kendi çözümünüzü geliştirmek yerine iyi test edilmiş kütüphaneler kullanın. (Ayrıca tartışmaya bakınız burada .)
Olivier CAILLOUX

12

Ben rally25rs cevap kod kopyaladı ve tamsayı olmayan veriler için bazı testler ekledi. Sonuçlar yadsınamaz bir şekilde Jonas Klemming tarafından yayınlanan yöntemin lehinedir. Tam sayı verileriniz olduğunda ilk olarak gönderdiğim İstisna yönteminin sonuçları oldukça iyi, ancak RegEx çözümünün sonuçları (bir çok insanın kullanacağına bahse gireceğim) idi sürekli kötü. Çok daha hızlı derlenmiş normal ifade örneği için Felipe'nin cevabına bakınız .

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

Sonuçlar:

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

6

Bu daha kısa, ancak daha kısa olması daha iyi değildir (ve danatel'in yorumunda belirtildiği gibi aralık dışında olan tamsayı değerlerini yakalamaz ):

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

Şahsen, uygulama yardımcı bir yöntemle sincaplandığından ve doğruluk uzunluğa düştüğü için, sadece sahip olduğunuz gibi bir şeyle giderdim (eksi temel Exceptionsınıfı yakalamak değil NumberFormatException).


1
Ve belki de \\ d {1,10}, mükemmel olmasa da, Java Tamsayıları yakalamak için \\ d + 'dan daha iyidir
Maglob

6

String sınıfının match yöntemini kullanabilirsiniz. [0-9], olabileceği tüm değerleri temsil eder, +, en az bir karakter uzunluğunda olması gerektiği anlamına gelir ve *, sıfır veya daha fazla karakter uzunluğunda olabileceği anlamına gelir.

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

1
Bu normalde geçerli tamsayı olarak dahil edilecek "+10" veya "-10") ile eşleşmiyor
Tim Wintle

4

Nasıl olur:

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

9999999999999999999999999999999999 tamsayı ne olacak?
danatel

Negatif işareti kontrol etmeyi unutmayın.
Jeremy Ruten

Normal ifadenin başlangıcını ve sonunu tutturmanıza gerek yok, bu yüzden "aaa-1999zzz" yi geçmeyeceksiniz?
Tim Howland

2
Tim, match () yöntemlerinden birini çağırdığınızda (String, Pattern ve Matcher'ın her birinde bir tane bulunur), normal ifadenin tüm girdiyle eşleşmesi ve çapaların gereksiz olması gerekir. Diğer regex lezzetlerinin çoğu tarafından tanımlanan bir eşleşme bulmak için Matcher # find () kullanmanız gerekir.
Alan Moore

4

Bu, Jonas Klemming yanıtının Java 8 varyasyonudur:

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

Test kodu:

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

Test kodunun sonuçları:

        1231231 true
    -1232312312 true
   +12313123131 true
  qwqe123123211 false
              2 true
  0000000001111 true
                false
           123- false
          ++123 false
         123-23 false
           null false
          +-123 false

3

Sadece NumberFormatException kontrol edin : -

 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 
 }  

3

Dize diziniz saf Tamsayılar ve Dizeler içeriyorsa, aşağıdaki kodun çalışması gerekir. Sadece ilk karaktere bakmalısın. örneğin ["4", "44", "abc", "77", "bağ"]

if (Character.isDigit(string.charAt(0))) {
    //Do something with int
}


2

Dizenin int türüne uyan bir tamsayıyı temsil edip etmediğini kontrol etmek isterseniz, jonas'ın cevabında küçük bir değişiklik yaptım, böylece Integer.MAX_VALUE değerinden daha büyük veya Integer'den daha küçük tam sayıları temsil eden dizeler şimdi dönecek yanlış. Örneğin: 3147483647 2147483647'den büyük olduğu için "3147483647" yanlış döndürür ve benzer şekilde -2147483649 -2147483648'den küçük olduğu için "-2147483649" da yanlış döndürür.

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

1
Lütfen cevabınızı düzenleyebilir ve daha önce bahsettiğiniz cevabı nasıl geliştirdiğini açıklayabilir misiniz?
Gilles Gouaillardet

Harika cevap için teşekkürler. Ancak "123" yani 123, boşlukla birlikte geçerli tamsayı olarak kabul edilir.
Saikrishna Radarapu

1
@SaikrishnaRadarapu Kullanıyorlar trim()ki bu açıkça bir kasıtlı tasarım seçimi.
Guildenstern


1

Muhtemelen kullanım durumunu da dikkate almanız gerekir:

Çoğu zaman sayıların geçerli olmasını bekliyorsanız, istisnayı yakalamak yalnızca geçersiz sayıları dönüştürmeye çalışırken performans yüküne neden olur. Bazı isInteger()yöntemlerin çağrılması ve ardından dönüştürmenin kullanılması Integer.parseInt()her zaman geçerli sayılar için bir performans yüküne neden olur - dizeler bir kez kontrolle ve bir kez dönüşümle iki kez ayrıştırılır.


1

Bu, dizenin bir tamsayıya dönüştürülecek aralıkta olup olmadığını kontrol eden Jonas kodunda yapılan bir değişikliktir .

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

1
iyi görünüyor, ancak son for-loop'un sıfıra sıfırlaması (veya negatif bir sayı ise 1) olması gerekir, çünkü her basamağın bir sayı olup olmadığını kontrol eden döngü i dizesinin uzunluğu, dolayısıyla son for-loop olmasıyla sonuçlanır asla koşmayacak. Sihirli sayılar yerine Integer.MAX_VALUE ve Integer.MIN_VALUE Java sabitlerini de kullanırdım.
Büyücü Tim

@TimtheEnchanter Önerileriniz için teşekkür ederim, onları tamamen gözden kaçırdım. Bunları dahil etmek için yaptığım düzenlemede, ekstra if ifadesinden kaçınmak için ilk olarak döngü için yeni bir değişken kullandım.
Wayne

1

Android API'sını kullanıyorsanız şunları kullanabilirsiniz:

TextUtils.isDigitsOnly(str);

1

Başka seçenek:

private boolean isNumber(String s) {
    boolean isNumber = true;
    for (char c : s.toCharArray()) {
        isNumber = isNumber && Character.isDigit(c);
    }
    return isNumber;
}

0
is_number = true;
try {
  Integer.parseInt(mystr)
} catch (NumberFormatException  e) {
  is_number = false;
}

5
Bu, posterin sorduğu şeyle aynı şeyi yapıyor.
Martin Carney

0

Yaptıklarınız işe yarıyor, ama muhtemelen her zaman bu şekilde kontrol etmemelisiniz. Fırlatma istisnaları "istisnai" durumlar için ayrılmalıdır (belki de sizin durumunuza uyan) ve performans açısından çok maliyetlidir.


Sadece atılırlarsa pahalıdırlar.
Kertenkele Bill

0
Number number;
try {
    number = NumberFormat.getInstance().parse("123");
} catch (ParseException e) {
    //not a number - do recovery.
    e.printStackTrace();
}
//use number

0

Bu yalnızca pozitif tamsayılar için işe yarar.

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

4
Stackoverflow'a hoş geldiniz. Eski bir ileti dizisini yeniden diriltmeden önce, önceki yanıtları ve yorumları okuduğunuzdan emin olun. Bu yöntem (ve olası dezavantajlar) aslında zaten tartışılmıştır.
Leigh

0

Bu benim için çalışıyor. Bir String'in bir ilkel mi yoksa bir sayı mı olduğunu belirlemek için.

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

0

Tüm int karakterlerini kontrol etmek için çift negatif kullanabilirsiniz.

eğer (! searchString.matches ("[^ 0-9] + $")) ...

[^ 0-9] + $, tamsayı olmayan karakterler olup olmadığını kontrol eder, bu nedenle test doğru ise başarısız olur. Sadece bu DEĞİLDİR ve başarıya ulaşırsınız.


Hayır. Bunu açıkça test etmediniz. Bu, yalnızca dizede bir rakam varsa dize yalnızca rakam olduğunda değil, true değerini döndürür. matchesYöntem tüm dize, bunun sadece bir bölümüne karşı eşleşir.
Dawood ibn Kareem

Çifte negatif kısmı alamazsınız.
Roger F. Gay

Ben, çift negatif alamıyorum. Bu işe yaramıyor. Rakam ve harflerden oluşan bir karışımınız varsa, bu ifbloğa gider . Olmamalı.
Dawood ibn Kareem

0

Bunu faydalı bulabilir:

public static boolean isInteger(String self) {
    try {
        Integer.valueOf(self.trim());
        return true;
    } catch (NumberFormatException nfe) {
        return false;
    }
}

0

Hep güvenle ayrıştırmak altınızda gördüğünüz gibi çünkü bir istisna haline çalışan sıfır risk, orada inanmak intiçinString aksi halde değil.

Yani:

  1. Sen kontrol eğer dize eşleşmeleri karakterlerin en az biri karakterin her yuva { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} .

    if(aString.substring(j, j+1).equals(String.valueOf(i)))
  2. Sen Özetle slotlardaki yukarıdaki karakterler karşılaşılan tüm kez.

    digits++;
  3. Son olarak, karakter olarak tamsayılarla karşılaştığınız zamanların verilen dizenin uzunluğuna eşit olup olmadığını kontrol edersiniz.

    if(digits == aString.length())

Ve pratikte:

    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!!");
    }

Ve sonuçlar:

Bu bir tamsayı !!

Tamsayı değil !!

Benzer şekilde, a'nın Stringa floatveya a olup olmadığını doğrulayabilirsiniz , doubleancak bu gibi durumlarda yalnızca bir tanesiyle karşılaşmanız gerekir . (nokta) Dizede ve tabii ki digits == (aString.length()-1)

Yine, orada burada bir ayrıştırma istisna haline çalışan sıfır risk, ama bunu (let diyelim bir sayı içeren bilinmektedir ki bir dize ayrıştırma planlıyorsanız int veri türü) veri türü uyuyorsa öncelikle kontrol edilmelidir. Aksi takdirde dökmeniz gerekir.

umarım yardımcı olmuşumdur

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.