Validasikan bahwa string adalah bilangan bulat positif

200

Saya ingin tes gagal-aman yang paling sederhana untuk memeriksa apakah string dalam JavaScript adalah bilangan bulat positif.

isNaN(str)mengembalikan true untuk semua jenis nilai non-integer dan parseInt(str)mengembalikan integer untuk string float, seperti "2.5". Dan saya tidak mau harus menggunakan beberapa plugin jQuery juga.

Mick Byrne
sumber
7
Apakah Anda mengizinkan "+2"? Bagaimana dengan "0.1e1"? Bagaimana dengan "1,0000"?
Phrogz
The isNaN()Fungsi berperilaku jalan tersebut karena konsepnya Not a Numbermemiliki arti yang sangat spesifik dalam IEEE 794 floating spesifikasi titik. Itu tidak bermaksud memberikan jawaban untuk pertanyaan sehari-hari yang sederhana, "apakah nilai ini bukan angka?"
Runcing
3
Pertanyaannya tidak jelas sampai ekstrim. Anda tidak dapat memvalidasi bahwa "string adalah integer", karena tidak ada hal seperti itu - tidak ada objek yang dapat berupa string dan angka pada saat yang sama. Anda mungkin bermaksud "bagaimana menguji apakah string adalah representasi valid integer", tetapi untuk menjawab ini kita perlu tahu bahasa atau "budaya" mana yang Anda bicarakan. Sebagai contoh, ٢‎٣٤atau MCMXIXkeduanya adalah representasi integer yang valid, tetapi saya tidak berpikir Anda sedang mencari kode yang dapat menguraikan ini. Bisakah Anda menentukan format angka yang akan Anda dukung, karena orang-orang tampaknya bingung tentang hal itu.
georg
5
Saya pikir 'samar-samar ke ekstrem' itu sendiri agak ekstrem; tapi bagaimanapun ... Konteksnya adalah validasi bidang input kuantitas pada keranjang belanja yang digunakan di negara berbahasa Inggris, jadi hanya angka Barat. Dengan "positif" yang saya maksud lebih besar dari nol. Apakah saya menerima yang berikut ini: "+2" ya, "0,1e1" tidak, "1.000" yakin mengapa tidak. Namun, jika Anda dapat memberikan jawaban yang dapat disesuaikan untuk memasukkan / mengecualikan berbagai skenario khusus ini saya berjanji akan memberi Anda tambahan (dan saya yakin orang lain juga akan).
Mick Byrne

Jawaban:

296

Dua jawaban untuk Anda:

  • Berdasarkan parsing

  • Ekspresi reguler

Perhatikan bahwa dalam kedua kasus, saya telah menafsirkan "bilangan bulat positif" untuk disertakan 0, meskipun 0tidak positif. Saya menyertakan catatan jika Anda ingin melarang 0.

Berdasarkan Parsing

Jika Anda menginginkannya menjadi string integer desimal yang dinormalisasi pada rentang nilai yang wajar, Anda dapat melakukan ini:

function isNormalInteger(str) {
    var n = Math.floor(Number(str));
    return n !== Infinity && String(n) === str && n >= 0;
}

atau jika Anda ingin membolehkan spasi putih dan memimpin nol:

function isNormalInteger(str) {
    str = str.trim();
    if (!str) {
        return false;
    }
    str = str.replace(/^0+/, "") || "0";
    var n = Math.floor(Number(str));
    return n !== Infinity && String(n) === str && n >= 0;
}

Testbed langsung (tanpa menangani angka nol atau spasi kosong):

Testbed langsung ( dengan penanganan untuk memimpin nol dan spasi putih):

Jika Anda ingin melarang 0, ubah saja >= 0ke > 0. (Atau, dalam versi yang memungkinkan angka nol di depan, hapus angka || "0"di replacetelepon.)

Cara kerjanya:

  1. Dalam versi yang memungkinkan spasi dan nol terkemuka:

    • str = str.trim(); menghapus whitepace terkemuka dan tertinggal.
    • if (!str) menangkap string kosong dan kembali, tidak ada gunanya melakukan sisa pekerjaan.
    • str = str.replace(/^0+/, "") || "0"; menghapus semua 0 terkemuka dari string - tetapi jika itu menghasilkan string kosong, mengembalikan satu 0.
  2. Number(str): Konversi strke angka; jumlahnya mungkin memiliki porsi fraksional, atau mungkin NaN.

  3. Math.floor: Pangkas angkanya (memotong bagian pecahan).

  4. String(...): Mengubah hasil kembali menjadi string desimal normal. Untuk jumlah yang sangat besar, ini akan masuk ke notasi ilmiah, yang mungkin mematahkan pendekatan ini. (Saya tidak tahu di mana perpecahan itu, detailnya ada dalam spesifikasi , tetapi untuk bilangan bulat, saya yakin itu pada titik Anda telah melampaui 21 digit [saat itu jumlahnya menjadi sangat tidak tepat, seperti IEEE-754 angka presisi ganda hanya memiliki presisi 15 digit ..)

  5. ... === str: Membandingkannya dengan string asli.

  6. n >= 0: Periksa apakah itu positif.

Perhatikan bahwa ini gagal untuk input "+1", input apa pun dalam notasi ilmiah yang tidak berubah menjadi notasi ilmiah yang sama di atas String(...)panggung, dan untuk nilai apa pun yang digunakan oleh nomor jenis JavaScript (IEEE-754 floating point biner presisi ganda) tidak dapat secara akurat menunjukkan parses mana yang lebih dekat ke nilai yang berbeda dari yang diberikan (yang mencakup banyak bilangan bulat lebih dari 9.007.199.254.740.992; misalnya, 1234567890123456789akan gagal). Yang pertama adalah perbaikan yang mudah, dua yang terakhir tidak begitu banyak.

Ekspresi Reguler

Pendekatan lain adalah untuk menguji karakter string melalui ekspresi reguler, jika tujuan Anda hanya mengizinkan (katakanlah) sebuah opsi +diikuti oleh salah satu 0atau string dalam format desimal normal:

function isNormalInteger(str) {
    return /^\+?(0|[1-9]\d*)$/.test(str);
}

Testbed langsung:

Cara kerjanya:

  1. ^: Cocokkan mulai dari string

  2. \+?: Izinkan satu, opsional +(hapus ini jika Anda tidak mau)

  3. (?:...|...): Izinkan salah satu dari dua opsi ini (tanpa membuat grup tangkap):

    1. (0|...): Izinkan 0sendiri ...

    2. (...|[1-9]\d*): ... atau angka yang dimulai dengan sesuatu selain 0dan diikuti oleh sejumlah angka desimal.

  4. $: Cocokkan ujung string.

Jika Anda ingin melarang 0(karena itu tidak positif), ekspresi reguler menjadi adil /^\+?[1-9]\d*$/(misalnya, kita dapat kehilangan pergantian yang perlu kami izinkan 0).

Jika Anda ingin membolehkan angka nol di depan (0123, 00524), maka ganti saja alternasinya (?:0|[1-9]\d*)dengan\d+

function isNormalInteger(str) {
    return /^\+?\d+$/.test(str);
}

Jika Anda ingin membolehkan spasi putih, tambahkan \s*setelah ^dan \s*sebelum $.

Catatan untuk ketika Anda mengonversikannya menjadi angka: Pada mesin modern mungkin akan baik untuk digunakan +stratau Number(str)melakukannya, tetapi yang lebih tua mungkin memperpanjangnya dengan cara yang tidak standar (tetapi sebelumnya diizinkan) yang mengatakan nol di depan berarti oktal (basis 8), mis. "010" => 8. Setelah Anda memvalidasi angka, Anda dapat menggunakan dengan aman parseInt(str, 10)untuk memastikan bahwa itu diuraikan sebagai desimal (basis 10). parseIntakan mengabaikan sampah di akhir string, tetapi kami telah memastikan tidak ada dengan regex.

TJ Crowder
sumber
keduanya Number(' ')dan Number('')kembali 0sementara harus NaNsebaliknya.
neurino
@ TJCrowder ok tapi saya butuh string seperti '2a' 'untuk ditolak, parseIntkembali 2.
neurino
@neurino: /\D/.test('2a')benar (karena ada non-digit). Jadi mungkin if (!/\D/.test(str) && !isNan((num = parseInt(str, 10))) { /* Valid number in num */}... Tepat di atas kepala saya ...
TJ Crowder
Dari segi kinerja, metode mana yang lebih cepat? Atau yang mana yang disarankan?
phkavitha
@ phkavitha: Jawaban atas pertanyaan kinerja JavaScript hampir selalu "Itu tergantung" karena mesin yang berbeda sangat berbeda satu sama lain. Anda dapat menguji mesin / browser target Anda menggunakan jsperf.com . Saya tidak akan berpikir operasi ini akan menjadi penghambat dalam aplikasi apa pun ... :-)
TJ Crowder
76

Solusi 1

Jika kami menganggap integer JavaScript sebagai nilai maksimum 4294967295(yaitu Math.pow(2,32)-1), maka solusi singkat berikut ini akan berfungsi dengan baik:

function isPositiveInteger(n) {
    return n >>> 0 === parseFloat(n);
}

DESKRIPSI:

  1. Operator zero-fill right shift melakukan tiga hal penting:
    • memotong bagian desimal
      • 123.45 >>> 0 === 123
    • apakah pergeseran untuk angka negatif
      • -1 >>> 0 === 4294967295
    • "berfungsi" dalam kisaran MAX_INT
      • 1e10 >>> 0 === 1410065408
      • 1e7 >>> 0 === 10000000
  2. parseFloatmelakukan parsing nomor string yang benar (pengaturan NaNuntuk string non numerik)

UJI:

"0"                     : true
"23"                    : true
"-10"                   : false
"10.30"                 : false
"-40.1"                 : false
"string"                : false
"1234567890"            : true
"129000098131766699.1"  : false
"-1e7"                  : false
"1e7"                   : true
"1e10"                  : false
"1edf"                  : false
" "                     : false
""                      : false

DEMO: http://jsfiddle.net/5UCy4/37/


Solusi 2

Cara lain baik untuk semua nilai numerik yang valid hingga Number.MAX_VALUE, yaitu sekitar 1.7976931348623157e+308:

function isPositiveInteger(n) {
    return 0 === n % (!isNaN(parseFloat(n)) && 0 <= ~~n);
}

DESKRIPSI:

  1. !isNaN(parseFloat(n))digunakan untuk menyaring murni nilai string, misalnya "", " ", "string";
  2. 0 <= ~~nmenyaring negatif dan nilai-nilai non-integer besar, misalnya "-40.1", "129000098131766699";
  3. (!isNaN(parseFloat(n)) && 0 <= ~~n)kembali truejika nilainya numerik dan positif ;
  4. 0 === n % (...)memeriksa apakah nilainya tidak mengambang - di sini (...)(lihat 3) dievaluasi seperti 0dalam kasus false, dan seperti 1dalam kasus true.

UJI:

"0"                     : true
"23"                    : true
"-10"                   : false
"10.30"                 : false
"-40.1"                 : false
"string"                : false
"1234567890"            : true
"129000098131766699.1"  : false
"-1e10"                 : false
"1e10"                  : true
"1edf"                  : false
" "                     : false
""                      : false

DEMO: http://jsfiddle.net/5UCy4/14/


Versi sebelumnya:

function isPositiveInteger(n) {
    return n == "0" || ((n | 0) > 0 && n % 1 == 0);
}

DEMO: http://jsfiddle.net/5UCy4/2/

Penglihatan
sumber
Coba string kosong atau sejumlah besar seperti 1290000981231123.1 - jsfiddle.net/5UCy4/1
Niko
@ gdoron Sama dengan ~~val, memotong bagian fraksional. Ini sedikit lebih cepat karena melakukan satu operasi bitwise bukannya dua.
VisioN
Jawaban yang bagus Secara pribadi saya lebih suka sedikit lebih mudah dibaca(!isNaN(parseFloat(n)) && n % 1 === 0 && 0 <= ~~n)
Ramy Nasr
true, false, 0xFF, dan nilai-nilai lainnya berhasil isPositiveIntegertanpa terdeteksi.
Xeoncross
1
Yang ini bahkan menangani nol yang empuk (bagus!). Anda dapat menambahkan itu ke tes Anda.
Rashack
21

Sepertinya ekspresi reguler adalah caranya:

var isInt = /^\+?\d+$/.test('the string');
Niko
sumber
Tutup, kecuali "1.0" atau ".1e1" diizinkan.
Phrogz
Nah 1290000192379182379123782900192981231 adalah bilangan bulat tetapi tidak dapat diwakili persis dalam angka asli JavaScript, jadi dengan regex masih perlu melakukan konversi numerik dan memverifikasi bahwa itu berhasil.
Runcing
Ini adalah solusi yang sangat tidak tepat.
usr
@ Usr: Saya kira itu memungkinkan memimpin di 0tempat yang biasanya tidak Anda harapkan, tetapi sebagian besar, tampaknya baik-baik saja.
TJ Crowder
Itu tidak memeriksa rentang paling banyak 2 ^ 31-1 dan itu tidak memungkinkan angka arab. Ini adalah retasan, bukan solusi yang baik. Solusi terbaik memiliki upvotes terbanyak dalam pertanyaan ini. Mengapa tidak menggunakannya? Lebih baik dalam segala hal.
usr
17

Solusi modern yang bekerja di node dan di lebih dari 90% dari semua browser (kecuali IE dan Opera Mini) adalah dengan menggunakan Number.isInteger diikuti oleh pemeriksaan positif sederhana.

Number.isInteger(x) && x > 0

Ini diselesaikan dalam ECMAScript 2015 .

function isPositiveInteger(x) {
    return Number.isInteger(x) && x > 0
}

Polyfil adalah:

Number.isInteger = Number.isInteger || function(value) {
  return typeof value === 'number' && 
    isFinite(value) && 
    Math.floor(value) === value;
};

Jika Anda perlu mendukung input yang mungkin dalam bentuk string atau angka maka Anda dapat menggunakan fungsi ini Saya menulis sebuah test suite besar setelah semua jawaban yang ada (2/1/2018) gagal pada beberapa bentuk input.

function isPositiveInteger(v) {
  var i;
  return v && (i = parseInt(v)) && i > 0 && (i === v || ''+i === v);
}
Xeoncross
sumber
4

Ini hampir merupakan pertanyaan rangkap untuk pertanyaan ini:

Validasi angka desimal dalam JavaScript - IsNumeric ()

Jawabannya adalah:

function isNumber(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

jadi, bilangan bulat positif adalah:

function isPositiveInteger(n) {
  var floatN = parseFloat(n);
  return !isNaN(floatN) && isFinite(n) && floatN > 0
      && floatN % 1 == 0;
}
Chango
sumber
Saya tahu ini hampir merupakan duplikat dari pertanyaan 'Validasi angka dalam JavaScript', saya membaca semuanya, tapi saya pikir pertanyaan khusus tentang representasi string bilangan bulat layak halaman itu sendiri.
Mick Byrne
2
return ((parseInt(str, 10).toString() == str) && str.indexOf('-') === -1);

tidak akan bekerja jika Anda memberikan string seperti '0001'

Sebas
sumber
2

Fungsi saya memeriksa apakah angka + ve dan bisa memiliki nilai desimal juga.

       function validateNumeric(numValue){
            var value = parseFloat(numValue);
            if (!numValue.toString().match(/^[-]?\d*\.?\d*$/)) 
                    return false;
            else if (numValue < 0) {
                return false;
            }
            return true;        
        }
Deepak Nirala
sumber
2

Hanya untuk membangun jawaban VisioN di atas, jika Anda menggunakan plugin validasi jQuery Anda dapat menggunakan ini:

$(document).ready(function() {
    $.validator.addMethod('integer', function(value, element, param) {
        return (value >>> 0 === parseFloat(value) && value > 0);
    }, 'Please enter a non zero integer value!');
}

Kemudian Anda dapat menggunakan dalam aturan normal Anda mengatur atau menambahkannya secara dinamis dengan cara ini:

$("#positiveIntegerField").rules("add", {required:true, integer:true});
usr-bin-drinking
sumber
2

Sederhana

function isInteger(num) {
  return (num ^ 0) === num;
}

console.log(isInteger(1));

Anda juga dapat menambah Nomor dan menetapkan fungsinya melalui prototipe.

manish kumar
sumber
1

Jika Anda menggunakan formulir HTML5, Anda bisa menggunakan atribut min="0"untuk elemen formulir <input type="number" />. Ini didukung oleh semua browser utama. Itu tidak melibatkan Javascript untuk tugas-tugas sederhana seperti itu, tetapi terintegrasi dalam standar html baru. Itu didokumentasikan di https://www.w3schools.com/tags/att_input_min.asp

mggluscevic
sumber
0

(~~a == a)dimana asenarnya.

Gus
sumber
1
Ini akan gagal untuk angka negatif: ~~"-1" == "-1"akan kembali true. Dan OP hanya meminta bilangan bulat positif.
Igor Milla
1
Gagal juga untuk '' dan ''.
neverfox
0

ES6:

Number.isInteger(Number(theNumberString)) > 0
oma
sumber