ipv6地址的正则表达式

时间:2016-11-25 09:12:13

标签: regex tcl regex-greedy

我有一个itcl文件,我的正则表达式正在为ipv4地址正确选择,但同样不适用于ipv6地址。

我的表达为:

REGEXP [^:]+://[^:/]+(:[0-9]+)?/?  

正在正确阅读以下内容:

https://10.77.56.89

但同样我想做的事情如下:

https://[2001:1:1:43::115]/ucmuser显示的格式不正确。

2 个答案:

答案 0 :(得分:1)

问题是你的正则表达式并不考虑IPv6数字地址(不是我首先建议使用它们;使用DNS将它们绑定到一个地方是明智的生产中使用的名称)。

为了检查事情是如何失败的,让我们稍微调整RE以获得更多信息:

([^:]+)://([^:/]+)(:[0-9]+)?(/?)

在此版本中,捕获了未完全修复的所有内容。现在让我们使用regexp -inline对您的用例进行测试(-inline选项使regexp返回匹配的子字符串,很好用于调试RE ,将RE放在变量中并使用如下所示,这样可以更容易避免拼写错误):

% set RE {([^:]+)://([^:/]+)(:[0-9]+)?(/?)}
([^:]+)://([^:/]+)(:[0-9]+)?(/?)
% regexp -inline $RE {https://10.77.56.89}
https://10.77.56.89 https 10.77.56.89 {} {}
% regexp -inline $RE {https://[2001:1:1:43::115]/ucmuser}
{https://[2001:1} https {[2001} :1 {}

我们看到[^:]+部分是问题,因为它停在IPv6地址的第一个冒号处。当主机名的第一部分以[开头时,我们需要添加一个特例;我们不会做完全验证(如果你想要的话,请检查Tcllib中的ip包)但我们可以通过检查括号内容是十六进制数字还是冒号来做一些简单的事情。

% set RE {([^:]+)://([^]:[/]+|\[[0-9a-f:A-F]+\])(:[0-9]+)?(/?)}
([^:]+)://([^]:[/]+|\[[0-9a-f:A-F]+\])(:[0-9]+)?(/?)
% regexp -inline $RE {https://10.77.56.89}
https://10.77.56.89 https 10.77.56.89 {} {}
% regexp -inline $RE {https://[2001:1:1:43::115]/ucmuser}
{https://[2001:1:1:43::115]/} https {[2001:1:1:43::115]} {} /

这对我来说是正确的(是的,由于与POSIX RE字符类的语法交互,因此需要稍微修改一下以获得正确的语法)。转换为拥有您最初拥有的相同捕获组,您的RE应为:

[^:]+://(?:[^]:[/]+|\[[0-9a-f:A-F]+\])(:[0-9]+)?/?

(注意:我们正在使用非捕获括号(?: ... ),因为我们需要在两个子RE之间进行交替|。)

答案 1 :(得分:0)

更宽松的变体:

% package require ip
1.3
% set addr1 https://10.77.56.89
https://10.77.56.89
% set addr2 {https://[2001:1:1:43::115]/ucmuser}
https://[2001:1:1:43::115]/ucmuser

以最简单的方式从地址获取IP号码*:

% set ip1 [regexp -inline {\d.*\d} $addr1]
10.77.56.89
% set ip2 [regexp -inline {\d.*\d} $addr2]
2001:1:1:43::115

然后验证它们:

% ::ip::version $ip1
4
% ::ip::version $ip2
6

*)此方法仅用于说明目的,肯定不适用于所有网址。原则是从一个非常简单的提取方法开始,如果有效地提取有效的ip数并拒绝,则逐步优化方法,直到它变得复杂,因为它需要,而不是更多。

E.g。如果我们得到这样的网址:

set addr3 http://127.0.0.1/a/b/c/1

上述方法将匹配最后一位数字。但是,通过稍微改进来解决这个问题很容易:

% set ip3 [regexp -inline {\d[^/]*\d} $addr3]
127.0.0.1

等等。

它不一定是regexp操作:

set ipX [string trim [lindex [split $addrX /] 2] \[]]

适用于此处提及的所有网址。

文档: ip (package)lindexpackagesetsplitstringregexp