Bir dizenin pozitif bir tam sayı olduğunu doğrulayın


200

JavaScript'te bir dize pozitif bir tamsayı olup olmadığını kontrol etmek için en basit başarısız-güvenli test istiyorum.

isNaN(str)tamsayı olmayan her türlü değer için true değerini parseInt(str)döndürür ve "2.5" gibi float dizeleri için tamsayı döndürür. Ve ben de bazı jQuery eklentisi kullanmak istemiyorum.


7
"+2" ye izin veriyor musunuz? "0.1e1" ne dersiniz? "1.0000" nasıl olur?
Phrogz

isNaN()Fonksiyon kavramı, çünkü neden bu şekilde davranır Not a Number, IEEE 794 kayan noktalı şartnamede çok özel bir anlamı vardır. Basit konuşma diline soruya cevap vermek niyetinde değil, "bu değer bir sayı değil mi?"
Sivri

3
Soru uç noktaya belirsiz. Böyle bir şey olmadığından, "bir dize bir tamsayıdır" olduğunu doğrulayamazsınız - hiçbir nesne bir dize ve bir sayı olamaz. Muhtemelen "bir dizenin bir tamsayının geçerli bir temsili olup olmadığını nasıl test edeceğinizi" kastediyorsunuzdur, ancak buna cevap vermek için hangi dilden veya "kültürden" bahsettiğinizi bilmemiz gerekir. Örneğin, ٢‎٣٤ya MCMXIXda her ikisi de geçerli tamsayı temsiller, ancak bunları ayrıştırabilecek bir kod aradığınızı sanmıyorum. İnsanlar bu konuda kafanız karıştığından hangi sayı biçimlerini destekleyeceğinizi belirtebilir misiniz?
georg

5
Bence 'aşırıya karşı belirsiz', biraz aşırı; ama yine de ... Bağlam İngilizce konuşulan bir ülkede kullanılan bir alışveriş sepeti üzerindeki miktar giriş alanının doğrulanmasıdır, bu yüzden sadece Batılı rakamlar. "Pozitif" ile sıfırdan büyük demek istedim. Aşağıdakileri kabul eder miyim: "+2" evet, "0.1e1" hayır, "1.000" neden olmasın. Ancak, bu çeşitli özel senaryoları dahil etmek / hariç tutmak için ayarlanabilen bir cevap sağlayabilirseniz, size ekstra ups vereceğime söz veriyorum (ve başkalarının da yapacağından eminim).
Mick Byrne

Yanıtlar:


297

Sizin için iki cevap:

  • Ayrıştırma esasına göre

  • Düzenli ifade

Her iki durumda da, pozitif 0olmasa 0da "pozitif tamsayı" yı içerecek şekilde yorumladığımı unutmayın. İzin vermemek istiyorsanız notlar ekliyorum 0.

Ayrıştırma Esasına Göre

Makul değerler aralığında normalleştirilmiş ondalık tam sayı dizesi olmasını istiyorsanız, bunu yapabilirsiniz:

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

veya boşluk ve baştaki sıfırlara izin vermek istiyorsanız:

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

Canlı test yatağı (önde gelen sıfırları veya boşlukları kullanmadan):

Canlı test yatağı ( önde gelen sıfırlar ve boşluklar için kullanım ile ):

Eğer izin vermemek istiyorsanız 0, sadece değiştirmek >= 0için > 0. (Veya önde gelen sıfırlara izin veren sürümde || "0", replacesatırı kaldırın .)

Bu nasıl çalışır:

  1. Boşluğa ve baştaki sıfırlara izin veren sürümde:

    • str = str.trim(); ön ve arkadaki beyaz boşlukları kaldırır.
    • if (!str) boş bir dize yakalar ve geri döner, işin geri kalanını yapmanın anlamı yoktur.
    • str = str.replace(/^0+/, "") || "0"; dizeden önde gelen tüm 0'ları kaldırır - ancak bu boş bir dizeyle sonuçlanırsa, tek bir 0'ı geri yükler.
  2. Number(str): strBir sayıya dönüştürme ; sayının kesirli bir kısmı olabilir veya olabilir NaN.

  3. Math.floor: Sayıyı kısaltın (kesirli kısmı keser).

  4. String(...): Sonucu tekrar normal ondalık bir dizeye dönüştürür. Gerçekten büyük sayılar için bu, bu yaklaşımı kırabilecek bilimsel gösterime gidecektir. (Bölmenin nerede olduğunu bilmiyorum , detaylar spesifikasyonda , ancak tam sayılar için bunun 21 basamağı aştığınıza inanıyorum [bu zamana kadar sayının çok kesinleşmediği, IEEE-754 çift ​​kesinlikli sayılar sadece 15 basamak hassasiyetle kesişir.)

  5. ... === str: Bunu orijinal dizeyle karşılaştırır.

  6. n >= 0: Pozitif olup olmadığını kontrol edin.

Bunun "+1"giriş, bilimsel gösterimdeki herhangi bir girişin String(...)aşamada aynı bilimsel gösterime dönüşmediği ve JavaScript'in kullandığı sayı türünün (IEEE-754 çift kesinlikli ikili kayan nokta) başarısız olduğunu unutmayın. hangi ayrıştırmaların verili olandan farklı bir değere daha yakın olduğunu doğru bir şekilde gösteremez (örneğin, 9,007,199,254,740,992'den fazla tamsayı içerir; 1234567890123456789başarısız olur). Birincisi kolay bir düzeltme, ikincisi çok fazla değil.

Düzenli ifade

Diğer yaklaşım, hedefiniz yalnızca isteğe bağlı bir seçeneğe ve +ardından 0normal ondalık biçimde bir dizeye veya bir dizeye izin vermek (diyelim) ise, dizenin karakterlerini normal bir ifade aracılığıyla test etmektir :

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

Canlı test yatağı:

Bu nasıl çalışır:

  1. ^: Dizenin maç başlangıcı

  2. \+?: Tek bir isteğe bağlı izin verin +(istemiyorsanız bunu kaldırın)

  3. (?:...|...): Bu iki seçenekten birine izin verin (bir yakalama grubu oluşturmadan):

    1. (0|...): 0Kendi başına izin ver ...

    2. (...|[1-9]\d*): ... veya 0herhangi bir ondalık basamaktan başka bir şeyle başlayan ve ardından gelen bir sayı.

  4. $: Dizenin sonuyla eşleşir.

İzin vermemek istiyorsanız 0(olumlu olmadığından), normal ifade sadece olur /^\+?[1-9]\d*$/(örneğin, izin vermemiz gereken değişimi değiştirebiliriz 0).

Önce gelen sıfırları (0123, 00524) izin vermek istiyorsanız, o zaman sadece münavebeye yerini (?:0|[1-9]\d*)ile\d+

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

Boşluğa izin vermek istiyorsanız, \s*hemen sonra ^ve \s*hemen önce ekleyin $.

Bunu bir sayıya dönüştürdüğünüzde dikkat edin: Modern motorlarda muhtemelen kullanmak +strveya Number(str)yapmak iyi olur, ancak daha eski olanlar standart olmayan (ancak daha önce izin verilmiş) bir şekilde önde gelen sıfır anlamına gelen sekizlik anlamına gelir. (taban 8), örneğin "010" => 8. Numarayı doğruladıktan sonra, parseInt(str, 10)ondalık olarak ayrıştırılmasını sağlamak için güvenle kullanabilirsiniz (taban 10). parseIntdizenin sonunda çöpü görmezden gelirdi, ama normal ifadeyle hiç bir şey olmadığından emin olduk.


Her iki Number(' ')ve Number('')dönüş 0sırasında dönmelidir NaNyerine.
neurino

@TJCrowder tamam ama bir şekilde reddedilmek için '' 2a '' gibi dizelere ihtiyacım var , parseIntdöndürür 2.
neurino

@neurino: /\D/.test('2a')doğrudur (çünkü rakam olmayan). Belki de if (!/\D/.test(str) && !isNan((num = parseInt(str, 10))) { /* Valid number in num */}... Sadece kafamın tepesinden ...
TJ Crowder

Performans açısından, hangi yöntem daha hızlı olurdu? Veya hangisi tavsiye edilir?
phkavitha

@phkavitha: JavaScript performans sorularının cevabı neredeyse her zaman "Bağlıdır" çünkü farklı motorlar birbirinden çok farklıdır. Jsperf.com'u kullanarak hedef motorlarınızı / tarayıcılarınızı test edebilirsiniz . Herhangi bir uygulamada bu operasyonun darboğaz olacağını düşünmüyorum ... :-)
TJ Crowder

76

Çözüm 1

Bir JavaScript tamsayısının maksimum (yani ) bir değer olduğunu düşünürsek , aşağıdaki kısa çözüm mükemmel bir şekilde çalışır:4294967295Math.pow(2,32)-1

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

AÇIKLAMA:

  1. Sıfır doldurma sağ kaydırma operatörü üç önemli şey yapar:
    • ondalık bölümü keser
      • 123.45 >>> 0 === 123
    • negatif sayılar için kayma
      • -1 >>> 0 === 4294967295
    • aralığında "çalışır" MAX_INT
      • 1e10 >>> 0 === 1410065408
      • 1e7 >>> 0 === 10000000
  2. parseFloatdize numaralarının ayrıştırılmasını düzeltir ( NaNsayısal olmayan dizeler için ayar )

TESTLERİ:

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


Çözüm 2

Diğer bir yolu geçerli yukarı olan tüm sayısal değerler için iyidir Number.MAX_VALUEyaklaşık yani 1.7976931348623157e+308:

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

AÇIKLAMA:

  1. !isNaN(parseFloat(n))filtrelemek için kullanılır saf dize değerleri, örneğin "", " ", "string";
  2. 0 <= ~~nnegatif ve büyük tam sayı olmayan değerler, filtre örneğin "-40.1", "129000098131766699";
  3. (!isNaN(parseFloat(n)) && 0 <= ~~n)döner truedeğeri hem de ise, sayısal ve pozitif ;
  4. 0 === n % (...)değeri olmayan yüzer ise kontrol - burada (...)(3 bakınız) olarak değerlendirilir 0durumunda falseve aynı 1olması durumunda true.

TESTLERİ:

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


Önceki sürüm:

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

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


Boş bir dize veya 1290000981231123.1 gibi büyük bir sayı deneyin - jsfiddle.net/5UCy4/1
Niko

@gdoron ~~valKesirli kısmı kesmekle aynı . İki yerine bir bit yönlü işlem yaptığından biraz daha hızlıdır.
VisioN

Mükemmel cevap. Şahsen okunabilirlik için biraz daha ayrıntılı olmayı tercih ediyorum(!isNaN(parseFloat(n)) && n % 1 === 0 && 0 <= ~~n)
Ramy Nasr

true, false, 0xFFve diğer değerler isPositiveIntegeralgılanmadan bunu gerçekleştirir .
Xeoncross

1
Bu bile yastıklı sıfırları (iyi!) Ele alır. Bunu testlerinize ekleyebilirsiniz.
Rashack

21

Normal bir ifade, gitmenin yolu gibi görünüyor:

var isInt = /^\+?\d+$/.test('the string');

"1.0" veya ".1e1" izin verilmedikçe kapatın.
Phrogz

1290000192379182379123782900192981231 bir tamsayıdır, ancak tam olarak JavaScript yerel numaralarında gösterilemez, bu nedenle normal ifadeyle sayısal bir dönüşüm yapmak ve çalıştığını doğrulamak gerekir.
Sivri

Bu çok kesin olmayan bir çözümdür.
usr

@usr: Sanırım 0normalde beklemediğiniz bir yere gitmenize izin veriyor , ancak çoğunlukla iyi görünüyor.
TJ Crowder

Aralığı en fazla 2 ^ 31-1 olarak kontrol etmez ve arapça rakamlara izin vermez. Bu bir hack, iyi bir çözüm değil. En iyi çözüm, bu soruda en çok oyuna sahiptir. Neden onu kullanmıyorsun? Her açıdan daha iyidir.
usr

17

Düğümde ve tüm tarayıcıların (IE ve Opera Mini hariç) % 90'ından fazlasında çalışan modern çözüm, Number.isInteger ve ardından basit bir pozitif kontrol kullanmaktır.

Number.isInteger(x) && x > 0

Bu, ECMAScript 2015'te sonuçlandırılmıştır .

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

Polifil:

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

Dize veya sayı biçiminde olabilecek girdiyi desteklemeniz gerekiyorsa, bu işlevi kullanabilirsiniz , mevcut tüm yanıtlar (2/1/2018) bir girdi biçiminde başarısız olduktan sonra karşı büyük bir test paketi yazdım .

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

4

Bu, bunun için neredeyse yinelenen bir soru:

JavaScript'te ondalık sayıları doğrulama - IsNumeric ()

Cevabı:

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

yani, pozitif bir tamsayı şöyle olur:

function isPositiveInteger(n) {
  var floatN = parseFloat(n);
  return !isNaN(floatN) && isFinite(n) && floatN > 0
      && floatN % 1 == 0;
}

Bu 'JavaScript'te sayıları doğrula' sorusunun neredeyse bir kopyası olduğunu biliyorum, her şeyi okudum, ancak özellikle tamsayıların dize gösterimleri hakkında bir soru kendi sayfasını hak ettiğini düşündüm.
Mick Byrne

2
return ((parseInt(str, 10).toString() == str) && str.indexOf('-') === -1);

'0001' gibi bir dize verirseniz çalışmaz


2

İşlevim, sayının + ve olup olmadığını ve ondalık değere sahip olup olmadığını kontrol eder.

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

2

Sadece VisioN'nin cevabı üzerine inşa etmek için, jQuery doğrulama eklentisini kullanıyorsanız bunu kullanabilirsiniz:

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

Daha sonra normal kural setinizde kullanabilir veya dinamik olarak bu şekilde ekleyebilirsiniz:

$("#positiveIntegerField").rules("add", {required:true, integer:true});

2

Basit

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

console.log(isInteger(1));

Ayrıca, Prototipi kullanarak Sayı'yı genişletebilir ve ona işlev atayabilirsiniz.



0

(~~a == a)adize nerede .


1
Bu negatif sayılar için başarısız olur: ~~"-1" == "-1"geri döner true. Ve OP sadece pozitif tamsayılar istedi.
Igor Milla

1
'' Ve '' için de başarısız olur.
neverfox

0

ES6:

Number.isInteger(Number(theNumberString)) > 0
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.