Java'da bir Dizenin sayısal olup olmadığı nasıl kontrol edilir


886

Bir Dizenin ayrıştırılmadan önce bir sayı olup olmadığını nasıl kontrol edersiniz?


36
Düzenli ifadelerle önerilen tüm çözümler onaltılık sayılar için çalışmaz.
Oscar Castiblanco

ve match (...) işlevinde null dizesi iletilmesi NullPointer istisnasını atar.
Hitesh Sahu

Üçüncü taraf kitaplıkları olmayan kısa bir Java 8 çözümü için Max Malysh'ın cevabına bakın.
Andy Thomas

@HiteshSahu null dizeleri en son sürümde (Java 6.x ve 7.x dahil) incelikle işlenmiş gibi görünüyor
lifebalance

Kullanılması önerilen tüm çözümler Integer.parseInt()cep telefonu numaraları ile ayrıştırılamaz NumberFormatException.
Hata değil

Yanıtlar:


691

İle Apache Commons Lang 3.5 ve üzeri: NumberUtils.isCreatableya StringUtils.isNumeric.

İle Apache Commons Lang 3.4 ve önceki sürümleri: NumberUtils.isNumberya StringUtils.isNumeric.

Boş dizeler için StringUtils.isNumericSpacedöndüren trueve dizedeki iç boşlukları yoksayanları da kullanabilirsiniz . Bir başka yol da, NumberUtils.isParsableJava'ya göre sayının temelde ayrıştırılabileceğini kontrol etmektir. (Bağlantılı javadoclar her yöntem için ayrıntılı örnekler içerir.)


59
StringUtils.isNumeric()muhtemelen dizenin bir basamak dizisi olup olmadığını kontrol ettiğinden burada uygun olmaz. Çoğu ints için iyi olurdu, ancak ondalıklı sayılar, grup ayırıcılar, vb. İçin değil
Jeff Mercado

42
tekerleği yeniden icat edin çünkü tek bir yerde 3 satırlık bir fonksiyona ihtiyacınız olduğu için bir kütüphanenin tamamını içermezsiniz.
dalvarezmartinez1

12
Gerçekten değer bir ekleme mi bütün gerçi bu özellik için kütüphane? Açıkçası harika olan diğer şeylerle birlikte kullanılıyorsa, ancak insanların bunu bir kod satırında çözdüğü düşünülürse muhtemelen aşırı derecede ağırdır.
Su

7
Negatiflerle çalışmaz. Ve tüm sayıların yarısı negatif, bu yüzden .....
Paul Draper

6
@PaulDraper: Haklısın, StringUtilsönde gelen işaretleri NumberUtils.isCreatabledesteklemiyor, ancak kontrol etmelisin , negatifleri düzgün bir şekilde destekliyor.
palacsint

904

Bu genellikle kullanıcı tarafından tanımlanmış basit bir işlevle yapılır (yani, kendi rollerinizin "isNumeric" işlevi).

Gibi bir şey:

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

Bununla birlikte, bu işlevi çok fazla çağırıyorsanız ve bir sayı olmaması nedeniyle kontrollerin çoğunun başarısız olmasını bekliyorsanız, bu mekanizmanın performansı büyük olmayacaktır, çünkü her hata için atılan istisnalara güveniyorsunuz, ki bu oldukça pahalı bir işlemdir.

Alternatif bir yaklaşım, bir sayı olmanın geçerliliğini kontrol etmek için düzenli bir ifade kullanmak olabilir:

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

Bununla birlikte, yukarıdaki RegEx mekanizmasına dikkat edin, çünkü Arapça olmayan rakamlar (örn. 0 ila 9 dışındaki sayılar) başarısız olur. Bunun nedeni RegEx'in "\ d" kısmının yalnızca [0-9] ile eşleşmesi ve uluslararası olarak sayısal olarak farkında olmamasıdır. (Bunu işaret ettiği için OregonGhost'a teşekkürler!)

Ya da başka bir alternatif, dizeyi ayrıştırdıktan sonra ayrıştırıcı konumunun dizenin sonunda olup olmadığını görmek için Java'nın yerleşik java.text.NumberFormat nesnesini kullanmaktır. Öyleyse, dizenin tamamının sayısal olduğunu varsayabiliriz:

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 yalnızca latin rakamları ile eşleşiyor mu? .NET regexes gibi, burada açıklandığı gibi diğer (örneğin arapça) rakamlarla ilgili bir sorunla karşılaşacaksınız: blogs.msdn.com/oldnewthing/archive/2004/03/09/86555.aspx
OregonGhost

3
numberFormatter çözümü, NumberFormatException çözümünü yakalamaktan muhtemelen çok az daha iyidir. En iyi yol regex bir kullanmak olduğundan şüpheleniyorum.
Chii

11
Not .senin regex herhangi bir karakter değil, sadece ondalık ayırıcı karakteri ile eşleşir.
jqno

9
Deneme / yakalama masrafını gerçekleştirmek için +1. Bu aslında tekrarlanan kullanım için uzun vadede kullanmak için korkunç bir yaklaşımdır, ancak gerçekten Java ile sıkışıp kaldık.
demongolem

5
"Latin rakamları" diye bir şey olmadığını ve 0-9 rakamları aslında Arap rakamları olduğunu unutmayın. İnsanlar muhtemelen Latince konuşan kişiler tarafından kullanılan, I, II, III, IV, V, VI, vb. Şeklinde Roma rakamlarıyla tanınırlar. En.wikipedia.org/wiki/Arabic_numerals ; en.wikipedia.org/wiki/Roman_numerals
dantiston

152

android iseniz, o zaman kullanmalısınız:

android.text.TextUtils.isDigitsOnly(CharSequence str)

belgeleri burada bulabilirsiniz

basit olsun . çoğunlukla herkes "yeniden programlayabilir" (aynı şey).


4
@ kape123 :) emin "123.456" rakam içermiyor.
Ahmed Alejo

8
Not: boş giriş için NPE ile sonuçlanır. Ayrıca, negatif sayılar veya ondalık sayılarla çalışmaz.
gMale

2
Bunu sevdim!! Bence bu kesinlikle rakamlar için. Değil .,-
illusionJJ

Aradığım şey buydu. Sadece 0-9 rakamlarını kontrol etmek için basit bir şey. EditText'imin bildiriminde bir filtre ayarladım, ancak yolun değişmesi veya değiştirilmesi durumunda basit bir programatik kontrol de yapmak güzel.
jwehrle

127

Java 8 lambda ifadeleri.

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

4
Bir yöntem başvurusu da kullanabilirsiniz: someString.chars (). AllMatch (Karakter :: isDigit)
Wienczny

3
Güzel ama yine de burada neredeyse tüm "çözümler" olarak tekerleği yeniden keşfediyor. Ayrıca, 'null' başarısız olur (neredeyse diğerleri gibi).
qben

8
Bu cevap kısa, basit ve okunabilir. Neredeyse İngilizce gibi okuyabilirsiniz - "tüm maç basamaklarını gösterir". Herhangi bir üçüncü taraf kütüphanesi gerektirmez. İstisnai olmayan durumlarda istisna kullanmaz. Bu kabul edilen cevap olmalı.
Andy Thomas

14
"-1" için ne üretecek?
Balázs Németh

2
Doğru cevap değil. Sayısal bir dize sayısal olmayan karakterlere (ör. "." Veya "-") sahip olabilir ve yine de mükemmel şekilde sayısal olabilir. Örneğin, 0,5, -1 ve 1,000 bu cevapta başarısız olur ve yine de mükemmel sayısaldır.
Simeon G

125

@CraigTP'nin mükemmel cevabında belirttiği gibi, dizenin sayısal olup olmadığını test etmek için İstisnalar kullanma konusunda da benzer performans endişelerim var. Böylece dize bölmek ve kullanmak sonunda java.lang.Character.isDigit().

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

Javadoc'a göre , Character.isDigit(char)Latin olmayan rakamları doğru bir şekilde tanıyacak. Performans açısından, ben n dizede karakter sayısı basit bir N sayısı karşılaştırma bir regex eşleştirme yapmak daha hesaplama açısından verimli olacağını düşünüyorum.

GÜNCELLEME: Yorumda Jean-François Corbett'in işaret ettiği gibi, yukarıdaki kod sadece benim kullanım durumumun çoğunu kapsayan pozitif tam sayıları doğrulayacaktır. Aşağıda, ondalık sayıları sisteminizde kullanılan varsayılan yerel ayara göre doğrulayan ve ondalık ayırıcının dizede yalnızca bir kez oluştuğu varsayılarak güncellenen kod bulunmaktadır.

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
Ondalık ayırıcı da bunun başarısız olmasına neden olmaz mı?
Jean-François Corbett

1
@ Jean-FrançoisCorbett: İyi bir nokta, kodu ondalık ayırıcıları kabul eden daha yeni bir kodla güncelledim.
Ibrahim Arief

2
-Ve işareti bu işlevde başarısız oluyor mu?
java_mouse

3
Arayan toCharArray()Karakter dizileri değişmez çünkü String nesnesinde dizinin bir kopyasını oluşturur. Muhtemelen charAt(int index)doğrudan String nesnesindeki yöntemi kullanmak daha hızlıdır .
Mike Kucera

2
StringIndexOutOfBoundsExceptionUzunluğu 0 olan bir dize geçtiğinde üretilecekif(str.length() == 0) return false;
samgak

43

Google'ın Guava kütüphanesi bunu yapmak için güzel bir yardımcı yöntem sağlar: Ints.tryParse. Bunu gibi kullanırsınız, Integer.parseIntancak nulldize geçerli bir tamsayıya ayrıştırmazsa bir İstisna atmak yerine geri döner . İnt yerine Integer döndürdüğünü unutmayın, bu yüzden int'e dönüştürmek / otomatik kutuya dönüştürmek zorundasınız.

Misal:

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

Bununla birlikte, mevcut sürümden - Guava r11 - hala @Beta olarak işaretlenmiştir.

Ben kıyaslama yapmadım. Kaynak koduna baktığımızda, birçok akıl sağlığı kontrolünden bir miktar yük var, ancak sonunda Character.digit(string.charAt(idx))yukarıdaki @Ibrahim'den gelen cevabı benzer, ama biraz farklı kullanıyorlar. Uygulamalarında örtülerin altında bir istisna işleme yükü yoktur.


Argümanın boş olması durumunda bunun NPE atacağını unutmayın.
Vadzim

30

Değerlerinizi doğrulamak için İstisnalar kullanmayın. Apache NumberUtils gibi Util kütüphanelerini kullanın:

NumberUtils.isNumber(myStringValue);

Düzenle :

Dizeniz 0 ile başlıyorsa, NumberUtils'in değerinizi onaltılık olarak yorumlayacağını lütfen unutmayın.

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

7
Üç yıl önce kabul edilen cevap zaten kapsanmıştır Number.isNumber().
Andy Thomas

Ben öyle düşünmüyorum. Güncellenmiştir veya kabul edilen yanıtı değiştirmiştir. Kabul edilen cevabın NumberUtils'i kapsamadığını hatırlıyorum, bu yüzden cevabımı ekledim. Ama yorum için teşekkürler
Goot

2
@Goot - Kabul edilen cevabın geçmişi, cevabın Number.isNumber()ilk sürümünde, 24 Eylül 'de 17: 01'de mevcut olduğunu gösterir .
Andy Thomas

@Goot, StringUtils'in aksine ondalık değer denetimini de kapsadığından oldukça iyi.
Heena Hussain

24

Neden herkes istisna / normal ifade çözümleri için baskı yapıyor?

Çoğu insanın dene / yakala ile iyi olduğunu anlayabiliyorum, ancak sık sık yapmak istiyorsanız ... son derece vergilendirici olabilir.

Burada ne yaptı regex, parseNumber () yöntemleri ve en verimli olduğunu görmek için dizi arama yöntemi almak oldu. Bu sefer sadece tam sayılara baktım.

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

Aldığım hızdaki sonuçlar:

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

Feragatname: Bu yöntemlerin% 100 optimize edildiğini iddia etmiyorum, sadece verilerin gösterilmesi içindir

İstisnalar yalnızca sayı 4 karakter veya daha azsa ve her karakter dizisi her zaman bir sayı ise kazanılır ... bu durumda neden bir çekiniz olur?

Kısacası, try / catch ile geçersiz sayılara sık sık girmeniz son derece acı vericidir, bu da mantıklıdır. Her zaman takip ettiğim önemli bir kural ASLA program akışı için try / catch kullanmayın . Bunun bir örneği.

İlginçtir, eğer char <0 || > 9 yazmak son derece basitti, hatırlaması kolay (ve birden çok dilde çalışması gerekiyor) ve neredeyse tüm test senaryolarını kazanıyor.

Tek dezavantajı dizi arama yöntemi değil iken Integer.parseInt () olmayan ASCII sayıları işleyebilir tahmin olduğunu.


Neden bir karakter dizisini hatırlamak kolay dediğimi merak edenler için, olumsuz işaret olmadığını biliyorsanız, bu şekilde yoğunlaştırılmış bir şeyle kolayca kurtulabilirsiniz:

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;

Son olarak, kabul edilen örnekte görevlendirme operatörünü tüm oylarla merak ettim. Ekleme

double d = Double.parseDouble(...)

sadece değeri kullanmazsınız, çünkü işlem süresini harcar ve çalışma süresini birkaç nanosaniye arttırır (bu da testlerde 100-200 ms'lik bir artışa neden olur). Performansı azaltmak için fazladan bir çalışma olduğu için neden bunu herkesin yapacağını anlayamıyorum.

Bunun optimize edileceğini düşünürdünüz ... yine de bayt kodunu kontrol etmeli ve derleyicinin ne yaptığını görmeliyim. Bu neden benim için her zaman daha uzun ortaya çıktığını açıklamıyor olsa da, bir şekilde optimize edilirse ... Bu yüzden neler olduğunu merak ediyorum. Not: Daha uzun olarak, testi 10000000 yineleme için çalıştırmak ve o programı birden çok kez (10x +) çalıştırmak her zaman daha yavaş olduğunu gösterdi.

EDIT: Character.isDigit () için bir test güncellendi


4
Bu her seferinde yeni bir düzenli ifade derlemiyor mu? Çok verimli görünmüyor.
Samuel Edwin Ward

1
@SamuelEdwinWard Bu yazıyı yapmamın tüm nedeni bu ... regex örneği başkalarının verdiği cevapları kullandı ve ne kadar verimsiz olduğunu gösterdi. Önceden derleyerek ve sadece bunu kullanarak regex girişiminde bulunsanız bile, zaman farkları şunlardır: Diğer sağlanan insanlardan gönderdiğim normal ifade için 2587 ms, vaktinden önce derlendiğinde 950 ms, bunu yaparken 144 ms sayısal dizi (aynı dizenin 1 mil yinelemeleri için). Zamanından önce derlemek yardımcı olacaktır, ama ne yazık ki dizi yolundan hala daha aşağı ... bilmediğim bazı deli optimizasyon sürece.
Su

Regex'in işleri daha hızlı hale getirdiğine inanmak neredeyse yanlıştır. Eğer bu bir arama kapalı, evet, anladım ... ama etkili bir şekilde kod yazdım aslında şok için yeterince regex outdoes! Great post @Water
Yo Apps

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

CraigTP'nin düzenli ifadesi (yukarıda gösterilmiştir) bazı yanlış pozitifler üretir. Örneğin, "23y4" sayı olarak sayılacaktır çünkü '.' ondalık işareti olmayan herhangi bir karakterle eşleşir.

Ayrıca önde gelen '+' ile herhangi bir sayıyı reddeder

Bu iki küçük problemden kaçınan bir alternatif

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

Bu dönecektir truetek artı için "+"veya eksi "-"ve falseiçin"0."
user85421

Tek artı veya eksi iyi yakalamak. "0" dır. geçerli bir sayı mı?
user872985

"0."için geçerlidir Double.parseDouble()ve JLS (göre geçerli değişmezi olan §3.10.2 )!
user85421 18:11

Normal ifadeler oluşturmak da maliyetlidir. Normal ifade bir kez oluşturulmalı ve yeniden kullanılmalıdır
Daniel Nuriyev

1
değiştirmelisinmatches("-?\\d+([.]\\d+)?")
Bobs

14

Verilen dizeden gelen tüm sayıları ("") yani boşluk ile değiştirmeyi deneyebiliriz ve bundan sonra dizenin uzunluğu sıfırsa, verilen dizenin yalnızca sayılar içerdiğini söyleyebiliriz. [Bu yanıtı yararlı bulduysanız, lütfen oylamayı düşünün] Örnek:

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

Yani ""bir sayı ama "3.14"ve "-1"değil mi?
Eric Duminil

Açıkçası tüm sayı formları için geçerli değildir, ama burada farklı düşünmek için bir oylama var ... eğer orijinal düşünce sizinse, yani.
gbenroscience

12

Şunları kullanabilirsiniz NumberFormat#parse:

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

Bir düzenleme önerdi - .getInstance () eksik. +1, çünkü bu soruyu bulurken gittiğim cevaptı.
8bitjunkie

5
Genişletilirse pahalı
Daniel Nuriyev

1
Sonunda çöp karakterler varsa da geçecektir value.
Brian White

İstisna günlüğe
kaydetmezseniz

1
Bu, Double.parseDouble'ın çalışmadığı 0x0001 sayı biçimi için çalıştı. +1
Seabass77


8

İşte benim sorunun cevabı.

Herhangi bir dizeyi herhangi bir ayrıştırıcı türü ile ayrıştırmak için kullanabileceğiniz tüm yakalama yöntemi isParsable(Object parser, String str). Ayrıştırıcı bir Classveya bir olabilir object. Bu ayrıca, yazdığınız özel ayrıştırıcıları kullanmanıza izin verir ve her zaman senaryo için çalışmalıdır, örneğin:

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

İşte benim kod yöntem açıklamaları ile tamamlandı.

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

Yalnızca ASCII basamaklarını içeren yalnızca pozitif temel on tamsayıları eşleştirmek için şunu kullanın:

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

5

Deneme yakalamadan kaçınmak ve negatif sayıları ve bilimsel gösterimi işlemek için iyi performans gösteren bir yaklaşım.

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

İşte bir dize sayısal olup olmadığını kontrol etmek için benim sınıf. Ayrıca sayısal dizeleri de düzeltir:

Özellikleri:

  1. Gereksiz sıfırları kaldırır ["12.0000000" -> "12"]
  2. Gereksiz sıfırları kaldırır ["12.0580000" -> "12.058"]
  3. Sayısal olmayan karakterleri kaldırır ["12.00sdfsdf00" -> "12"]
  4. Negatif dize değerlerini işler ["-12,020000" -> "-12,02"]
  5. Birden çok noktayı kaldırır ["-12.0.20.000" -> "-12.02"]
  6. Ek kütüphaneler yok, sadece standart Java

Hadi bakalım...

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

Normal İfade Eşleme

Burada, daha fazla doğrulamayla yükseltilmiş "CraigTP" normal ifade eşleşmesinin başka bir örneği verilmiştir.

public static boolean isNumeric(String str)
{
    return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
  1. Yalnızca bir negatif işarete -izin verilir ve başlangıçta olması gerekir.
  2. Negatif işaretten sonra rakam olmalıdır.
  3. Yalnızca bir ondalık işaretine .izin verilir.
  4. Ondalık işaretinden sonra rakam olmalıdır.

Normal İfade Testi

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

İstisnalar pahalıdır, ancak bu durumda RegEx çok daha uzun sürer. Aşağıdaki kod, biri istisnalar, diğeri regex kullanan iki fonksiyonun basit bir testini göstermektedir. Makinemde RegEx sürümü istisnadan 10 kat daha yavaş.

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

}

}

Genellikle, bu tür bir kod yazılan girdi gibi şeyleri kontrol etmek için kullanılacak düşünüyorum. Bu durumda hız dikkate alınmaz ve sayı olup olmadığını kontrol etmek için bir istisna atmak kadar çirkin bir şey yapmak yanlıştır.
user872985

Belki de değil. Yazılan giriş genellikle değeri göndermeden önce hataların hemen gösterilebileceği UI bileşeni tarafından kontrol edilir. Performansın önemli olduğu büyük girdi metin dosyalarından dizeleri doğrulamak daha yaygın olabilir. Buradaki cevabımdaki amaç, kabul edilen cevaptaki "istisnalar yavaş" ifadesini ele almaktır. Karmaşık normal regex çok daha pahalıdır. Ve kodumda hiç "çirkin atış" yok - ihlalleri tespit etmenin daha hızlı bir yolu. Önce kontrol et-sonra hesapla yaklaşımıyla, girişten iki geçiş yaparsınız: biri doğrulamak için ve sonra diğeri dönüştürmek için.
ChrisCantrell

5

// lütfen aşağıdaki kodu kontrol edin

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

Soru, tamsayı olmayan değerler içerebilen "sayısal" diyor.
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

Bu kontrol için basit bir örnek:

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 nesnesini kullanabilirsiniz.

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

2

CraigTP'nin çözümünü bilimsel gösterimi ve nokta ve virgülleri ondalık ayırıcılar olarak kabul edecek şekilde değiştirdim

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

misal

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

Bu yüzden .NET'te Try * yaklaşımını seviyorum. Java benzeri geleneksel Parse yöntemine ek olarak, bir TryParse yönteminiz de vardır. Java sözdiziminde (out parametreleri?) İyi değilim, bu yüzden lütfen bir tür sahte kod olarak aşağıdakileri ele alın. Yine de kavramı açıklığa kavuşturmalıdır.

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

Kullanımı:

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

Evet, Java'da "out parametresi" yoktur ve Tamsayı sarıcı değiştirilemez olduğundan (bu nedenle çıktıyı depolamak için geçerli bir referans olarak kullanılamaz), mantıklı deyimsel seçenek ayrıştırma durumunda boş olabilecek bir Integer nesnesi döndürmek olacaktır. başarısız oldu. Daha çirkin bir seçenek, çıkış parametresi olarak int [1] 'i geçmek olabilir.
fortran

Evet, Java'nın neden çıkış parametresi olmadığına dair bir tartışma hatırlıyorum. ama bir Integer (gerekirse null olarak) döndürmek de iyi olurdu, sanırım, Java'nın boks / unboxing ile ilgili performansını bilmiyorum.
OregonGhost

4
Ben C # sonraki adam gibi seviyorum, ama özellikleri Java mevcut olmadığında bir Java soru için bir .NET C # kod snippet'i eklemenin hiçbir faydası yok
Shane

İstisna günlüğe
kaydetmezseniz

2

Ayrıştırın (yani ile Integer#parseInt) ve sadece istisnayı yakalayın. =)

Açıklığa kavuşturmak için: parseInt işlevi, herhangi bir durumda sayıyı ayrıştırabildiğini (açık bir şekilde) kontrol eder ve yine de ayrıştırmak istiyorsanız, gerçekten ayrıştırma yaparak herhangi bir performans atmayacaksınız.

Ayrıştırmak istemiyorsanız (ya da çok, çok nadiren ayrıştırmak istemiyorsanız) farklı bir şekilde yapmak isteyebilirsiniz.


1
Genişletilirse pahalı
Daniel Nuriyev

İstisna günlüğe
kaydetmezseniz

Double
Alex78191

2

Apache Commons Lang'dan NumberUtils.isCreatable () yöntemini kullanabilirsiniz .

NumberUtils.isNumber 4.0'da kullanımdan kaldırılacağından, bunun yerine NumberUtils.isCreatable () öğesini kullanın.


2

Java 8 Stream, lambda ifadesi, fonksiyonel arayüz

İşlenen tüm durumlar ( dize boş, dize boş vb. )

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

Herhangi bir API kullanmadan sayıları ve ondalıkları kontrol etmek için bazı koşulları gösterdim,

Düzeltme Uzunluğunu Kontrol Edin 1 haneli sayı

Character.isDigit(char)

Sabit Uzunluk numarasını kontrol edin (Uzunluğun 6 olduğunu varsayın)

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

Arasında Değişen Uzunluk sayısını kontrol edin (4 ila 6 uzunluk olduğunu varsayın)

//  {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");

Değişen Uzunluk ondalık sayısını kontrol edin (4 ila 7 uzunluk olduğunu varsayın)

//  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");

Umarım herkese yardımcı olur.


2

Diğer cevaplara dayanarak kendi yazdım ve istisna kontrolü ile desen veya ayrıştırma kullanmıyor.

Maksimum bir eksi işaretini ve maksimum bir ondalık noktasını kontrol eder.

İşte bazı örnekler ve sonuçları:

"1", "-1", "-1,5" ve "-1,556" doğru değerini döndürür

"1..5", "1A.5", "1.5D", "-" ve "--1" yanlış döndürür

Not: Gerekirse bunu bir Locale parametresini kabul edecek şekilde değiştirebilir ve geçerli bir yerine belirli bir Yerel Ayar kullanmak için DecimalFormatSymbols.getInstance () çağrılarına iletebilirsiniz.

 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

İşte işe yarayabilecek iki yöntem. (İstisnalar kullanmadan). Not: Java varsayılan olarak bir by-pass değeridir ve bir String'in değeri, String'in nesne verilerinin adresidir. Yani, yaparken

stringNumber = stringNumber.replaceAll(" ", "");

Giriş değerini boşluk içermeyecek şekilde değiştirdiniz. İsterseniz bu satırı kaldırabilirsiniz.

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

Burada şamandıralara izin vermek istiyorsanız başka bir yöntem Bu yöntem, formda sayıları 1.123,123,123,123,123.123 ben sadece yaptım geçmesine izin verdiği iddia ve çalıştığından emin olmak için daha fazla test gerektiğini düşünüyorum.

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

Oh, güzel soru. Sanırım bu sadece normal tip tamsayıları çalışıyor. Yöntem başlangıçta giriş telefon numaralarını filtrelemek ve sayıları saymak için oluşturuldu.
XForCE07
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.