从一个数字输入框限制符号输入开始到正则入门

506 阅读3分钟

背景

数字输入框限制其它符号的输入是一个很常见的需求,但是网上的实现方案始终离理想状态差那么一丢丢,大多会遇到两个坑,一个是 type=number不能过滤加减符号,另外一个点就是如果需要能够输入小数时,如何限制首位禁止输入多个0,并且能够正确的过滤保留位数

本篇就带大家一起一步一步,通过实现这个需求,到最终掌握各项基础的正则小知识

思路

首先我们来对两个难点进行分析看看如何解决

能不能使用 type = number

如果你的需求要求输入时限制用户把加减符号输入进去,那么答案是肯定的,不能

通常我们在实现输入限制时会配合 input 事件对输入进行实时处理,如果使用 type=number ,那么遇到诸如 +,- 之类的运算符号时,事件结果会直接返回空,这样会导致我们的正则匹配失效,所以实现这个需求的第一步,我们需要把 input 上的类型属性设置为 text,以 element-ui 为例

<el-input v-model="number" type="text"></el-input>

各种需求情况下正则怎么写

这里可以先按几种简单的类型来实现,最后组装为我们想要的结果,大家也可以按自己的需求进行魔改,我们的代码逻辑大概是这个样子

<el-input v-model="number" type="text" @input="handleInput"></el-input>
​
const number = ref()
​
const handleInput = (value) => {
    // 用来匹配的正则
    const reg = /{期望正则}/g
    // input 变量保存替换结果
    let input = value.replace(reg,'')
    // 将替换结果赋值给绑定对象
    number.value = input
}

只允许输入正整数

不允许输入0以及运算符号,eg: +,-,.

使用 \D 匹配非数字

使用 ^0 匹配首位的0

const handleInput = (value) => {
    // 匹配非数字清除
    const reg = /\D|^0/g
    let input = value.replace(reg,'')
    number.value = input
}

只允许输入整数

允许输入0,但开头不可以输入连续0,eg: 012

使用 \D 匹配非数字

使用 /^0+(\d)/ 匹配开头的连续0,并获取0后第一个数字用于替换0

const handleInput = (value) => {
    // 匹配非数字清除
    const reg = /\D/g
    let input = value.replace(reg,'')
    // 匹配开头的连续0,用第一个数字替换
    const reg1 = /^0+(\d)/
    input = input.replace(reg1, '$1')
    number.value = input
}

允许输入小数

同样不允许输入各种加减号,这里主要是首位和连续的小数点需要处理

  • 使用 [^\d.]|^. 匹配非数字和小数点之外的输入,并且首位不能是小数点

[] 中括号表示匹配字符类

^ 在字符类中表示取反(注意这里第一个^就不是取首位了)

\d. 表示匹配数字和小数点

const reg = /[^\d.]|^./g
let input = value.replace(reg,'')
  • 如果输入多个小数点,只保留第一个

这里借鉴一下网上的一些思路,总结来说就3步

第一步,匹配到第一个小数点,进行特殊字符的替换(这里用 $#$

input = input.replace('.', '$#$')

第二步,匹配其余所有小数点,进行删除

input = input.replace(/./g, '')

第三步,把第一步的$#$还原成小数点

input = input.replace('$#$', '.')

三步合并下

input = input.replace('.', '$#$').replace(/./g, '').replace('$#$', '.')

最终结果(加上之前的不可输入连续0)

const handleInput = (value: any) => {
    const reg = /[^\d.]|^./g
    let input = value.replace(reg,'')
    input = input.replace('.', '$#$').replace(/./g, '').replace('$#$', '.')
    const reg1 = /^0+(\d)/
    input = input.replace(reg1, '$1')
    number.value = input
}

只允许输入指定精度的数字(这里以2位为例)

到这里已经很明朗了,只需要在上面的基础上稍加修改即可

思路是对小数点两侧进行分组匹配在将结果返回

第一步,匹配小数点左侧 ^(\d+)

第二步,匹配小数点 .

第三步,匹配小数点右侧 (\d\d) (如果更多位,增加\d即可)

第四步,.*$对余下字符进行匹配,最后使用$1, $2取到分组结果进行组合替换

合并下

const reg3 = /^(\d+).(\d\d).*$/
input = input.replace(reg3, '$1.$2')

最终结果

const handleInput = (value: any) => {
    const reg = /[^\d.]|^./g
    let input = value.replace(reg,'')
    input = input.replace('.', '$#$').replace(/./g, '').replace('$#$', '.')
    const reg2 = /^0+(\d)/
    input = input.replace(reg2, '$1')
    const reg3 = /^(\d+).(\d\d).*$/
    input = input.replace(reg3, '$1.$2')
    number.value = input
}

小结

看到这,相信你对输入框的限制输入需求如何实现已经有了大体的思路,也对各种常见的正则匹配小技巧有所了解了,简单梳理下

  • \d 匹配数字
  • \D 匹配非数字
  • ^ 标记第一个
  • + 匹配多个
  • [] 匹配字符串中的某一类字符
  • () 对匹配结果分组,可以使用 $ 符号获取匹配结果
  • .*$ 匹配余下所有

希望大家看完都能好好消化消化,相信不管对完成这个需求,还是加深对正则的理解,都会有所帮助的^_^