Cara memeriksa apakah suatu String adalah angka di Jawa

887

Bagaimana Anda memeriksa apakah suatu String adalah angka sebelum menguraikannya?

Craig Angus
sumber
36
Semua solusi yang diusulkan dengan expresi reguler tidak akan bekerja untuk bilangan heksadesimal.
Oscar Castiblanco
dan meneruskan fungsi string nol dalam kecocokan (...) akan melempar pengecualian NullPointer.
Hitesh Sahu
Lihat jawaban Max Malysh untuk solusi Java 8 ringkas tanpa pustaka pihak ketiga.
Andy Thomas
@HiteshSahu null string tampaknya ditangani dengan anggun dalam versi terbaru (termasuk Java 6.x dan 7.x)
lifebalance
Semua solusi yang diusulkan Integer.parseInt()akan gagal menguraikan nomor ponsel NumberFormatException.
Bukan bug

Jawaban:

691

Dengan Apache Commons Lang 3.5 dan lebih tinggi: NumberUtils.isCreatableatau StringUtils.isNumeric.

Dengan Apache Commons Lang 3.4 dan di bawah ini: NumberUtils.isNumberatau StringUtils.isNumeric.

Anda juga dapat menggunakan StringUtils.isNumericSpaceyang mengembalikan truestring kosong dan mengabaikan spasi internal dalam string. Cara lain adalah dengan menggunakan NumberUtils.isParsableyang pada dasarnya memeriksa nomor yang dapat diuraikan menurut Java. (The javadocs yang ditautkan berisi contoh terperinci untuk setiap metode.)

palacsint
sumber
59
StringUtils.isNumeric()mungkin tidak akan sesuai di sini karena hanya memeriksa apakah string adalah urutan digit. Akan baik untuk sebagian besar int tetapi tidak demikian untuk angka dengan desimal, pemisah grup, dll.
Jeff Mercado
42
temukan kembali roda karena Anda tidak menyertakan seluruh perpustakaan karena Anda memerlukan fungsi 3 baris di satu tempat.
dalvarezmartinez1
12
Apakah benar-benar layak menambahkan seluruh perpustakaan untuk fitur ini? Jelas jika itu digunakan dengan hal-hal lain yang hebat, tetapi mungkin berlebihan mengingat orang telah menyelesaikan ini dalam satu baris kode.
Air
7
Tidak bekerja dengan yang negatif. Dan setengah dari semua angka negatif, jadi .....
Paul Draper
6
@ PaulDraper: Anda benar, StringUtilstidak mendukung tanda-tanda terkemuka tetapi Anda harus memeriksa NumberUtils.isCreatable, ini mendukung negatif dengan benar.
palacsint
904

Ini umumnya dilakukan dengan fungsi sederhana yang ditentukan pengguna (yaitu fungsi Roll-your-own "isNumeric").

Sesuatu seperti:

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

Namun, jika Anda sering memanggil fungsi ini, dan Anda berharap banyak cek gagal karena tidak menjadi angka maka kinerja mekanisme ini tidak akan bagus, karena Anda mengandalkan pengecualian yang dilemparkan untuk setiap kegagalan, yang merupakan operasi yang cukup mahal.

Pendekatan alternatif mungkin menggunakan ekspresi reguler untuk memeriksa validitas menjadi nomor:

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

Berhati-hatilah dengan mekanisme RegEx di atas, karena akan gagal jika Anda menggunakan angka non-Arab (yaitu angka selain 0 hingga 9). Ini karena bagian "\ d" dari RegEx hanya akan cocok dengan [0-9] dan secara efektif tidak sadar secara numerik secara internasional. (Terima kasih kepada OregonGhost untuk menunjukkan ini!)

Atau bahkan alternatif lain adalah dengan menggunakan Java.text.NumberFormat objek bawaan Java untuk melihat apakah, setelah mengurai string posisi parser berada di akhir string. Jika ya, kita dapat menganggap seluruh string adalah numerik:

public static boolean isNumeric(String str) {
  NumberFormat formatter = NumberFormat.getInstance();
  ParsePosition pos = new ParsePosition(0);
  formatter.parse(str, pos);
  return str.length() == pos.getIndex();
}
CraigTP
sumber
7
Apakah di Java Regex hanya cocok dengan angka latin? Jika seperti .NET regexes, Anda akan mengalami masalah dengan digit lainnya (mis. Bahasa Arab), seperti dijelaskan di sini: blogs.msdn.com/oldnewthing/archive/2004/03/09/86555.aspx
OregonGhost
3
solusi numberFormatter mungkin hanya sedikit lebih baik daripada menangkap yang NumberFormatException. Saya menduga cara terbaik adalah menggunakan regex satu.
Chii
11
Perhatikan bahwa .dalam regex Anda akan cocok dengan karakter apa pun, bukan hanya karakter pemisah desimal.
jqno
9
+1 untuk menyadari biaya percobaan / tangkapan. Ini sebenarnya pendekatan yang mengerikan untuk digunakan dalam jangka panjang untuk penggunaan berulang, tapi kami benar-benar terjebak dengan itu di Jawa.
demongolem
5
Perhatikan bahwa tidak ada hal-hal seperti "angka latin", dan angka 0-9 sebenarnya adalah angka Arab. Orang-orang mungkin akrab dengan angka Romawi, yang digunakan oleh orang-orang yang berbicara bahasa Latin, dalam bentuk I, II, III, IV, V, VI, dll. En.wikipedia.org/wiki/Arabic_numerals ; en.wikipedia.org/wiki/Roman_numerals
dantiston
152

Jika Anda menggunakan Android, maka Anda harus menggunakan:

android.text.TextUtils.isDigitsOnly(CharSequence str)

dokumentasi dapat ditemukan di sini

tetap sederhana . kebanyakan orang dapat "memprogram ulang" (hal yang sama).

Ahmed Alejo
sumber
4
@ kape123 :) yakin "123.456" tidak mengandung digit.
Ahmed Alejo
8
Catatan: ini menghasilkan NPE untuk input nol. Juga, tidak bekerja dengan angka atau desimal negatif.
gMale
2
Saya suka itu!! Saya pikir ini mutlak untuk angka. Bukan untuk .,-
illusionJJ
Inilah yang saya cari. Sesuatu yang sederhana untuk memeriksa hanya angka 0-9. Saya menetapkan filter dalam deklarasi EditText saya, tetapi untuk berjaga-jaga jika bisa diubah atau diganti, ada baiknya juga melakukan pemeriksaan terprogram yang sederhana.
jwehrle
127

Ekspresi lambda Java 8

String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );
Max Malysh
sumber
4
Anda dapat menggunakan referensi metode, juga: someString.chars (). AllMatch (Character :: isDigit)
Wienczny
3
Bagus tapi tetap saja menciptakan kembali roda karena hampir semua "solusi" di sini. Juga, gagal pada 'null' (karena hampir semua yang lain).
qben
8
Jawaban ini ringkas, sederhana dan mudah dibaca. Anda hampir dapat membacanya seperti bahasa Inggris - "karakter semua angka cocok". Itu tidak memerlukan perpustakaan pihak ketiga. Itu tidak menggunakan pengecualian dalam kasus yang tidak biasa. Ini harus menjadi jawaban yang diterima.
Andy Thomas
14
Apa yang akan dihasilkan untuk "-1"?
Balázs Németh
2
Bukan jawaban yang benar. String numerik dapat memiliki karakter non-numerik (mis. "." Atau "-") dan masih numerik dengan sempurna. Misalnya 0,5, -1, dan 1.000 semuanya akan gagal dengan jawaban ini, namun semuanya numerik.
Simeon G
126

Seperti @CraigTP telah menyebutkan dalam jawaban yang sangat baik, saya juga memiliki masalah kinerja yang serupa dalam menggunakan Pengecualian untuk menguji apakah string tersebut numerik atau tidak. Jadi saya akhirnya memisahkan string dan menggunakan java.lang.Character.isDigit().

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

Menurut Javadoc , Character.isDigit(char)akan dengan benar mengenali angka non-Latin. Dari segi kinerja, saya pikir perbandingan N sederhana di mana N adalah jumlah karakter dalam string akan lebih efisien secara komputasi daripada melakukan pencocokan regex.

UPDATE: Seperti yang ditunjukkan oleh Jean-François Corbett dalam komentar, kode di atas hanya akan memvalidasi bilangan bulat positif, yang mencakup sebagian besar kasus penggunaan saya. Di bawah ini adalah kode yang diperbarui yang memvalidasi angka desimal dengan benar sesuai dengan lokal default yang digunakan dalam sistem Anda, dengan asumsi bahwa pemisah desimal hanya terjadi satu kali dalam string.

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;
}
Ibrahim Arief
sumber
4
Bukankah pemisah desimal juga menyebabkan ini gagal?
Jean-François Corbett
1
@ Jean-FrançoisCorbett: Bagus, saya telah memperbarui kode dengan yang lebih baru yang menerima pemisah desimal.
Ibrahim Arief
2
Apakah tanda -ve gagal fungsi ini?
java_mouse
3
Memanggil toCharArray()akan membuat salinan array di objek String karena String tidak berubah. Mungkin lebih cepat menggunakan charAt(int index)metode pada objek String secara langsung.
Mike Kucera
2
Akan menghasilkan StringIndexOutOfBoundsExceptionketika melewati string dengan panjang 0. Dapat diperbaiki denganif(str.length() == 0) return false;
samgak
43

Perpustakaan Guava Google menyediakan metode pembantu yang baik untuk melakukan hal ini: Ints.tryParse. Anda menggunakannya seperti Integer.parseInttetapi mengembalikan nulldaripada melemparkan Pengecualian jika string tidak mem-parsing ke integer yang valid. Perhatikan bahwa ia mengembalikan Integer, bukan int, jadi Anda harus mengonversi / autobox kembali ke int.

Contoh:

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

Namun, pada rilis saat ini - Jambu r11 - masih ditandai @Beta.

Saya belum membandingkannya. Melihat kode sumber ada beberapa overhead dari banyak pemeriksaan kewarasan tetapi pada akhirnya mereka menggunakan Character.digit(string.charAt(idx)), mirip, tetapi sedikit berbeda dari, jawaban dari @Ibrahim di atas. Tidak ada pengecualian menangani overhead di bawah penutup dalam implementasinya.

quux00
sumber
Berhati-hatilah karena ini akan melempar NPE jika argumennya nol.
Vadzim
30

Jangan gunakan Pengecualian untuk memvalidasi nilai Anda. Gunakan Util libs sebagai gantinya seperti apache NumberUtils:

NumberUtils.isNumber(myStringValue);

Edit :

Harap perhatikan bahwa, jika string Anda dimulai dengan 0, NumberUtils akan menafsirkan nilai Anda sebagai heksadesimal.

NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false
Goot
sumber
7
Jawaban yang diterima, tiga tahun sebelumnya, sudah dibahas Number.isNumber().
Andy Thomas
Saya kira tidak. Itu diperbarui atau op mengubah jawaban yang diterima. Saya ingat jawaban yang diterima tidak mencakup NumberUtils, itulah sebabnya saya menambahkan jawaban saya. Tapi terima kasih atas komentarnya
Goot
2
@ Goot - Sejarah jawaban yang diterima menunjukkan bahwa Number.isNumber()hadir dari versi pertama jawaban, tertanggal 24 Sep 12 pada 17:01.
Andy Thomas
@Boot, ini cukup bagus karena juga mencakup pemeriksaan nilai desimal, tidak seperti StringUtils.
Heena Hussain
24

Mengapa semua orang mendorong solusi pengecualian / regex?

Walaupun saya bisa mengerti kebanyakan orang baik-baik saja dengan menggunakan try / catch, jika Anda ingin sering melakukannya ... itu bisa sangat melelahkan.

Apa yang saya lakukan di sini adalah mengambil regex, metode parseNumber (), dan metode pencarian array untuk melihat mana yang paling efisien. Kali ini, saya hanya melihat angka integer.

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

Hasil dalam kecepatan yang saya dapatkan adalah:

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

Penafian: Saya tidak mengklaim metode ini 100% dioptimalkan, mereka hanya untuk demonstrasi data

Pengecualian dimenangkan jika dan hanya jika jumlahnya 4 karakter atau kurang, dan setiap string selalu angka ... dalam hal ini, mengapa bahkan memiliki cek?

Singkatnya, sangat menyakitkan jika Anda sering menemukan nomor yang tidak valid dengan try / catch, yang masuk akal. Aturan penting yang selalu saya ikuti adalah JANGAN PERNAH menggunakan try / catch untuk aliran program . Ini adalah contoh mengapa.

Menariknya, simpel jika char <0 || > 9 sangat sederhana untuk ditulis, mudah diingat (dan harus bekerja dalam berbagai bahasa) dan memenangkan hampir semua skenario pengujian.

Satu-satunya downside adalah bahwa saya menebak Integer.parseInt () mungkin menangani angka non ASCII, sedangkan metode pencarian array tidak.


Bagi mereka yang bertanya-tanya mengapa saya mengatakan mudah untuk mengingat satu array karakter, jika Anda tahu tidak ada tanda-tanda negatif, Anda dapat dengan mudah lolos dengan sesuatu yang kental seperti ini:

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;

Terakhir sebagai catatan terakhir, saya ingin tahu tentang operator asistensi dalam contoh yang diterima dengan semua suara di atas. Menambahkan penugasan

double d = Double.parseDouble(...)

tidak hanya tidak berguna karena Anda bahkan tidak menggunakan nilai, tetapi juga membuang-buang waktu pemrosesan dan meningkatkan runtime oleh beberapa nanodetik (yang menyebabkan peningkatan 100-200 ms dalam tes). Saya tidak dapat melihat mengapa ada orang yang melakukan itu karena ini adalah pekerjaan tambahan untuk mengurangi kinerja.

Anda akan berpikir bahwa itu akan dioptimalkan ... meskipun mungkin saya harus memeriksa bytecode dan melihat apa yang dilakukan oleh kompiler. Itu tidak menjelaskan mengapa itu selalu tampak lebih panjang bagi saya meskipun jika entah bagaimana dioptimalkan keluar ... karena itu saya bertanya-tanya apa yang terjadi. Sebagai catatan: Secara lebih panjang, maksud saya menjalankan tes untuk 10.000.000 iterasi, dan menjalankan program itu beberapa kali (10x +) selalu menunjukkan itu lebih lambat.

EDIT: Diperbarui tes untuk Character.isDigit ()

air
sumber
4
Bukankah ini mengkompilasi ekspresi reguler baru setiap waktu? Itu tidak terlihat sangat efisien.
Samuel Edwin Ward
1
@SamuelEdwinWard Itulah seluruh alasan saya membuat posting ini ... contoh regex menggunakan jawaban yang diberikan orang lain dan menunjukkan betapa tidak efisiennya itu. Bahkan jika Anda mencoba regex dengan pra-kompilasi sebelumnya dan hanya menggunakan itu, perbedaan waktu adalah: 2587 ms untuk regex yang saya posting dari orang lain yang disediakan, 950 ms ketika dikompilasi sebelumnya, 144 ms ketika melakukannya sebagai array numerik (untuk 1 mil iterasi string yang sama). Mengompilasi sebelumnya tentu saja akan membantu, tetapi sayangnya itu masih cukup rendah dengan cara array ... kecuali ada beberapa optimasi gila yang saya tidak tahu.
Air
Percaya bahwa Regex membuat segalanya lebih cepat hampir merupakan kekeliruan. Jika ini adalah satu pencarian, ya, saya mengerti ... tapi saya perhatikan kode yang ditulis secara efisien sebenarnya mengalahkan regex yang cukup mengejutkan Anda! Pos luar biasa @Water
Aplikasi Yo
19
public static boolean isNumeric(String str)
{
    return str.matches("-?\\d+(.\\d+)?");
}

Ekspresi reguler CraigTP (ditampilkan di atas) menghasilkan beberapa positif palsu. Misalnya "23y4" akan dihitung sebagai angka karena '.' cocok dengan karakter apa pun bukan titik desimal.

Juga akan menolak nomor apa pun dengan '+' yang memimpin

Alternatif yang menghindari dua masalah kecil ini adalah

public static boolean isNumeric(String str)
{
    return str.matches("[+-]?\\d*(\\.\\d+)?");
}
pengguna872985
sumber
ini akan kembali trueuntuk plus "+"atau minus tunggal "-", dan falseuntuk"0."
user85421
Bagus menangkap plus atau minus tunggal. Apakah "0." angka yang valid?
user872985
"0."valid untuk Double.parseDouble()dan merupakan literal yang sah menurut JLS ( §3.10.2 )!
user85421
Membuat ekspresi reguler juga mahal. Ekspresi reguler harus dibuat sekali dan digunakan kembali
Daniel Nuriyev
1
Anda harus mengubahnya kematches("-?\\d+([.]\\d+)?")
Bobs
14

Kita dapat mencoba mengganti semua angka dari string yang diberikan dengan ("") yaitu ruang kosong dan jika setelah itu panjang string adalah nol maka kita dapat mengatakan bahwa string yang diberikan hanya berisi angka. [Jika Anda menemukan jawaban ini bermanfaat maka silakan pertimbangkan untuk memilihnya] Contoh:

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;
    }
Ketan Ramteke
sumber
Jadi ""adalah angka tetapi "3.14"dan "-1"tidak?
Eric Duminil
Jelas tidak berlaku untuk semua bentuk angka, tetapi inilah suara positif untuk berpikir secara berbeda ... jika pikiran aslinya adalah milik Anda, itu adalah.
gbenroscience
12

Anda bisa menggunakan NumberFormat#parse:

try
{
     NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
    // Not a number.
}
Artem Barger
sumber
Menawarkan suntingan - .getInstance () tidak ada. Memberi +1 karena ini adalah jawaban yang saya gunakan ketika menemukan pertanyaan ini.
8bitjunkie
5
Mahal jika digunakan secara extensibly
Daniel Nuriyev
1
Ini juga akan lulus jika ada karakter sampah di akhir value.
Brian White
Itu akan membuat masalah sonar jika Anda tidak mencatat pengecualian
jmhostalet
1
Ini berfungsi untuk format angka 0x0001 di mana Double.parseDouble tidak berfungsi. +1
Seabass77
11

Jika Anda menggunakan java untuk mengembangkan aplikasi Android, Anda bisa menggunakan fungsi TextUtils.isDigitsOnly .

Eric Guo
sumber
8

Inilah jawaban saya untuk masalah tersebut.

Sebuah menangkap semua metode kenyamanan yang dapat Anda gunakan untuk mengurai setiap String dengan semua jenis parser: isParsable(Object parser, String str). Parser dapat berupa a Classatau a object. Ini juga akan memungkinkan Anda untuk menggunakan parser khusus yang Anda tulis dan harus berfungsi untuk skenario sebelumnya, misalnya:

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

Ini kode saya lengkap dengan deskripsi metode.

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;
    }
}
Jamie Bell
sumber
5

Untuk mencocokkan hanya bilangan bulat basis-sepuluh positif, yang hanya berisi digit ASCII, gunakan:

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

Pendekatan yang berperforma baik menghindari try-catch dan menangani angka negatif dan notasi ilmiah.

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

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

Ini kelas saya untuk memeriksa apakah sebuah string adalah angka. Itu juga memperbaiki string numerik:

Fitur:

  1. Menghapus nol yang tidak perlu ["12.0000000" -> "12"]
  2. Menghapus nol yang tidak perlu ["12.0580000" -> "12.058"]
  3. Menghapus karakter non numerik ["12.00sdfsdf00" -> "12"]
  4. Menangani nilai string negatif ["-12,020000" -> "-12,02"]
  5. Menghapus banyak titik ["-12.0.20.000" -> "-12.02"]
  6. Tidak ada perpustakaan tambahan, hanya Java standar

Ini dia ...

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

}
Bakso
sumber
5

Pencocokan Regex

Berikut adalah contoh lain pemutakhiran regex "CraigTP" yang ditingkatkan dengan lebih banyak validasi.

public static boolean isNumeric(String str)
{
    return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
  1. Hanya satu tanda negatif yang -diizinkan dan harus di awal.
  2. Setelah tanda negatif harus ada angka.
  3. Hanya satu tanda desimal yang .diizinkan.
  4. Setelah tanda desimal harus ada angka.

Tes Regex

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
Madan Sapkota
sumber
5

Pengecualian itu mahal, tetapi dalam hal ini RegEx membutuhkan waktu lebih lama. Kode di bawah ini menunjukkan tes sederhana dari dua fungsi - satu menggunakan pengecualian dan satu menggunakan regex. Di komputer saya, versi RegEx 10 kali lebih lambat dari pengecualian.

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

}

}
ChrisCantrell
sumber
Secara umum, saya pikir kode semacam ini akan digunakan untuk memeriksa hal-hal seperti input yang diketik. Dalam hal ini kecepatan bukanlah pertimbangan dan melakukan sesuatu yang jelek seperti melempar pengecualian untuk memeriksa nomor atau bukan-nomor adalah salah.
user872985
Mungkin tidak. Input yang diketik umumnya diperiksa oleh komponen UI di mana kesalahan dapat segera ditampilkan sebelum mengirimkan nilai. Mungkin lebih umum untuk memvalidasi string dari file teks input besar - di mana kinerja penting. Tujuan jawaban saya di sini adalah untuk menanggapi pernyataan "pengecualian lambat" dalam jawaban yang diterima. Regex yang kompleks jauh lebih mahal. Dan tidak ada "lemparan jelek" dalam kode saya sama sekali - hanya cara yang lebih cepat untuk mendeteksi pelanggaran. Dengan pendekatan check-first-then-menghitung Anda membuat dua lintasan melalui input: satu untuk memverifikasi dan satu lagi untuk dikonversi.
ChrisCantrell
5

// silakan periksa kode di bawah ini

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;
}
Tejas Parmar
sumber
Pertanyaannya mengatakan "numerik" yang dapat menyertakan nilai-nilai non-integer.
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;
    }
}
Elye M.
sumber
3

Ini contoh sederhana untuk pemeriksaan ini:

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;
}
ARIJIT
sumber
3

Anda dapat menggunakan objek java.util.Scanner.

public static boolean isNumeric(String inputData) {
      Scanner sc = new Scanner(inputData);
      return sc.hasNextInt();
    }
Yu Wai Hlaing
sumber
2

Saya memodifikasi solusi CraigTP untuk menerima notasi ilmiah dan juga titik dan koma sebagai pemisah desimal

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

contoh

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
AndyTheEntity
sumber
2

Itu sebabnya saya menyukai pendekatan Try * di .NET. Selain metode Parse tradisional yang seperti Java, Anda juga memiliki metode TryParse. Saya tidak pandai sintaksis Java (parameter out?), Jadi tolong perlakukan yang berikut ini sebagai semacam pseudo-code. Seharusnya konsepnya jelas.

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

Pemakaian:

int num;
if (parseInteger("23", out num)) {
    // Do something with num.
}
OregonGhost
sumber
ya, tidak ada "parameter keluar" di Jawa dan karena pembungkus Integer tidak dapat diubah (dengan demikian tidak dapat digunakan sebagai referensi yang valid untuk menyimpan output), opsi idiomatis yang masuk akal akan mengembalikan objek Integer yang bisa menjadi nol jika mengurai gagal. Opsi yang lebih buruk adalah untuk melewatkan int [1] sebagai parameter output.
fortran
Ya, saya ingat diskusi tentang mengapa Java tidak memiliki parameter output. tetapi mengembalikan Integer (sebagai null, jika perlu) akan baik-baik saja, saya kira, meskipun saya tidak tahu tentang kinerja Java sehubungan dengan tinju / unboxing.
OregonGhost
4
Saya suka C # sebanyak orang berikutnya, tetapi tidak ada gunanya menambahkan potongan .NET C # kode untuk pertanyaan Java ketika fitur tidak ada di Jawa
Shane
Itu akan membuat masalah sonar jika Anda tidak mencatat pengecualian
jmhostalet
2

Parse itu (yaitu dengan Integer#parseInt) dan cukup menangkap pengecualian. =)

Untuk memperjelas: Fungsi parseInt memeriksa apakah ia dapat menguraikan nomor dalam kasus apa pun (jelas) dan jika Anda tetap ingin menguraikannya, Anda tidak akan mendapatkan kinerja yang terpukul dengan benar-benar melakukan parsing.

Jika Anda tidak ingin menguraikannya (atau menguraikannya sangat, sangat jarang), Anda tentu ingin melakukannya secara berbeda.

gha.st
sumber
1
Mahal jika digunakan secara extensibly
Daniel Nuriyev
Itu akan membuat masalah sonar jika Anda tidak mencatat pengecualian
jmhostalet
Double.parseDouble
Alex78191
2

Anda dapat menggunakan NumberUtils.isCreatable () dari Apache Commons Lang .

Karena NumberUtils.isNumber akan ditinggalkan pada 4.0, jadi gunakan NumberUtils.isCreatable () sebagai gantinya.

Cenxui
sumber
2

Java 8 Stream, ekspresi lambda, antarmuka fungsional

Semua kasus ditangani ( string null, string kosong dll )

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();
Noor Nawaz
sumber
2

Saya telah menggambarkan beberapa kondisi untuk memeriksa angka dan desimal tanpa menggunakan API apa pun,

Periksa Perbaiki Panjang 1 digit angka

Character.isDigit(char)

Periksa nomor Fix Length (Asumsikan panjang 6)

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

Periksa nomor Panjang yang Bervariasi antara (Asumsikan panjang 4 hingga 6)

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

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

Periksa Memvariasikan angka desimal Panjang antara (Asumsikan 4 hingga 7 panjang)

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

Semoga ini bisa membantu orang lain.

ArifMustafa
sumber
2

Didasarkan atas jawaban lain saya menulis sendiri dan tidak menggunakan pola atau parsing dengan pengecekan pengecualian.

Ia memeriksa maksimum satu tanda minus dan memeriksa maksimum satu titik desimal.

Berikut ini beberapa contoh dan hasilnya:

"1", "-1", "-1.5" dan "-1.556" mengembalikan true

"1..5", "1A.5", "1.5D", "-" dan "--1" menghasilkan false

Catatan: Jika perlu, Anda dapat memodifikasi ini untuk menerima parameter Lokal dan meneruskannya ke panggilan DecimalFormatSymbols.getInstance () untuk menggunakan Lokal tertentu alih-alih yang sekarang.

 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;
}
Josh Gager
sumber
1

Berikut adalah dua metode yang mungkin berhasil. (Tanpa menggunakan Pengecualian). Catatan: Java adalah nilai pass-by-nilai secara default dan nilai String adalah alamat data objek String. Jadi, ketika Anda melakukannya

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

Anda telah mengubah nilai input menjadi tidak ada spasi. Anda dapat menghapus garis itu jika mau.

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

Berikut adalah metode lain jika Anda ingin mengizinkan pelampung. Metode ini diduga memungkinkan angka-angka dalam bentuk lulus 1.123,123,123,123,123,123.123 saya baru saja membuatnya, dan saya pikir perlu pengujian lebih lanjut untuk memastikannya berfungsi.

private boolean isValidStringTrueNumber(String stringNumber)
{
    if(stringNumber.isEmpty())
    {
        return false;
    }

    stringNumber = stringNumber.replaceAll(" ", "");
    int countOfDecimalPoint = 0;
    boolean decimalPointPassed = false;
    boolean commaFound = false;
    int countOfDigitsBeforeDecimalPoint = 0;
    int countOfDigitsAfterDecimalPoint =0 ;
    int commaCounter=0;
    int countOfDigitsBeforeFirstComma = 0;

    char [] charNumber = stringNumber.toCharArray();
    for(int i =0 ; i<charNumber.length ;i++)
    {
        if((commaCounter>3)||(commaCounter<0))
        {
            return false;
        }
        if(!Character.isDigit(charNumber[i]))//Char is not a digit.
        {
            if(charNumber[i]==',')
            {
                if(decimalPointPassed)
                {
                    return false;
                }
                commaFound = true;
                //check that next three chars are only digits.
                commaCounter +=3;
            }
            else if(charNumber[i]=='.')
            {
                decimalPointPassed = true;
                countOfDecimalPoint++;
            }
            else
            {
                return false;
            }
        }
        else //Char is a digit.
        {
            if ((commaCounter>=0)&&(commaFound))
            {
                if(!decimalPointPassed)
                {
                    commaCounter--;
                }
            }

            if(!commaFound)
            {
                countOfDigitsBeforeFirstComma++;
            }

            if(!decimalPointPassed)
            {
                countOfDigitsBeforeDecimalPoint++;
            }
            else
            {
                countOfDigitsAfterDecimalPoint++;
            }
        }
    }
    if((commaFound)&&(countOfDigitsBeforeFirstComma>3))
    {
        return false;
    }
    if(countOfDecimalPoint>1)
    {
        return false;
    }

    if((decimalPointPassed)&&((countOfDigitsBeforeDecimalPoint==0)||(countOfDigitsAfterDecimalPoint==0)))
    {
        return false;
    }
    return true;
}
XForCE07
sumber
Oh, pertanyaan bagus. Saya kira ini hanya bekerja bilangan bulat tipe normal. Metode awalnya dibuat untuk menyaring input nomor telepon, dan menghitung angka.
XForCE07