[javascript] JavaScript에서 10 진수 유효성 검사-IsNumeric ()

JavaScript에서 십진수의 유효성을 검사하는 가장 깨끗하고 효과적인 방법은 무엇입니까?

보너스 포인트 :

  1. 명쾌함. 솔루션은 깨끗하고 단순해야합니다.
  2. 크로스 플랫폼.

테스트 사례 :

01. IsNumeric('-1')      => true
02. IsNumeric('-1.5')    => true
03. IsNumeric('0')       => true
04. IsNumeric('0.42')    => true
05. IsNumeric('.42')     => true
06. IsNumeric('99,999')  => false
07. IsNumeric('0x89f')   => false
08. IsNumeric('#abcdef') => false
09. IsNumeric('1.2.3')   => false
10. IsNumeric('')        => false
11. IsNumeric('blah')    => false



답변

@Joel의 답변 은 매우 비슷하지만 다음과 같은 경우에는 실패합니다.

// Whitespace strings:
IsNumeric(' ')    == true;
IsNumeric('\t\t') == true;
IsNumeric('\n\r') == true;

// Number literals:
IsNumeric(-1)  == false;
IsNumeric(0)   == false;
IsNumeric(1.1) == false;
IsNumeric(8e5) == false;

얼마 전에 IsNumeric변수에 유형에 관계없이 숫자 값이 포함되어 있는지 확인하기 위해 함수 를 구현 해야했습니다 String. 숫자 값 (지수 표기법 등도 고려해야 함), Number객체, 거의 아무것도 해당 함수에 전달 될 수있는, 내가 강제 형 변환을 돌보는, 모든 종류의 가정을 만들 수 없습니다 (예. +true == 1;하지만 true로 간주되어서는 안됩니다 "numeric").

수많은 함수 구현에 대한이 +30 단위 테스트 세트를 공유하고 모든 테스트를 통과 한 단위 테스트를 공유 할 가치가 있다고 생각 합니다.

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

PS isNaN & isFinite 는 숫자로의 강제 변환으로 인해 혼란스러운 동작을합니다. ES6에서 Number.isNaN & Number.isFinite 는 이러한 문제를 해결합니다. 그것들을 사용할 때 명심하십시오.


업데이트 :
jQuery가 현재 수행하는 방법은 다음과 같습니다 (2.2-stable) :

isNumeric: function(obj) {
    var realStringObj = obj && obj.toString();
    return !jQuery.isArray(obj) && (realStringObj - parseFloat(realStringObj) + 1) >= 0;
}

업데이트 :
Angular 4.3 :

export function isNumeric(value: any): boolean {
    return !isNaN(value - parseFloat(value));
}


답변

아 아아아! 정규식 답변을 듣지 마십시오. RegEx는 이것에 icky이며 성능 만 말하는 것이 아닙니다. 정규 표현식에서 실수를 발견하기가 미묘하고 불가능합니다.

를 사용할 수 없으면 isNaN()훨씬 잘 작동합니다.

function IsNumeric(input)
{
    return (input - 0) == input && (''+input).trim().length > 0;
}

작동 방식은 다음과 같습니다.

(input - 0)표현식은 JavaScript가 입력 값에 대해 강제 변환을 수행하도록합니다. 먼저 빼기 연산의 숫자로 해석해야합니다. 숫자로의 변환이 실패하면식이됩니다 NaN. 그런 다음 이 숫자 결과는 전달한 원래 값과 비교됩니다. 왼쪽이 이제 숫자이므로 강제 변환 유형이 다시 사용됩니다. 양쪽의 입력이 동일한 원래 값에서 동일한 유형으로 강제되었으므로 항상 동일해야한다고 생각합니다 (항상 참). 그러나 NaN결코 같지 않은 특수 규칙이 NaN있으므로 숫자로 변환 할 수없는 값 (및 숫자로 변환 할 수없는 값만)은 false가됩니다.

길이 확인은 빈 문자열과 관련된 특수한 경우입니다. 또한 0x89f 테스트에 해당하지만 많은 환경에서 숫자 리터럴을 정의하는 것이 좋습니다. 특정 시나리오를 잡으려면 추가 검사를 추가 할 수 있습니다. 더 좋은 점은 그것이 사용하지 않는 이유 인 경우 추가 검사를 수행 할 수있는 isNaN()자체 기능을 감싸는 것 isNaN()입니다.

요약하면, 값을 숫자로 변환 할 수 있는지 알고 싶다면 실제로 숫자로 변환하십시오.


나는 돌아가서 공백 문자열에 예상 출력이없는 이유에 대한 조사를 수행 했으며 지금 얻는다고 생각합니다. 빈 문자열이 0아니라 강제됩니다 NaN. 길이를 확인하기 전에 문자열을 잘라 내면이 경우를 처리 할 수 ​​있습니다.

새로운 코드에 대해 단위 테스트를 실행하면 무한대와 부울 리터럴에서만 실패하며 문제가 될 유일한 시간은 코드를 생성하는 경우입니다 (실제로 누가 리터럴을 입력하고 숫자인지 확인합니까? ) 을 알아야 하며, 생성하기에는 이상한 코드 일 것입니다.

그러나 다시, 이것을 사용하는 유일한 이유는 어떤 이유로 isNaN ()을 피해야하는 경우입니다.


답변

이 방법은 잘 작동하는 것 같습니다.

function IsNumeric(input){
    var RE = /^-{0,1}\d*\.{0,1}\d+$/;
    return (RE.test(input));
}

한 줄로 :

const IsNumeric = (num) => /^-{0,1}\d*\.{0,1}\d+$/.test(num);

그리고 그것을 테스트하려면 :

const IsNumeric = (num) => /^-{0,1}\d*\.{0,1}\d+$/.test(num);

    function TestIsNumeric(){
        var results = ''
        results += (IsNumeric('-1')?"Pass":"Fail") + ": IsNumeric('-1') => true\n";
        results += (IsNumeric('-1.5')?"Pass":"Fail") + ": IsNumeric('-1.5') => true\n";
        results += (IsNumeric('0')?"Pass":"Fail") + ": IsNumeric('0') => true\n";
        results += (IsNumeric('0.42')?"Pass":"Fail") + ": IsNumeric('0.42') => true\n";
        results += (IsNumeric('.42')?"Pass":"Fail") + ": IsNumeric('.42') => true\n";
        results += (!IsNumeric('99,999')?"Pass":"Fail") + ": IsNumeric('99,999') => false\n";
        results += (!IsNumeric('0x89f')?"Pass":"Fail") + ": IsNumeric('0x89f') => false\n";
        results += (!IsNumeric('#abcdef')?"Pass":"Fail") + ": IsNumeric('#abcdef') => false\n";
        results += (!IsNumeric('1.2.3')?"Pass":"Fail") + ": IsNumeric('1.2.3') => false\n";
        results += (!IsNumeric('')?"Pass":"Fail") + ": IsNumeric('') => false\n";
        results += (!IsNumeric('blah')?"Pass":"Fail") + ": IsNumeric('blah') => false\n";

        return results;
    }

console.log(TestIsNumeric());
.as-console-wrapper { max-height: 100% !important; top: 0; }

http://www.codetoad.com/javascript/isnumeric.asp 에서 정규식을 빌 렸습니다 . 설명:

/^ match beginning of string
-{0,1} optional negative sign
\d* optional digits
\.{0,1} optional decimal point
\d+ at least one digit
$/ match end of string


답변

야후! UI 는 이것을 사용합니다 :

isNumber: function(o) {
    return typeof o === 'number' && isFinite(o);
}


답변

function IsNumeric(num) {
     return (num >=0 || num < 0);
}

이것은 0x23 타입 숫자에서도 작동합니다.


답변

받아 들여진 대답은 시험 # 7에 실패했으며 마음이 바뀌었기 때문입니다. 그래서 이것은 내가 받아 들인 대답에 대한 답변입니다.

일부 프로젝트 중에 일부 데이터의 유효성을 검사하고 가능한 한 수학 연산에 사용할 수있는 자바 스크립트 숫자 값인지 확인해야했습니다.

jQuery 및 일부 다른 자바 스크립트 라이브러리에는 이미 이러한 함수 (일반적으로)가 포함되어 isNumeric있습니다. 스택 오버 플로우 대한 게시물 도 앞에서 언급 한 라이브러리가 사용하는 것과 동일한 일반적인 루틴으로 대답으로 널리 받아 들여졌습니다.

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

첫째, 인수가 길이 1의 배열이고 단일 요소가 위의 논리에 의해 숫자로 간주되는 유형 인 경우 위의 코드는 true를 리턴합니다. 제 생각에는 배열이면 숫자가 아닙니다.

이 문제를 완화하기 위해 논리에서 어레이를 할인하는 검사를 추가했습니다.

function isNumber(n) {
  return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n);
}

물론 Array.isArray, jquery $.isArray또는 prototype Object.isArray대신Object.prototype.toString.call(n) !== '[object Array]'

두 번째 문제는 음의 16 진 정수 리터럴 문자열 ( “-0xA”-> -10)이 숫자로 계산되지 않았다는 것입니다. 그러나 양의 16 진 정수 리터럴 문자열 ( “0xA”-> 10)은 숫자로 처리되었습니다. 둘 다 유효한 숫자 여야했습니다.

그런 다음 이것을 고려하여 논리를 수정했습니다.

function isNumber(n) {
  return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
}

함수가 호출 될 때마다 정규 표현식 생성이 걱정되면 클로저 내에서 다시 작성할 수 있습니다.

var isNumber = (function () {
  var rx = /^-/;

  return function (n) {
      return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(rx, ''));
  };
}());

그런 다음 CMSs +30 테스트 사례 를 가져 와서 jsfiddle 에서 테스트를 복제하여 추가 테스트 사례와 위에서 설명한 솔루션을 추가했습니다.

널리 사용되거나 사용되는 답변을 대체하지는 않지만 isNumeric 함수의 결과로 기대하는 것 이상이라면 도움이 될 것입니다.

편집 : Bergi가 지적한 것처럼 숫자로 간주 될 수있는 다른 가능한 개체가 있으며 블랙리스트보다 화이트리스트 에 올리는 것이 좋습니다. 이를 염두에두고 기준에 추가하겠습니다.

내 isNumeric 함수가 숫자 또는 문자열 만 고려하기를 원합니다.

이를 염두에두고 사용하는 것이 좋습니다

function isNumber(n) {
  return (Object.prototype.toString.call(n) === '[object Number]' || Object.prototype.toString.call(n) === '[object String]') &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
}

솔루션 테스트

var testHelper = function() {

  var testSuite = function() {
    test("Integer Literals", function() {
      ok(isNumber("-10"), "Negative integer string");
      ok(isNumber("0"), "Zero string");
      ok(isNumber("5"), "Positive integer string");
      ok(isNumber(-16), "Negative integer number");
      ok(isNumber(0), "Zero integer number");
      ok(isNumber(32), "Positive integer number");
      ok(isNumber("040"), "Octal integer literal string");
      ok(isNumber(0144), "Octal integer literal");
      ok(isNumber("-040"), "Negative Octal integer literal string");
      ok(isNumber(-0144), "Negative Octal integer literal");
      ok(isNumber("0xFF"), "Hexadecimal integer literal string");
      ok(isNumber(0xFFF), "Hexadecimal integer literal");
      ok(isNumber("-0xFF"), "Negative Hexadecimal integer literal string");
      ok(isNumber(-0xFFF), "Negative Hexadecimal integer literal");
    });

    test("Foating-Point Literals", function() {
      ok(isNumber("-1.6"), "Negative floating point string");
      ok(isNumber("4.536"), "Positive floating point string");
      ok(isNumber(-2.6), "Negative floating point number");
      ok(isNumber(3.1415), "Positive floating point number");
      ok(isNumber(8e5), "Exponential notation");
      ok(isNumber("123e-2"), "Exponential notation string");
    });

    test("Non-Numeric values", function() {
      equals(isNumber(""), false, "Empty string");
      equals(isNumber("        "), false, "Whitespace characters string");
      equals(isNumber("\t\t"), false, "Tab characters string");
      equals(isNumber("abcdefghijklm1234567890"), false, "Alphanumeric character string");
      equals(isNumber("xabcdefx"), false, "Non-numeric character string");
      equals(isNumber(true), false, "Boolean true literal");
      equals(isNumber(false), false, "Boolean false literal");
      equals(isNumber("bcfed5.2"), false, "Number with preceding non-numeric characters");
      equals(isNumber("7.2acdgs"), false, "Number with trailling non-numeric characters");
      equals(isNumber(undefined), false, "Undefined value");
      equals(isNumber(null), false, "Null value");
      equals(isNumber(NaN), false, "NaN value");
      equals(isNumber(Infinity), false, "Infinity primitive");
      equals(isNumber(Number.POSITIVE_INFINITY), false, "Positive Infinity");
      equals(isNumber(Number.NEGATIVE_INFINITY), false, "Negative Infinity");
      equals(isNumber(new Date(2009, 1, 1)), false, "Date object");
      equals(isNumber(new Object()), false, "Empty object");
      equals(isNumber(function() {}), false, "Instance of a function");
      equals(isNumber([]), false, "Empty Array");
      equals(isNumber(["-10"]), false, "Array Negative integer string");
      equals(isNumber(["0"]), false, "Array Zero string");
      equals(isNumber(["5"]), false, "Array Positive integer string");
      equals(isNumber([-16]), false, "Array Negative integer number");
      equals(isNumber([0]), false, "Array Zero integer number");
      equals(isNumber([32]), false, "Array Positive integer number");
      equals(isNumber(["040"]), false, "Array Octal integer literal string");
      equals(isNumber([0144]), false, "Array Octal integer literal");
      equals(isNumber(["-040"]), false, "Array Negative Octal integer literal string");
      equals(isNumber([-0144]), false, "Array Negative Octal integer literal");
      equals(isNumber(["0xFF"]), false, "Array Hexadecimal integer literal string");
      equals(isNumber([0xFFF]), false, "Array Hexadecimal integer literal");
      equals(isNumber(["-0xFF"]), false, "Array Negative Hexadecimal integer literal string");
      equals(isNumber([-0xFFF]), false, "Array Negative Hexadecimal integer literal");
      equals(isNumber([1, 2]), false, "Array with more than 1 Positive interger number");
      equals(isNumber([-1, -2]), false, "Array with more than 1 Negative interger number");
    });
  }

  var functionsToTest = [

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

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

    function(n) {
      return !isNaN((n));
    },

    function(n) {
      return !isNaN(parseFloat(n));
    },

    function(n) {
      return typeof(n) != "boolean" && !isNaN(n);
    },

    function(n) {
      return parseFloat(n) === Number(n);
    },

    function(n) {
      return parseInt(n) === Number(n);
    },

    function(n) {
      return !isNaN(Number(String(n)));
    },

    function(n) {
      return !isNaN(+('' + n));
    },

    function(n) {
      return (+n) == n;
    },

    function(n) {
      return n && /^-?\d+(\.\d+)?$/.test(n + '');
    },

    function(n) {
      return isFinite(Number(String(n)));
    },

    function(n) {
      return isFinite(String(n));
    },

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

    function(n) {
      return parseFloat(n) == n;
    },

    function(n) {
      return (n - 0) == n && n.length > 0;
    },

    function(n) {
      return typeof n === 'number' && isFinite(n);
    },

    function(n) {
      return !Array.isArray(n) && !isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
    }

  ];


  // Examines the functionsToTest array, extracts the return statement of each function
  // and fills the toTest select element.
  var fillToTestSelect = function() {
    for (var i = 0; i < functionsToTest.length; i++) {
      var f = functionsToTest[i].toString();
      var option = /[\s\S]*return ([\s\S]*);/.exec(f)[1];
      $("#toTest").append('<option value="' + i + '">' + (i + 1) + '. ' + option + '</option>');
    }
  }

  var performTest = function(functionNumber) {
    reset(); // Reset previous test
    $("#tests").html(""); //Clean test results
    isNumber = functionsToTest[functionNumber]; // Override the isNumber global function with the one to test
    testSuite(); // Run the test

    // Get test results
    var totalFail = 0;
    var totalPass = 0;
    $("b.fail").each(function() {
      totalFail += Number($(this).html());
    });
    $("b.pass").each(function() {
      totalPass += Number($(this).html());
    });
    $("#testresult").html(totalFail + " of " + (totalFail + totalPass) + " test failed.");

    $("#banner").attr("class", "").addClass(totalFail > 0 ? "fail" : "pass");
  }

  return {
    performTest: performTest,
    fillToTestSelect: fillToTestSelect,
    testSuite: testSuite
  };
}();


$(document).ready(function() {
  testHelper.fillToTestSelect();
  testHelper.performTest(0);

  $("#toTest").change(function() {
    testHelper.performTest($(this).children(":selected").val());
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" type="text/javascript"></script>
<script src="https://rawgit.com/Xotic750/testrunner-old/master/testrunner.js" type="text/javascript"></script>
<link href="https://rawgit.com/Xotic750/testrunner-old/master/testrunner.css" rel="stylesheet" type="text/css">
<h1>isNumber Test Cases</h1>

<h2 id="banner" class="pass"></h2>

<h2 id="userAgent">Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11</h2>

<div id="currentFunction"></div>

<div id="selectFunction">
  <label for="toTest" style="font-weight:bold; font-size:Large;">Select function to test:</label>
  <select id="toTest" name="toTest">
  </select>
</div>

<div id="testCode"></div>

<ol id="tests">
  <li class="pass">
    <strong>Integer Literals <b style="color:black;">(0, 10, 10)</b></strong>

    <ol style="display: none;">
      <li class="pass">Negative integer string</li>

      <li class="pass">Zero string</li>

      <li class="pass">Positive integer string</li>

      <li class="pass">Negative integer number</li>

      <li class="pass">Zero integer number</li>

      <li class="pass">Positive integer number</li>

      <li class="pass">Octal integer literal string</li>

      <li class="pass">Octal integer literal</li>

      <li class="pass">Hexadecimal integer literal string</li>

      <li class="pass">Hexadecimal integer literal</li>
    </ol>
  </li>

  <li class="pass">
    <strong>Foating-Point Literals <b style="color:black;">(0, 6, 6)</b></strong>

    <ol style="display: none;">
      <li class="pass">Negative floating point string</li>

      <li class="pass">Positive floating point string</li>

      <li class="pass">Negative floating point number</li>

      <li class="pass">Positive floating point number</li>

      <li class="pass">Exponential notation</li>

      <li class="pass">Exponential notation string</li>
    </ol>
  </li>

  <li class="pass">
    <strong>Non-Numeric values <b style="color:black;">(0, 18, 18)</b></strong>

    <ol style="display: none;">
      <li class="pass">Empty string: false</li>

      <li class="pass">Whitespace characters string: false</li>

      <li class="pass">Tab characters string: false</li>

      <li class="pass">Alphanumeric character string: false</li>

      <li class="pass">Non-numeric character string: false</li>

      <li class="pass">Boolean true literal: false</li>

      <li class="pass">Boolean false literal: false</li>

      <li class="pass">Number with preceding non-numeric characters: false</li>

      <li class="pass">Number with trailling non-numeric characters: false</li>

      <li class="pass">Undefined value: false</li>

      <li class="pass">Null value: false</li>

      <li class="pass">NaN value: false</li>

      <li class="pass">Infinity primitive: false</li>

      <li class="pass">Positive Infinity: false</li>

      <li class="pass">Negative Infinity: false</li>

      <li class="pass">Date object: false</li>

      <li class="pass">Empty object: false</li>

      <li class="pass">Instance of a function: false</li>
    </ol>
  </li>
</ol>

<div id="main">
  This page contains tests for a set of isNumber functions. To see them, take a look at the source.
</div>

<div>
  <p class="result">Tests completed in 0 milliseconds.
    <br>0 tests of 0 failed.</p>
</div>


답변

예, 내장 isNaN(object)은 정규식 구문 분석보다 훨씬 빠릅니다. 내장되어 컴파일되지 않고 내장되어 컴파일되기 때문입니다.

결과가 찾고있는 것과 약간 다르지만 ( 시도해보십시오 ) :

                                              // IS NUMERIC
document.write(!isNaN('-1') + "<br />");      // true
document.write(!isNaN('-1.5') + "<br />");    // true
document.write(!isNaN('0') + "<br />");       // true
document.write(!isNaN('0.42') + "<br />");    // true
document.write(!isNaN('.42') + "<br />");     // true
document.write(!isNaN('99,999') + "<br />");  // false
document.write(!isNaN('0x89f') + "<br />");   // true
document.write(!isNaN('#abcdef') + "<br />"); // false
document.write(!isNaN('1.2.3') + "<br />");   // false
document.write(!isNaN('') + "<br />");        // true
document.write(!isNaN('blah') + "<br />");    // false