js 正则 真的是个坑~~~求大佬帮忙

大于0 小于等于1 小数点限制6位

就这样的一个正则
写了一个小时 没写明白 感觉做前端好难啊
求大佬帮忙指点

阅读 3.9k
7 个回答

忙活了一个小时,也是没能完全写出来。下面以供参考。

一、关于题目

感觉提问描述感觉不够清晰。既然你之前尝试了一个小时,其实可以将试验的结果作为问题扩展以供大家参考,从而更加了解你想实现的结果。

毕竟打字成本不高,详细描述清楚有助于其他人帮你。

二、思路

我的正则水平也是非常一般,所以只能逐步分解任务:

  1. 大于 0,则找出以 0 开头的 1 到 6 位数字 ^0\.(\d{1,6})$
  2. 等于 1,可能为 1, 1.0 甚至为 1.,所以使用 ^[1][\.]0{0,6}$|^1$

组合起来就是

let answer = (str) => {
  let reg = /(^0\.(\d{1,6})$)|(^[1][\.]0{0,6}$|^1$)/g
  return reg.test(str)
}

module.exports = answer

跑一下测试:

let answer = require('./index')
// 符合要求
let accept = ['0.1', '0.000001', '0.010', '0.001', '1', '1.', '1.0', '1.000000', '0.999999']
// 不符合要求
let reject = ['0', '1.1', '1.01', '1.000001', '1.0000000', '2']
// 本应该不符合要求
let weird = ['0.0', '0.000000']

accept.forEach((v) => {
  test(`符合要求 ${v}`, () => {
    expect(answer(v)).toEqual(true)
  })
})

reject.forEach((v) => {
  test(`不符合要求 ${v}`, () => {
    expect(answer(v)).toEqual(false)
  })
})

weird.forEach((v) => {
  test(`本应该不符合要求 ${v}`, () => {
    expect(answer(v)).toEqual(false)
  })
})

结果为:

clipboard.png

所以,对类似 0.00.000000 这种"等于" 0 的,我的正则也没能将其排除在外。

结语

如果硬性要求完全使用正则实现这个判断,测试反映出上面的正则还是存在缺陷

如果只是单纯实现一个判断需求,上面的正则通过配合其他判断也能实现结果。

当如,倘若并非硬性要求正则实现。完全可以对字符串进行截取、预处理等或者配合正则校验,这样更加简单。

提供一个在线小工具 regexr,如果不太了解正则语法,这个可视化正则工具可以看出每一步的实现。

另外,正则并不是一个坑,在不恰当的场景使用正则才是一个坑。

这段时间待业在家,写了一些关于前端的文章,发布在个人公众号「前后端面试题带答案」,欢迎交流。

clipboard.png

不要求长度一定要小于等于6的话,可以用这个:(^1(\.0*)?$)|(^0\.(\d*[1-9]\d*)$)

run in console

[["0.1", true],
["0.000001", true],
["0.010", true],
["0.001", true],
["1", true],
["1.", true],
["1.0", true],
["1.000000", true],
["0.999999", true],
["0.18273981723981273", true],
["0.182739", true],
["0.12", true],
["0", false],
["1.1", false],
["1.01", false],
["1.000001", false],
["2", false],
["0.", false],
["0.0", false],
["0.000111", true],
["0.1001", true],
["0.000000", false]].map(t=>/(^1(\.0*)?$)|(^0\.(\d*[1-9]\d*)$)/m.test(t[0]) === t[1])

一般这种既要求混合模式,有要求定长的正则自己做起来比较难,因为不
可以给混合模式限定重复次数的同时,又给整个匹配限定长度。

所以一般都是一个正则匹配一种要求,多个正则和其他的逻辑联合行动。

比如上面的正则配合.length <= 8

来了老弟,不知道00000 00001 1. 0. 这些你要的结果,我处理为true

demo(0) // true
demo(0.1) // true
demo(0.123456) // true
demo(1) // true
demo('1.000000') // => true
demo('1.')// => true
demo('0.')// => true
demo('000000000')// => true
demo('000000001')// => true
demo('000000001.')// => true
demo('000000001.0')// => true
demo('000.999999')// => true
demo('000000001.1')// => false
demo('1.0000000')// => false
demo(0.1234567) // false
demo('00010000')// => false

function demo (num) {
  let str = String(num)
  let res = /^\+?((0+((\.?&)|(\.[0-9]{0,6})?$))|(0*1((\.?$)|(\.0{1,6})?$)))/.test(str)
  console.log(str, res)
  return res
}

我的建议是与其绞尽脑汁写出一个可能还不能完全匹配成功的正则
,还不如直接转换为数字后比较大小来得简单粗暴:

function isNumeric(str) {
    var num = parseFloat(str);
    return num == str && num > 0 && num <= 1 && str.length <= 8;
}
console.log(isNumeric("0"));
console.log(isNumeric("1"));

正则表达式的断言语法!

  • 等于 0

    • 用断言排除 00.^(?!0[.]{0,1}$)
    • 用断言排除 0.0 ~ 0.000000^(?!0\.[0]{1,6}$)
  • 大于 0 小于 1

    • ^0\.[0-9]{0,6}$
  • 等于 1

    • ^1$
    • ^1\.[0]{0,6}$

组合一下,得到结果:

^(?!0[.]{0,1}$)(?!0\.[0]{1,6}$)0\.[0-9]{0,6}$|^1$|^1\.[0]{0,6}$

/^(?!0+(\.0+)?$)\d+(\.\d{1,6})?$/

讲一下思路:
1、先确定一个整体的结构\d+(\.\d{1,6})?:意思就是前面是一个以上的数字,后面如果有小数点就加上1-6个数字(是否0-6需求),没有就算了
2、上面大框架定下了,然后我们需要排除全是0的情况,即:0、000、00.000。使用正向否定预查?!排除从开头到结尾全是0的情况^(?!0+(\.0+)?$)
3、组合一下,就是上面的正则:这个正则是允许前面有多个零的:0001.123

谢谢 大佬们 问题 我已经干掉了 结合了 正则 自定义验证两种 谢谢大佬们 下次 我会把问题 尽量描述清楚 及时回复大家 谢谢

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题