小数点后保留2位小数的正则表达式
Write By Monkeyfly
以下内容均为原创,如需转载请注明出处。
前提
- 今天同事问我,这个正则表达式是什么意思?(如下所示)
^(([1-9]{1}\\d*)|([0]{1}))(\\.(\\d){0,2})?$
- 我说目前我也不知道它代表什么,那要看你的使用场景了,一时半会也看不出来,我得分析一下。
- 他说,要求保留两位小数。这是我网上百度的用法,你看一下对不对?
- 于是,我就去求证了。
分析
要看明白正则表达式,首先就要从语法层面进行分析,把每一部分都了解清楚,弄明白,必须知道每一部分匹配的是什么,随后整个表达式的意思也就迎刃而解了。
^(([1-9]{1}\\d*)|([0]{1}))(\\.(\\d){0,2})?$
(1)首先从写法上可以看出,使用了显式定义正则表达式的语法,因为其中存在对字符串"\"(反斜杠)
的转义。
-
普及一下:正则表达式的定义共有
2
种方式:显示定义
和隐式定义
。
/*\d是正则表达式中的元字符,用于匹配数字,相当于[0-9],所以[0-9]也可以写成\d*/
var myregex = new RegExp("[0-9]"); //显式定义
var myregex = /[0-9]/; //隐式定义
-
对两种定义方式的解释说明:
(2)其次,我们把正则表达式拆分开,以分组的形式来观察,问题就简单多了。因为复杂的正则表达式就是由许多子表达式构成的。
- 此处涉及到正则表达的
3
个知识点:定位符
、限定符
和分组
-
何谓定位符?
即限定某些字符出现的位置。
-
说明:
^
表示必须以什么字符开头;$
表示必须以什么字符结尾。
-
说明:
-
何谓限定符?
即限定某个字符或某类字符出现的次数。
-
说明:
-
*
表示重复0
次或更多次(任意次数); -
?
表示重复0
次或1
次(最多1
次); -
{n}
表示重复n
次; -
{n,m}
表示重复n-m
次;
-
-
说明:
-
何谓分组?
分组又称为子表达式,即把一个正则表达式的全部或部分分成一个或多个组。
-
语法:分组使用的字符为
“(”
和“)”
,即左括号和右括号。每一个子表达式都可以当做一个整体来处理。
-
语法:分组使用的字符为
-
何谓定位符?
- 拆分的步骤:
//初始
^(([1-9]{1}\\d*)|([0]{1}))(\\.(\\d){0,2})?$
//为了简化操作,方便观察,在这里把字符串的转义都去掉。
^(([1-9]{1}\d*)|([0]{1}))(\.(\d){0,2})?$
即:(([1-9]{1}\d*)|([0]{1}))(\.(\d){0,2})
//第一步:先分组,不管定位符和限定符。总共可分为两大组。
(([1-9]{1}\d*)|([0]{1}))//第一大组:整数部分
(\.(\d){0,2})//第二大组:小数部分
//第二步:继续分组,将第一大组(整数部分)继续拆分,可分为3部分。
([1-9]{1}\d*)//第一部分
| //第二部分
([0]{1})//第三部分
知识点说明: [...]
是正则表达式中的元字符
。它会匹配方括号中的所有字符。
|
是正则表达式中的选择符
。简单来说就是:用于二选一
。即选择2个选项之中的任意一个,选他或选她。
第二步分析:
因此,在第二步中,第一部分和第三部分的子表达式,这两部分只要满足任何一个部分都可以匹配的上。
注:这也就说明了整数部分的两种情况:首位是0
和首位不是0
。即0.12
、13.14
、5.21
- 先来看第一部分中的内容,即第一种情况,首位不为
0
:([1-9]{1}\d*)
- 可以看出,第一部分由两个模块组成,即
[1-9]{1}
和\d*
。
(1)[1-9]{1}
表示1-9
之间的数字只出现一次,即保证了该数的首位不是0
,总之是大于0
的数。
(2)\d*
表示0-9
之间的数字可以出现任意次,即0
次或更多次。出现0
次说明是一位整数。出现更多次就是多位整数。
- 可以看出,第一部分由两个模块组成,即
- 再来看第三部分中的内容,即第二种情况,首位为
0
:([0]{1})
【一个字符没必要使用[
元字符,直接写0
就行,即(0{1})
】- 这个就比较简单了,表示数字
0
只能出现一次,即首位只能是0
,而且只能有一个0
。
- 这个就比较简单了,表示数字
总结:第一大组匹配了整数部分的情况,大于0的数还是小于1的数
。
(\.(\d){0,2})//第二大组:小数部分
//第三步:继续分组,将第二大组(小数部分)继续拆分,可分为3部分。
\. //第一部分
(\d) //第二部分
{0,2} //第三部分
知识点说明: .(点)
是正则表达式中的元字符
。它会匹配除了换行符以外的任意字符
。
注:由于.(点)
是元字符,所以,如果想要匹配字面意义上的点时(此处需要匹配小数点),需要使用转义字符\(反斜杠)
将它进行转义,即\.
。
第三步分析:
- 第一部分:
\.
表示匹配小数点。 - 第二部分:
(\d)
表示匹配数字0-9
。【此处可以不用分组符,用了多此一举】 - 第三部分:
{0,2}
表示将前面的字符重复0-2
次,即重复的次数不确定,可能重复0
次,可能重复1
次,也可能重复2
次。 - 其实,二三部分应该放在一块分析,即
\d{0,2}
,表示:0
个数字、1
个数字或者2
个数字。
总结:第二大组匹配了小数点后所保留的位数
,分别是小数点后保留0
位小数(即正整数)、小数点后保留1
位小数或者小数点后保留2
位小数。
注:如果要匹配小数点后保留2
位小数,则只需要改一下限定符即可。\.\d{2}
至此为止,我们已经将正则表达式拆分完毕,现在就需要将它们完整的分析一下。
(([1-9]{1}\d*)|(0{1}))(\.\d{0,2})
- 完整分析:
/*1、先加上限定符?(问号)【它表示前面紧跟的字符,即(\.\d{0,2})这个整体,重复0次或1次(最多1次)】*/
(([1-9]{1}\d*)|(0{1}))(\.\d{0,2})?
//如果(\.\d{0,2})不存在,表示该数为自然数(指非负整数,即正整数与0的集合),无小数部分。
//如果(\.\d{0,2})存在,表示该数为小数。
/*如果是小数的话,按照大小来分,存在两种情况:
**(1)可能是大于0的小数;即([1-9]{1}\d*)
**(2)也可能是小于1的小数;即(0{1})
*/
/*如果是小数的话,按照位数来分,存在3种情况:
**(1)无小数位数,为整数;即(\.\d{0,2})重复0次,相当于没有它
**(2)有小数位数,为小数;即(\.\d{0,2})重复1次
** 小数的位数又分为三种情况:{0,2}相当于是{0},{1},{2}的集合,它们之间是“或”的关系
** 小数点后保留0位小数;即\.\d{0}
** 小数点后保留1位小数;即\.\d{1}
** 小数点后保留2位小数;即\.\d{2}
*/
在这里普及一下整数的知识:
我们以0
为界限,将整数分为3
大类:
- 正整数。即大于
0
的整数,如:1,2,3,…
-
0
。0
既不是正整数,也不是负整数(0
是整数)。 - 负整数。即小于
0
的整数,如:-1,-2,-3,…
/*2、最后再加上限定开始和结束位置的限定符,^和$。*/
^(([1-9]{1}\d*)|(0{1}))(\.\d{0,2})?$
//这就表示了,它必须以数字开头和结尾。限定了它必须是一个数字,而不能包含其他的字符。
结果
^(([1-9]{1}\d*)|(0{1}))(\.\d{0,2})?$
就表示了小数点后可以保留0
位、1
位、或2
位小数。
如果我们要求小数点后只能保留2位小数
,则修改表示小数点后面数字的重复次数(即位数)
的限定符{}
,直接将{0,2}
改为{2}
,然后去掉限定符?
即可。去掉了 ? 就代表该数不可能是整数,一定是小数。
最终的正则表达式:^(([1-9]{1}\d*)|(0{1}))(\.\d{2})$
测试过程:
如下图所示
隐式定义:↓
显式定义:↑
上一篇: IEEE754浮点数格式详解