`
RednaxelaFX
  • 浏览: 3049374 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

消除一个IPv4地址中每段的前导0

阅读更多
刚才有个师兄问,说在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

分享到:
评论
2 楼 RednaxelaFX 2008-12-30  
cajon 写道

呵呵,路过...

啊,Colin老大 T T
最近都在忙些什么呢?Blog那边好像11月下半开始都没更新过了……Gendarme有没有试用过?
1 楼 cajon 2008-12-30  
呵呵,路过...

相关推荐

    IPV4地址大全(国内国外)(mysql存储文件)

    IPV4地址大全,包含国内国外的IPV4地址,是我从我的mysql数据库导出的,可直接导入到mysql数据库中

    获取本机的IPV4地址

    IPv4地址是一个32位的二进制数,通常以点分十进制的形式表示,如192.168.1.1。它由网络部分和主机部分组成,用于在网络中唯一标识一台设备。 要获取本机的IPv4地址,我们通常需要利用操作系统提供的API,比如在...

    IPV4大网段拆分为多个均分子网段

    总的来说,"IPV4大网段拆分为多个均分子网段"是一个涉及网络地址规划和Java编程的问题。理解子网划分的概念和计算方法,以及如何在Java中实现这些计算,对于任何IT专业人士,尤其是网络管理员和软件开发者来说,都是...

    练习 6.7.3:IPv4 地址的子网划分

    在IPv4地址系统中,子网划分允许我们将一个大的IP地址空间分割成若干个更小、独立的子网,以更好地管理和控制网络流量。下面将详细解释这个练习中涉及的子网划分知识。 首先,我们要理解IP地址的结构。一个IPv4地址...

    IPv4地址知识.docx

    - **说明**:这是一个A类私有地址,通常用于大型企业或组织内部的局域网。 通过对以上知识点的学习和理解,我们可以更好地管理和配置网络环境中的设备,并有效地利用有限的IP地址资源。例如,在实际应用中,合理...

    全球IPv4地址分配库

    全球IPv4地址分配情况,chm格式。网络安全人士必备。

    编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址

    IPv4 地址由十进制数和点来表示,每个地址包含4个十进制数,其范围为 0 - 255, 用(".")分割。比如,172.16.254.1;同时,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。 IPv6 地址由8组16...

    IPV4地址配置和测试实验.pdf

    5. 对 IP 地址进行改变,三台机器为一个组,对计算机的 IP 地址进行改变。 实验结果: 1. 使用网络测试命令,确定每台计算机的网络配置正确。 2. 同组的计算机测试是否连通?于其它组的计算机测试连同情况。 3. ...

    cpp-将只有ipv4的地址转换为ipv6支持地址

    在当前的互联网环境中,IPv4地址的枯竭已经成为一个不可忽视的问题。为了应对这一挑战,IPv6被引入作为IPv4的替代方案,它提供了更大的地址空间。然而,由于IPv4和IPv6不兼容,直接的通信是无法实现的。在这种背景下...

    IPv4地址相关计算ppt

    IPv4地址是一个32位的二进制数字,通常被分为四部分,每部分8位,中间用点分隔,这种形式被称为点分十进制表示法。例如,192.168.1.1是一个典型的IPv4地址。 二进制与十进制之间的转换是理解和处理IPv4地址的基础。...

    IPV4地址合法性鉴别

    首先,一个有效的IPV4地址必须满足以下条件: 1. 地址由四个十进制数字组成,每个数字介于0和255之间。 2. 每个十进制数字之间用点(.)分隔。 3. 地址中不能包含额外的空格或其他非数字字符。 在Linux环境中,我们...

    ensp实验:ipv6 over ipv4

    IPv6 over IPv4隧道的工作原理是将IPv6的数据包封装在一个IPv4的数据包中,然后通过IPv4网络进行传输。在隧道的两端,这些封装的IPv6数据包会被解封装,恢复成原始的IPv6数据包,从而实现IPv6流量在IPv4网络中的传输...

    Ch4_IPv4地址1

    在IPv4地址中,子网掩码是一个非常重要的概念。子网掩码是用于确定IP地址的网络部分和主机部分的。子网掩码是一个32位的二进制数,用于与IP地址进行逻辑AND运算,以确定网络ID和主机ID。 此外,IPv4地址还存在一些...

    高级网络管理-IPv4地址详细讲解

    很详细的ipv4地址讲解,适合学网络的朋友。

    IPV4地址超全详解.doc

    IPV4 地址是给在因特网上的每一台主机的每一个接口分配一个在全世界范围内是唯一的 32 比特的标识符。一个 IPV4 地址由 32 位比特数字组成,为方便记忆,每 8 位为一组转换为 10 进制数字,用 "." 隔开,共分为 4 组...

    IPv4地址1

    一个IPv4地址由四个部分组成,每个部分称为octet,每个octet以点分十进制形式表示,范围从0到255。例如,IP地址172.16.31.10可以分解为四个octet:172、16、31和10。 IPv4地址的分类 IPv4地址可以分为五类,每类都...

    IPv4地址转换工具

    IPv4地址转换工具 IPv6AddressConverter

    获取本机IP的小案例,可以获取Ipv4的IP地址

    总的来说,掌握如何在C#中获取本机IP地址是一项基础但重要的技能,这个小案例提供了一个清晰的起点,让开发者能够进一步探索和扩展网络编程的知识领域。通过实践这个案例,你可以更好地理解网络接口、IP地址以及如何...

    批量ipv4/ipv6地址生成小工具

    批量ipv4/ipv6地址生成小工具

    双击一键获取本机IP地址(IPv4地址)bat文件,批处理

    双击一键获取本机IP地址(IPv4地址)

Global site tag (gtag.js) - Google Analytics