HOWTO · JavaScript

在 JavaScript 中验证表单输入中的数字

本文将教你如何在 JavaScript 中验证数字。我们将使用正则表达式和 JavaScript 函数,包括 isNaN、parseFloat 和 isFinite。

本页内容

要验证 HTML 表单中的数字,先确定表单接受哪些字符串。整数、带符号的小数和前后带空格的值属于不同格式。然后在提交时验证完整输入;输入过程中提供反馈会有帮助,但不能代替最终检查。

先确定哪些内容算作数字

JavaScript 可以将许多字符串转换为数字,但能否转换并不能决定表单的规则。例如,Number(" ") 的结果是 0,而 Number("12px") 的结果是 NaN。请决定是否接受正负号、小数、指数表示法、前后空格和空输入。如果应用要求输入正整数,就应强制执行这条具体规则,而不是把所有 JavaScript 能转换的值都视为有效。

使用正则表达式验证完整输入

当允许的格式有意设得较窄时,正则表达式很有用。下面的模式允许一个可选符号,后面跟一个或多个数字。RegExp.prototype.test() 会返回匹配结果的布尔值。

运行此示例:

本节中的代码以及显示的标签或输出仍为英文。

const wholeNumber = /^[+-]?\d+$/;
const value = "-42";
console.log(wholeNumber.test(value));

此模式接受 -42,拒绝 42x 和 2.5;它不会限制数值范围。JavaScript 的 $ 锚点也可能在字符串末尾的换行符之前匹配,因此应再明确检查是否存在换行符。下面的函数会拒绝该换行符,也会拒绝数字之后的任何其他文本:

const wholeNumber = /^[+-]?\d+$/;
const isWholeNumber = value =>
  wholeNumber.test(value) && !/[\r\n\u2028\u2029]$/.test(value);

console.log(isWholeNumber("-42"));
console.log(isWholeNumber("42x"));
console.log(isWholeNumber("2.5"));
console.log(isWholeNumber("42\n"));

这种格式检查不会设置数值范围。如果允许小数,请明确规定其语法,例如 3.、.5 或 -0.5 是否应被接受。不要用 /\d/ 这样的模式验证完整输入;它只会查找字符串中是否出现过数字。

使用 JavaScript 数字检查验证数字字符串

对于 JavaScript 的数字转换所接受的值,转换一次并检查结果即可。Number.isFinite() 会拒绝 NaN、正负无穷大以及非数字值。Number.isNaN() 则专门用于检测 NaN。相比之下,全局函数 isNaN() 会先强制转换参数,因此空白字符串等值可能看起来像数字。

要检查完整值,可以先去掉前后空格,拒绝空字符串,再用 Number() 转换剩余文本,并要求结果为有限数。下面的示例会先将允许的文本限制为带符号的十进制数和指数表示法,再进行转换;因此,0x10 这样的字符串会被排除,尽管 Number() 可以转换它。parseFloat() 通常不适合作为唯一的验证方法,因为它接受数字前缀,所以 12px 这样的文本会被解析为 12。

本节中的代码以及显示的标签或输出仍为英文。

function isDecimalNumber(value) {
  const trimmed = value.trim();
  const decimal = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
  if (trimmed === "" || !decimal.test(trimmed)) return false;
  return Number.isFinite(Number(trimmed));
}

const examples = ["", "12.5", "1e3", "12px"];
for (const value of examples) {
  console.log(`${JSON.stringify(value)}: ${isDecimalNumber(value)}`);
}

在这里,空输入和带有尾随文本的输入会失败,而 12.5 和 1e3 会通过。Number.isNaN() 可以识别 NaN 结果,但 Number.isFinite() 还会排除无穷大,因此是这里更合适的最终检查。

如需进一步了解这一区别,请参阅检查字符串是否为数字。

在用户输入时进行验证

监听 input 事件,在字段内容变化时更新提示状态。读取字段当前的 .value,并应用与提交时相同的完整值规则。下面这个简洁的浏览器示例会在用户编辑时以礼貌的方式更新状态,并在表单提交时再次检查:

本节中的代码以及显示的标签或输出仍为英文。

<form id="number-form">
  <label for="amount">Amount</label>
  <input id="amount" name="amount" type="text" inputmode="decimal">
  <p id="number-feedback" aria-live="polite">Enter a decimal number.</p>
  <button type="submit">Submit</button>
</form>
<script>
  const form = document.querySelector("#number-form");
  const field = document.querySelector("#amount");
  const feedback = document.querySelector("#number-feedback");

  function isDecimalNumber(value) {
    const trimmed = value.trim();
    const decimal = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
    return trimmed !== "" && decimal.test(trimmed) &&
      Number.isFinite(Number(trimmed));
  }

  field.addEventListener("input", () => {
    const value = field.value;
    feedback.textContent = value.trim() === ""
      ? "Enter a decimal number."
      : isDecimalNumber(value)
        ? "This value is ready to submit."
        : "Enter a signed decimal or exponent value.";
  });

  form.addEventListener("submit", event => {
    if (!isDecimalNumber(field.value)) {
      event.preventDefault();
      feedback.textContent = "Enter a valid decimal number before submitting.";
      field.focus();
    }
  });
</script>

input 处理程序会在每次编辑后检查字段当前的完整值;它不会过滤单个按键。字段为空时会显示提示,输入尚未完成时也可以显示临时引导信息。提交时会再次应用相同规则,并阻止不符合规则的值被发送。

不要单独验证用户准备输入的字符:用户可能会粘贴、删除、选取文本、使用辅助技术,或通过手机键盘输入。逐字符过滤也可能妨碍用户修正输入过程中暂时不完整的值。

临时反馈应与表单的最终判定区分开。小数在输入过程中可能暂时不完整,完成后却是有效值。提交时应验证最终字符串、显示清晰的提示,并在不符合所选规则时阻止提交。required、min、max 和 step 等原生 HTML 约束也能提供帮助,但对于需要信赖的数据,仍然需要服务器端验证。

测试边界情况并选择合适的方法

请根据表单要执行的确切规则检查有代表性的值。除非在模式中明确允许,否则只匹配数字的模式会拒绝 2.5、-2 和前后带空格的值。数字转换可以接受小数,但需要明确拒绝空文本,因为空白字符串转换后会得到零。即使表单不接受指数表示法,1e3 这样的值仍会转换为有限数。同样,转换本身不会强制要求正数或限制最大值。

文本格式很重要时使用正则表达式;数值含义很重要时使用数字转换并检查范围。无论选哪种方法,都要测试空输入、有效整数、允许的小数、正负号、尾随字母,以及与表单相关的边界值。将这些情况纳入应用测试,避免后续改动悄然扩大表单接受的输入范围。