ตรวจสอบว่าสตริงเป็นจำนวนเต็มบวก


200

ฉันต้องการการทดสอบล้มเหลวที่ง่ายที่สุดเพื่อตรวจสอบว่าสตริงใน JavaScript เป็นจำนวนเต็มบวก

isNaN(str)ส่งคืนค่าจริงสำหรับทุกประเภทของค่าที่ไม่ใช่จำนวนเต็มและparseInt(str)ส่งคืนจำนวนเต็มสำหรับสตริงลอยเช่น "2.5" และฉันไม่ต้องการที่จะใช้ปลั๊กอิน jQuery บางอย่างเช่นกัน


7
คุณอนุญาต "+2" หรือไม่ วิธีการเกี่ยวกับ "0.1e1" เกี่ยวกับ "1.0000"
Phrogz

isNaN()ฟังก์ชั่นทำงานทางมันไม่เพราะแนวคิดNot a Numberที่มีความหมายที่เฉพาะเจาะจงมากในข้อกำหนดจุด IEEE 794 ลอย ไม่ต้องการให้คำตอบสำหรับคำถามเกี่ยวกับภาษาพูดง่ายๆ "ค่านี้ไม่ใช่ตัวเลขใช่หรือไม่"
Pointy

3
คำถามที่คลุมเครือมาก คุณไม่สามารถตรวจสอบได้ว่า "สตริงเป็นจำนวนเต็ม" เนื่องจากไม่มีสิ่งนั้น - ไม่มีวัตถุใดที่สามารถเป็นสตริงและตัวเลขได้ในเวลาเดียวกัน คุณอาจหมายถึง "วิธีการทดสอบว่าสตริงเป็นตัวแทนที่ถูกต้องของจำนวนเต็ม" แต่เพื่อตอบคำถามนี้เราจำเป็นต้องรู้ภาษาหรือ "วัฒนธรรม" ที่คุณกำลังพูดถึง ตัวอย่างเช่น٢‎٣٤หรือMCMXIXเป็นทั้งจำนวนเต็มที่ถูกต้อง แต่ฉันไม่คิดว่าคุณกำลังมองหารหัสที่จะสามารถแยกวิเคราะห์เหล่านี้ คุณช่วยระบุรูปแบบตัวเลขที่คุณจะให้การสนับสนุนได้หรือไม่เพราะคนดูสับสน
georg

5
ฉันคิดว่า 'คลุมเครือไปสุดขั้ว' นั้นรุนแรงเกินไป แต่อย่างไรก็ตาม ... บริบทคือการตรวจสอบความถูกต้องของฟิลด์การป้อนข้อมูลปริมาณบนรถเข็นช็อปปิ้งที่ใช้ในประเทศที่ใช้ภาษาอังกฤษดังนั้นตัวเลขเท่านั้น โดย "บวก" ฉันหมายถึงมากกว่าศูนย์ ฉันจะยอมรับสิ่งต่อไปนี้: "+2" ใช่ "0.1e1" ไม่ "1.000" แน่นอนว่าทำไมไม่ อย่างไรก็ตามหากคุณสามารถให้คำตอบที่สามารถปรับให้รวม / ยกเว้นสถานการณ์พิเศษต่างๆเหล่านี้ได้ฉันสัญญาว่าจะให้บริการเสริม (และฉันมั่นใจว่าคนอื่นจะทำเช่นเดียวกัน)
มิกเบิร์น

คำตอบ:


296

คำตอบสองข้อสำหรับคุณ:

  • ขึ้นอยู่กับการแยกวิเคราะห์

  • การแสดงออกปกติ

โปรดทราบว่าในทั้งสองกรณีฉันได้ตีความ "จำนวนเต็มบวก" ให้รวม0แม้ว่า0จะไม่เป็นบวก 0ผมรวมถึงการบันทึกถ้าคุณต้องการที่จะไม่อนุญาตให้

ขึ้นอยู่กับการแยกวิเคราะห์

หากคุณต้องการให้มันเป็นสตริงจำนวนเต็มฐานสิบในช่วงของค่าที่เหมาะสมคุณสามารถทำได้:

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

หรือถ้าคุณต้องการอนุญาตให้มีช่องว่างและศูนย์นำหน้า:

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

Live testbed (โดยไม่ต้องจัดการกับศูนย์หรือช่องว่างชั้นนำ):

Live testbed ( พร้อมการจัดการสำหรับศูนย์นำหน้าและช่องว่าง):

หากคุณต้องการที่จะไม่อนุญาตให้0เพียงแค่เปลี่ยนไป>= 0 > 0(หรือในเวอร์ชันที่อนุญาตให้ศูนย์นำหน้าให้ลบเครื่องหมาย|| "0"บนreplaceบรรทัด)

มันทำงานอย่างไร:

  1. ในเวอร์ชันที่อนุญาตให้มีช่องว่างและศูนย์นำหน้า:

    • str = str.trim(); ลบ whitepace ที่นำหน้าและต่อท้าย
    • if (!str) จับสตริงว่างและส่งคืนไม่มีจุดในการทำงานที่เหลือ
    • str = str.replace(/^0+/, "") || "0"; ลบ 0s นำหน้าทั้งหมดออกจากสตริง - แต่หากผลลัพธ์นั้นเป็นสตริงว่างให้เรียกคืน 0 เดียว
  2. Number(str): แปลงstrเป็นตัวเลข; จำนวนอาจมีส่วนที่เป็นเศษส่วนหรืออาจเป็นNaNได้

  3. Math.floor: ตัดทอนตัวเลข (ตัดส่วนที่เป็นเศษส่วนออก)

  4. String(...): แปลงผลลัพธ์กลับเป็นสตริงทศนิยมปกติ สำหรับตัวเลขจำนวนมากสิ่งนี้จะเป็นสัญกรณ์ทางวิทยาศาสตร์ซึ่งอาจทำให้วิธีการนี้แตก (ฉันไม่รู้ว่าตัวแยกอยู่ตรงไหนรายละเอียดอยู่ในสเป็คแต่สำหรับตัวเลขทั้งหมดฉันเชื่อว่ามันอยู่ที่จุดที่คุณได้เกิน 21 หลัก [ตามเวลาที่จำนวนกลายเป็นไม่แน่นอนมากเช่น IEEE-754 ตัวเลขที่มีความแม่นยำสองเท่ามีความแม่นยำ 15 หลักเท่านั้น .. )

  5. ... === str: เปรียบเทียบกับสตริงเดิม

  6. n >= 0: ตรวจสอบว่าเป็นบวก

โปรดทราบว่าสิ่งนี้ล้มเหลวสำหรับอินพุตอินพุต"+1"ใด ๆ ในสัญกรณ์วิทยาศาสตร์ที่ไม่เปลี่ยนกลับไปเป็นสัญกรณ์ทางวิทยาศาสตร์แบบเดียวกันที่String(...)เวทีและสำหรับค่าใด ๆ ที่จาวาสคริปต์แบบตัวเลขใช้ (IEEE-754 จุดลอยตัวไบนารีความแม่นยำสองเท่า) ไม่สามารถแสดงได้อย่างถูกต้องว่าตัวแยกวิเคราะห์ใดที่ใกล้เคียงกับค่าที่แตกต่างจากค่าที่ระบุ (ซึ่งมีจำนวนเต็มมากกว่า 9,007,199,254,740,992 ตัวอย่างเช่น1234567890123456789จะล้มเหลว) อดีตคือการแก้ไขที่ง่ายสองหลังไม่มาก

การแสดงออกปกติ

อีกวิธีหนึ่งคือการทดสอบอักขระของสตริงผ่านนิพจน์ทั่วไปหากเป้าหมายของคุณคืออนุญาต (พูด) ตัวเลือก+ตามด้วย0สตริงตัวใดตัวหนึ่งหรือสตริงในรูปแบบทศนิยมปกติ:

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

เตียงทดสอบสด:

มันทำงานอย่างไร:

  1. ^: จับคู่เริ่มต้นของสตริง

  2. \+?: อนุญาตหนึ่งตัวเลือก+(ลบออกหากคุณไม่ต้องการ)

  3. (?:...|...): อนุญาตหนึ่งในสองตัวเลือกเหล่านี้ (โดยไม่สร้างกลุ่มการจับภาพ):

    1. (0|...): อนุญาต0ด้วยตัวมันเอง ...

    2. (...|[1-9]\d*): ... หรือตัวเลขที่ขึ้นต้นด้วยอย่างอื่นที่ไม่ใช่0และตามด้วยตัวเลขทศนิยมใด ๆ

  4. $: จับคู่ส่วนท้ายของสตริง

หากคุณต้องการไม่อนุญาต0(เพราะไม่ใช่เชิงบวก) การแสดงออกปกติจะกลายเป็นเพียงแค่/^\+?[1-9]\d*$/(เช่นเราอาจสูญเสียการสลับที่เราจำเป็นต้องอนุญาต0)

หากคุณต้องการอนุญาตให้เลขศูนย์นำหน้า (0123, 00524) จากนั้นเพียงแทนที่การสลับ(?:0|[1-9]\d*)ด้วย\d+

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

หากคุณต้องการที่จะช่วยให้ช่องว่างเพิ่ม\s*หลัง^และก่อน\s*$

หมายเหตุเมื่อคุณแปลงที่หมายเลข: เกี่ยวกับเครื่องมือที่ทันสมัยก็อาจจะถูกปรับให้ใช้งาน+strหรือNumber(str)ที่จะทำมัน แต่คนเก่าอาจขยายผู้ที่อยู่ในทางที่ไม่ได้มาตรฐาน ( แต่ก่อนได้รับอนุญาต) ที่ระบุว่าเป็นศูนย์หมายถึงชั้นนำฐานแปด (ฐาน 8) เช่น "010" => 8. เมื่อคุณตรวจสอบความถูกต้องของตัวเลขแล้วคุณสามารถใช้parseInt(str, 10)เพื่อให้แน่ใจว่ามันจะแยกเป็นทศนิยม (ฐาน 10) parseIntจะไม่สนใจขยะในตอนท้ายของสตริง แต่เรามั่นใจว่าไม่มี regex


ทั้งสองNumber(' ')และNumber('')กลับมา0ในขณะที่ควรกลับมาNaNแทน
neurino

@TJCrowder ตกลง แต่ฉันต้องการสตริงเช่น '' 2a '' ที่จะถูกปฏิเสธอย่างใดparseIntกลับ2มา
neurino

@neurino: /\D/.test('2a')เป็นจริง (เพราะไม่มีตัวเลข) ดังนั้นอาจif (!/\D/.test(str) && !isNan((num = parseInt(str, 10))) { /* Valid number in num */}... แค่ปิดหัวฉัน ...
TJ Crowder

ประสิทธิภาพฉลาดวิธีใดจะเร็วขึ้น หรืออันไหนแนะนำให้เลือก?
phkavitha

@phkavitha: คำตอบสำหรับคำถามเกี่ยวกับประสิทธิภาพ JavaScript มักจะเป็น "มันขึ้นอยู่กับ" เพราะเอ็นจิ้นที่แตกต่างกันนั้นแตกต่างกันมาก คุณสามารถทดสอบเครื่องมือเป้าหมายของคุณ / เบราว์เซอร์ที่ใช้jsperf.com ฉันไม่คิดว่าการดำเนินการนี้น่าจะเป็นคอขวดในแอปใดก็ตาม ... :-)
TJ Crowder

76

โซลูชันที่ 1

หากเราพิจารณาว่าจำนวนเต็ม JavaScript เป็นค่าสูงสุด4294967295(เช่นMath.pow(2,32)-1) ดังนั้นโซลูชันระยะสั้นต่อไปนี้จะทำงานได้อย่างสมบูรณ์แบบ:

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

รายละเอียด:

  1. ตัวดำเนินการกะที่ถูกต้องแบบไม่มีการเติมเต็มทำให้สามสิ่งสำคัญ:
    • ตัดส่วนทศนิยม
      • 123.45 >>> 0 === 123
    • การเปลี่ยนแปลงของจำนวนลบหรือไม่
      • -1 >>> 0 === 4294967295
    • "ทำงาน" ในช่วงของ MAX_INT
      • 1e10 >>> 0 === 1410065408
      • 1e7 >>> 0 === 10000000
  2. parseFloatทำการแยกวิเคราะห์หมายเลขสตริงอย่างถูกต้อง (การตั้งค่าNaNสำหรับสตริงที่ไม่ใช่ตัวเลข)

แบบทดสอบ:

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


โซลูชันที่ 2

อีกวิธีหนึ่งที่ดีสำหรับค่าตัวเลขทั้งหมดที่ใช้ได้จนถึงNumber.MAX_VALUEกล่าวคือ1.7976931348623157e+308:

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

รายละเอียด:

  1. !isNaN(parseFloat(n))ถูกนำมาใช้ในการกรองบริสุทธิ์ค่าสตริงเช่น"", " ", "string";
  2. 0 <= ~~nกรองเชิงลบและค่าที่ไม่ใช่จำนวนเต็มขนาดใหญ่เช่น"-40.1", "129000098131766699";
  3. (!isNaN(parseFloat(n)) && 0 <= ~~n)ผลตอบแทนtrueถ้าค่าเป็นทั้งตัวเลขและบวก ;
  4. 0 === n % (...)การตรวจสอบถ้าค่าไม่ลอย - ที่นี่(...)(ดู 3) มีการประเมินว่า0ในกรณีของfalseและเป็นในกรณีของ1true

แบบทดสอบ:

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


รุ่นก่อนหน้า:

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

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


ลองใช้สตริงว่างหรือเป็นจำนวนมากเช่น 1290000981231123.1 - jsfiddle.net/5UCy4/1
Niko

@gdoron เช่นเดียวกับ~~valการตัดส่วนที่เป็นเศษส่วน มันเร็วกว่านิดหน่อยตั้งแต่ใช้การทำงานระดับบิตเดียวแทนที่จะเป็นสองแบบ
VisioN

คำตอบที่ดี โดยส่วนตัวแล้วฉันชอบที่จะอ่านรายละเอียดเพิ่มเติมเล็กน้อย(!isNaN(parseFloat(n)) && n % 1 === 0 && 0 <= ~~n)
Ramy Nasr

true, false, 0xFFและค่าอื่น ๆ ทำให้ผ่านisPositiveIntegerโดยไม่ถูกตรวจพบ
Xeoncross

1
อันนี้จะจัดการกับศูนย์ padded (ดี!) คุณสามารถเพิ่มสิ่งนั้นลงในการทดสอบของคุณ
Rashack

21

ดูเหมือนว่าการแสดงออกปกติเป็นวิธีที่จะไป:

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

ปิดเว้นแต่จะอนุญาตให้ "1.0" หรือ ".1e1"
Phrogz

ดี 1290000192379182379123782900192981231 เป็นจำนวนเต็ม แต่ไม่สามารถแทนได้อย่างชัดเจนในหมายเลขพื้นเมืองของ JavaScript ดังนั้นด้วย regex ยังจำเป็นต้องทำการแปลงตัวเลขและตรวจสอบว่ามันใช้งานได้จริง
Pointy

นี่เป็นวิธีที่ไม่แม่นยำมาก
usr

@usr: ฉันคิดว่ามันช่วยให้นำ0ที่คุณปกติไม่คาดหวัง แต่ส่วนใหญ่ดูเหมือนดี
TJ Crowder

ไม่ได้ตรวจสอบช่วงที่มีค่าไม่เกิน 2 ^ 31-1 และไม่อนุญาตให้ใช้เลขอารบิค นี่คือแฮ็คไม่ใช่ทางออกที่ดี ทางออกที่ดีที่สุดมี upvotes มากที่สุดในคำถามนี้ ทำไมไม่ใช้อันนั้น มันจะดีกว่าในทุกเรื่อง
usr

17

ทางออกที่ทันสมัยที่ทำงานในโหนดและข้าม90% ของเบราว์เซอร์ทั้งหมด (ยกเว้น IE และ Opera Mini) คือการใช้Number.isIntegerตามด้วยการตรวจสอบเชิงบวกอย่างง่าย

Number.isInteger(x) && x > 0

นี้ได้รับการสรุปใน ECMAScript 2015

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

Polyfil คือ:

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

หากคุณต้องการสนับสนุนอินพุตที่อาจอยู่ในรูปแบบสตริงหรือตัวเลขคุณสามารถใช้ฟังก์ชั่นนี้ได้ฉันเขียนชุดทดสอบขนาดใหญ่เพื่อป้องกันหลังจากที่คำตอบที่มีอยู่ทั้งหมด (2/1/2018) ล้มเหลวในอินพุตบางรูปแบบ

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

4

นี่เป็นคำถามที่ซ้ำกันสำหรับคำถามนี้:

ตรวจสอบตัวเลขทศนิยมใน JavaScript - IsNumeric ()

คำตอบคือ:

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

ดังนั้นจำนวนเต็มบวกจะเป็น:

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

ฉันรู้ว่ามันเกือบจะซ้ำซ้อนกับคำถาม 'ตรวจสอบตัวเลขใน JavaScript' ฉันอ่านทุกอย่างแล้ว แต่ฉันคิดว่าคำถามเกี่ยวกับการแทนค่าสตริงของจำนวนเต็มสมควรได้รับเป็นหน้าของตัวเอง
มิกเบิร์น

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

จะไม่ทำงานถ้าคุณให้สตริงเหมือน '0001'


2

ฟังก์ชั่นของฉันตรวจสอบว่าตัวเลขเป็น + ve และอาจมีค่าทศนิยมเช่นกัน

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

2

เพียงสร้างคำตอบของ VisioN ด้านบนหากคุณใช้ปลั๊กอินตรวจสอบ jQuery คุณสามารถใช้สิ่งนี้:

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

จากนั้นคุณสามารถใช้ในชุดกฎปกติของคุณหรือเพิ่มแบบไดนามิกด้วยวิธีนี้:

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

2

ง่าย

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

console.log(isInteger(1));

นอกจากนี้คุณยังสามารถขยาย Number และกำหนดฟังก์ชั่นผ่านทางต้นแบบ


1

หากคุณกำลังใช้รูปแบบ HTML5 คุณสามารถใช้แอตทริบิวต์สำหรับองค์ประกอบแบบฟอร์มmin="0" <input type="number" />นี่คือเบราว์เซอร์หลักที่รองรับทั้งหมด มันไม่ได้เกี่ยวข้องกับ Javascript สำหรับงานง่ายๆเช่นนั้น แต่รวมอยู่ในมาตรฐาน html ใหม่ มีการบันทึกไว้ในhttps://www.w3schools.com/tags/att_input_min.asp


0

(~~a == a)ที่aเป็นสตริง


1
นี้จะล้มเหลวสำหรับตัวเลขที่ติดลบ: จะกลับมา~~"-1" == "-1" trueและ OP ขอเลขจำนวนเต็มบวกเท่านั้น
Igor Milla

1
ล้มเหลวด้วยสำหรับ '' และ ''
Neverfox

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.