set ip 10.10.
if {[regexp
{^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.?){4}$} $ip
match]} { puts $match }
以上模式匹配10.10.
任何人都可以告诉我这是怎么发生的
答案 0 :(得分:4)
首先,使用正则表达式来检查IP地址非常脆弱且不必要地复杂,您仍然需要自己进行繁重的工作。相反,请使用Tcllib_ip包。
package require ip
如果您想知道给定的字符串是否是IPv4地址,请查看
::ip::is 4 $str ;# 1 if valid ipv4, 0 otherwise
或
::ip::version $str ;# returns 4 or 6 for ipv4 or ipv6, -1 otherwise
包中的命令也处理非点分十进制的地址字符串。
该软件包未包含在所有发行版中,但可以使用teacup install
安装,也可以下载文件并将其发送到脚本中。
回答这个问题:原始提问者有一个错误和一个问题。错误是用于匹配ip地址的正则表达式也匹配不是ip地址的字符串。这是使用正则表达式时最常见的问题之一。在问题的其他答案中解决了原因和解决方法。回顾一下:船长注意到由于原始正则表达式使点可选,因此字符串10.10.
可以匹配为1 0. 1 0.
。有几种可能的解决方案:{^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.|$)){4}$}
由同一船长建议似乎有效,但如果经过测试可能会产生更多问题。
主要问题是使用非平凡的正则表达式来匹配地址。除了最琐碎的正则表达式之外,必须进行严格的测试以确保它们不会产生误报。 这种测试通常是不切实际的,无法做出详尽的,这意味着在愤怒的客户告诉你不这样做之前,你无法确定它是否有效。当找到一个误报匹配的情况时,解决方案是删除正则表达式并尝试另一种方法,或者使正则表达式更复杂以使匹配更严格。此时,测试套件也可能需要增长。
更好的方法是退一步寻找其他解决方案。如果有标准库函数,则应使用该函数。如果我们想象在这种情况下没有,只需反映ipv4十进制地址的最基本公式(“从0到255的四组整数,由点连接”)表明一些简单而安全的函数:
proc isOctet n {
expr {[string is integer -strict $n] && 0 <= $n && $n <= 255}
}
proc splitIpv4dd1 str {
split $str .
}
proc splitIpv4dd2 str {
scan $str %d.%d.%d.%d
}
proc splitIpv4dd3 str {
lrange [regexp -inline {^(\d+)\.(\d+)\.(\d+)\.(\d+)$} $str] 1 end
}
# plug any of the preceding splitIpv4ddN functions into this command
proc putsIpv4dd str {
set count 0
foreach n [splitIpv4dd1 $str] {
if {[isOctet $n]} {
incr count
}
}
if {$count == 4} {puts $str}
}
更容易验证这些函数中的每一个是否正确地执行其工作而没有错误否定或肯定,如果这样做,则可以假定打印ip地址的命令正常工作。第三个拆分函数使用正则表达式,但在这种情况下,它是一个简单的,没有替代和可选原子。
编写健壮且可维护的代码时,一个重要的目标是保持功能的内聚和清晰,没有漏洞或不规则。与非平凡的正则表达式匹配与此相反。
我当然理解并且实际上赞赏了解错误的愿望,但是从中得出的正确结论是匹配的正则表达式不适合在这种情况下使用。< / p>
答案 1 :(得分:0)
要回答“这是怎么回事” - “。”可选,它会找到1
,0.
,1
,0.
未解决问题的答案
如果它是字符串的末尾(修改为确保没有尾随点),下面的表达式将使点成为可选:
^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.(?=[0-9])|$)){4}$
请记住原始问题是“这是怎么回事” - 即了解正则表达式行为...... 没什么关于如何更改正则表达式或如何应该这样做......
答案 2 :(得分:0)
您可以尝试使用此正则表达式:
^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$