2 个回答

这样?

^(?>[1-9]\d*|0\.\d*|\D+)+$

不支持(?>...)的话,(?:...)应该也可以,就是慢些

可以先匹配非法的再取反((?<!regex) 用法见 正则表达式预查的解释与应用

!/(^|[^\d.])0\d/.test(s)
// 使用预查
!/(?<![\d.])0\d/.test(s)

不取反,可改为

/^(?!.*(?<![\d.])0\d).*$/.test(s)

不使用预查,可分步匹配

// 匹配合法的
s.match(/\d+(?:\.\d+)?/g)?.every(d => /^(?:0|[1-9]\d*)(?:\.\d+)?$/.test(d)) ?? true
// 匹配非法的
!s.match(/\d+(?:\.\d+)?/g)?.some(d => /^0\d/.test(d))

非要写成一个正则且匹配合法的,要防止一个数字被分成多段匹配,如 00 是非法的,但分成 0 0 会变成合法的,1.01 是合法的,但分成 1 . 01 会变成非法的

几个正确写法参考:

// (?!\d) 使得下次不匹配数字,防止了连续两次匹配数字
/^(?:(?:0|[1-9]\d*)(?:\.\d+)?(?!\d)|\D+)*$/.test(s)
// 不使用预查,修改字符串总以非数字开头,使得正则容易编写
/^(?:\D+(?:(?:0|[1-9]\d*)(?:\.\d+)?)?)*$/.test('a' + s)
// 不使用预查,不修改字符串
/^(?:(?:^|(?:0|[1-9]\d*)(?:\.\d+)?)(?:\D+|$))*$/.test(s)

测试用例

[
  // true
  '0',
  '1',
  '10',
  '0.1',
  '0.01',
  '1.01',
  '100.00',
  '',
  '我',
  '1.0我0.1a1.01',

  // false
  '00',
  '01',
  '010',
  '00.1',
  '00.01',
  '01.01',
  '00.00',
  '10我01a101',
].forEach(s => console.log(s,
  /^(?:(?:0|[1-9]\d*)(?:\.\d+)?(?!\d)|\D+)*$/.test(s)
))
推荐问题