刚才有个师兄问,说在JavaScript里要怎么用正则表达式来消除IPv4地址中每段的前导0。他原本是用parseInt+concat来做,觉得麻烦所以想试试正则表达式。输入的字符串保证是a.b.c.d这样的形式,其中a、b、c、d都是1-3位的数字。本来应该顺便验证一下是否满足0-255的范围的……算了。
想了一下,给了他这个:
/^0*(\d+\.)0*(\d+\.)0*(\d+\.)0*(\d+)$/
(编辑:呃,无视这个吧。我傻了,觉得应该要匹配IPv4里的那3个点('.')来保证输入的字符串的格式是正确的;不过在这个具体的场景其实前面的有别的程序已经保证了输入是正确的IPv4地址了,我这里没必要弄那么麻烦。
看帖子最后的那个……)
用法是例如:
function stripLeadingZeros(ip) {
var re = /^0*(\d+\.)0*(\d+\.)0*(\d+\.)0*(\d+)$/
return ip.replace(re, '$1$2$3$4')
}
///////////////////////////
ip = stripLeadingZeros('010.64.01.00') // 10.64.1.0
在IE7和Rhino 1.7R1里测了下都OK。
但是这个正则表达式貌似太麻烦了,师兄不肯用在他的production code里 T T
呜呜白写了。只好记在blog上了。
可恶的JavaScript标准,居然不支持/x选项,不然要是能给每节加上注释的话说不定就能通过 review了……
写得这么麻烦还是因为要处理整段都是0的状况。假如一段数字是0010,那用
/^(?:0*)(\d+)$/
就足以匹配和捕获了,捕获到的就是10。
但是如果整串数字都是0,要消除前导0就意味着要消除除了最后一个0之外的其它0。这就有点麻烦了。我能想到的最直观的办法就是照样用0*匹配前导0,然后在末尾看看是否到头了;如果到头了的话就强制让匹配位置后退一位。所以上面的正则表达式里每段匹配都加了一个顺序环视(?=\d)来做这个强制回退,变成0*(?=\d)。
这么一加整个表达式就变得好长……呜
[color=red](编辑:我的理解有误,这些正则表达式引擎都很聪明的会自动回溯,没有必要显式指定顺序环视的条件。
关键是在0
*后面跟的是\d
+,如果后面跟的是\d
*,则必须要手工的让匹配位置回退,也就是必须加上(?=\d)的顺序环视条件;不过后者很明显是多余的了。
*与+有显著的区别。*是Kleene Star,在集合论中没有是基本操作之一;+是一个简写方式,展开来就是(假如要匹配的元素是a,那么)aa*。
如果一个正则表达式里有两个连续的*,而它们要匹配的表达式所对应的集合如果有交集,那么后一个*所能匹配到的交集内的内容就一定会被前一个*所匹配。例如(0*)(d*)用于匹配000时,总是$1为000而$2为空。
但如果是(0*)(\d+),先展开为(0*)(\d\d*),就可以看到这里不存在连续的两个*,中间被一个固定长度的\d分隔开了。正则表达式引擎就会在遇到这个\d时自动决定是否需要回溯。
关注一下这个例子:
/^.*(\d+)/
在匹配"Copyright 2008."的时候,$1只是8,而不是2008。展开来看,/^.*(\d\d*)/中固定长度的\d只迫使.*回退了1个字符,然后整个正则表达式就满足匹配了,因而不会继续回退。)[/color]
==========================================================================
不过回头再想了想,既然这里都没验证0-255的范围,干脆连IPv4的格式也不验证算了。那样正则表达式就可以短很多,这样:
function stripLeadingZeros(str) {
return str.replace(/0*(\d+)/g, '$1')
}
///////////////////////////
ip = stripLeadingZeros('010.64.01.00') // 10.64.1.0
这个正则表达式:
/0*(\d+)/g
做的事情很简单,就是匹配输入字符串中任意连续的数字,并捕获前导0以外的部分到$1。
原理也很简单:
1、\d+可以匹配输入字符串中任意一串连续的数字;
2、任意一串连续的数字前面再加上一串0的话还是一串连续的数字;(涉及到+量词的贪婪性(匹配优先))
3、0*可以匹配任意一串连续的0或空串;
4、/0*(\d+)/匹配的是一串连续的0或空串,后面接上一串不为空并且不以0开头的数字;后面接的这串数字被捕获到第一个捕获分组中;
6、/g选项使得这个正则表达式匹配输入字符串中所有可能的匹配。
这里有把0*换成0+的诱惑,但改了之后:
/0+(\d+)/g
这个正则表达式就不能正确的将输入字符串中所有数字的前导0去除——不只是前导的0,它有可能匹配到位于数字中间的连续的0。
如果改成这样:
/0*(?=\d)/g
然后替换为空串,也无法满足要求。它会匹配到任意数字前的一个位置(零长度),也会匹配到任意一串连续的、后面还有数字的0。
前面的能正确消除前导0的正则表达式之所以正确,是因为那个表达式每次从整体来看总能匹配到最左最长的一串连续的数字,无论它是0开头(进入0*部分)还是其它数字开头(跳过0*直接进入\d+部分)。这样就能保证不会匹配到位于数字中间的连续的0。
同一个方法要是用Ruby写也一样:
def strip_leading_zeros(str)
str.gsub /0*(?=\d)/, '\1'
end
分享到:
相关推荐
IPV4地址大全,包含国内国外的IPV4地址,是我从我的mysql数据库导出的,可直接导入到mysql数据库中
全球IPv4地址分配情况,chm格式。网络安全人士必备。
IPv4地址知识.docx
IPv4 地址由十进制数和点来表示,每个地址包含4个十进制数,其范围为 0 - 255, 用(".")分割。比如,172.16.254.1;同时,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。 IPv6 地址由8组16...
网络原理是计算机的重要组成部分,而子网划分有所谓是重中之重,练习 6.7.3:IPv4 地址的子网划分 给你们练习
很详细的ipv4地址讲解,适合学网络的朋友。
这个C++程序将帮助你自动获取本机的ipv4地址。
IPv4地址转换工具 IPv6AddressConverter
公司妹子写的一个小程序(java),对ipv4的大网段进行拆分,拆成多个小网段。。。有需要的赏个分
IPV4地址配置和测试实验.pdf 学习资料 复习资料 教学资源
我们通常用前缀/XX的形式来表示IPv4地址,IPv4前缀和所表示的地址数量的对应关系介绍
批量ipv4/ipv6地址生成小工具
NAPT普遍应用于接入设备中,它可以将中小型的网络隐藏在一个合法的IP地址后面。 在Internet 中使用NAPT时,所有不同的信息流看起来好像来源于同一个IP地址。这个优点在小型办公室内非常实用,通过从ISP处申请的一个...
IPv4地址简介,介绍IP地址组成的PPT
中国IPv4地址应用状况研究
包含了IPv4地址的一些测例以及测试地址合法性的代码和测试程序 linux下执行gcc -o main main.c编译,./main IP.txt运行
二进制与十进制的互相转换 IPV4地址的划分,地址结构,五类地址 IP地址相关计算,如:计算IP的网段号,判断主机是否在同一网。 对于初学者来说还是很不错的
可以使用此工具更改你的ip地址,是手动还是自动,方便地址变更
it is used to make IPv4 -only to support IPv6 DNS64/NAT64 Networks./将只有ipv4的地址转换为ipv6支持地址
在CentOS中给Apache Tomcat绑定IPv4地址的教程.docx