TCL RegExp IP例外

时间:2016-06-10 22:37:52

标签: tcl

我有以下TCl regexp从一行中提取确切的IP:

set ip [regexp -all -inline {((([2][5][0-5]|([2][0-4]|[1][0-9]|[0-9])?[0-9])\.){3})([2][5][0-5]|([2][0-4]|[1][0-9]|[0-9])?[0-9])} $ip_text]

我正在使用它来分析日志文件,它工作正常,除了当域名还包含IP格式(但通常是反向)时它还提取域名IP部分,我不想't

例如ip_text = Log File 61.140.142.192 - 2012-06-16, 192.142.140.61.broad.gz.gd.dynamic.163data.com.cn, CHN, 1

我得到61.140.142.192& 192.142.140.61但仅 61.140.142.192 是合法的。

以及ip_text = Entry "61.140.170.118" resolved from 118.170.140.61.broad.gz.gd.dynamic.163data.com.cn, and 61.140.185.45 verified.

我得到61.140.170.118,118.170.140.61& 164.111.111.34但仅 61.140.170.118 & 61.140.185.45 是合法的。

有没有办法让regexpr排除其后有域名字符的IP?即排除<IP><dot><IP><dash><IP><any alpha/numeric character>

2 个答案:

答案 0 :(得分:4)

您可以在该RE的末尾使用负前瞻约束。在这种情况下,它们被写为(?!\.|\d),当下一个字符 a .或数字时它匹配(它也匹配字符串的末尾,当时有根本没有下一个角色。使用复杂的正则表达式,通常更容易将它们保存在变量(通常是全局变量)中,因为这样可以有效地命名RE。

set IPAddrRE {(((25[0-5]|(2[0-4]|1[0-9]|[1-9])?[0-9])\.){3})(25[0-5]|(2[0-4]|1[0-9]|[1-9])?[0-9])(?!\.|\d)}
set ip [regexp -all -inline $IPAddrRE $ip_text]

您需要阻止关注者成为数字的原因?如果没有它,RE可以提前停止匹配一个字符,允许它从您的示例文本中选择192.142.140.6以及您实际想要的值。

您应该考虑对此任务使用非捕获分组。用(…)替换(?:…)将允许RE引擎在内部使用更高效的匹配器。在很多文本中,这将产生重大影响。例如,使用此版本:

set IPAddrRE {(?:(?:25[0-5]|(?:2[0-4]|1[0-9]|[1-9])?[0-9])\.){3}(?:25[0-5]|(?:2[0-4]|1[0-9]|[1-9])?[0-9])(?!\.|\d)}

我发现执行的时间大约是我在本答案第一部分中列出的版本的一半(并且大约是原始版本所需版本的40%)。但是,它会产生不同的结果 - 您可能不需要的任何位 - 所以您还需要调整其他代码:

% set ip [regexp -all -inline $IPAddrRE $ip_text]
61.140.142.192

答案 1 :(得分:2)

将正则表达式愚蠢而不是试图让它们变得更聪明,这通常是一个好主意。

lmap candidate [regexp -inline -all {[\d.]+} $txt] {
    if {[llength [split $candidate .]] == 4} {
        set candidate
    } else {
        continue
    }
}

将从您的文字中挑选出您想要的三个数字。

文档:continueifllengthlmaplmap替代,Syntax of Tcl regular expressionsregexp,{{ 3}},set