我有以下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>
答案 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)