如何打印在TCL变量中多次出现的单词(URL名称)?

时间:2014-07-24 17:46:17

标签: regex excel tcl

以下是我的TCL脚本:

set line { 
Jul 24 21:06:40 2014: %AUTH-6-INFO: login[1765]: user 'admin' on 'pts/1' logged
Jul 24 21:05:15 2014: %DATAPLANE-5-: Unrecognized HTTP URL www.58.net. Flow: 0x2
Jul 24 21:04:39 2014: %DATAPLANE-5-: Unrecognized HTTP URL static.58.com. Flow:
Jul 24 21:04:38 2014: %DATAPLANE-5-: Unrecognized HTTP URL www.google-analytics.
com. Flow: 0x2265394048.
Jul 24 21:04:36 2014: %DATAPLANE-5-: Unrecognized HTTP URL track.58.co.in. Flow: 0
}




if {[regexp -all {Unrecognized HTTP URL ([a-z0-9.]*) Flow} $line junk one]} {
puts $one
}

使用上面的TCL脚本,我想grep“$ line”变量中的URL名称。现在我只能grep显示在末尾的URL名称(track.58.co.in。)。如何使用TCL正则表达式grep所有URL名称。

此外,我还想将这些grepped URL名称导出到Microsoft Excel文件。如何做到这一点?请帮我解决你的想法。

谢谢,

Balu P。

2 个答案:

答案 0 :(得分:3)

(我的老答案有点漫无边际,为了改变而有点改变,这个有点好。请注意,我的答案现在与格伦杰克曼的答案非常相似。但是,还有一些微妙的差异。由于答案被接受了,我已经将其保留在文本的末尾。)

而不是

if {[regexp -all {Unrecognized HTTP URL ([a-z0-9.]*) Flow} $line junk one]} {
    puts $one
}

使用

set urls {}
foreach {junk url} [regexp -all -inline {Unrecognized HTTP URL ([a-z0-9.]*) Flow} $line] {
    lappend urls [string trim $url .]
}

或(Tcl 8.6 +)

set urls [lmap {junk url} [regexp -all -inline {Unrecognized HTTP URL ([a-z0-9.]*) Flow} $line] {string trim $url .}]

使用regexp调用-all和变量名称会在这些变量中存储最后一组匹配项,并返回true或false,指示是否存在匹配项。使用-inline调用将返回一个列表,该列表是所有匹配项的串联(如果此列表为空,则表示没有匹配项)。在这种情况下,使用foreachlmap遍历返回的列表并选择您想要的项目,您可以收集网址列表。

日志在您可能不想要的每个网址后面添加一个点,而string trim $url .修复了它(如果它们出现,它也会删除前导点)。使用正则表达式{Unrecognized HTTP URL ([a-z0-9.]*)\. Flow}{Unrecognized HTTP URL (.*?)\. Flow}是另一种解决方法,通过从捕获中排除该点。

请注意,您使用的正则表达式与所有有效网址都不匹配,并且它与一些无效网址匹配(由于您正在提取实际记录的网址,因此这不是一个很大的问题)。具体来说,由于" com"之前的换行,它错过了第三个url。如果这是一个问题,那么刻意强调网址可能是有意义的:

regexp -all -inline {Unrecognized HTTP URL (.*?) Flow} $line

使用非贪婪的匹配来获取" URL"之间的任何(包括嵌入的空格)和"流动"。在下一步中,您可以通过过滤器传递网址列表,该过滤器会丢弃或标记任何对您来说无效的网址。

将URL导出到Excel的最简单方法应该是将它们写入文本文件:

package require fileutil
::fileutil::writeFile urllist.txt [join $urls \n]\n

或(再次假设Tcl 8.6)

try {
    open urllist.txt w
} on ok f {
    chan puts $f [join $urls \n]
} finally {
    catch {chan close $f}
}

然后在Excel中打开文件;每个URL都位于自己行的第一列。

文档:catchchanifjoinlappendlmapopen,{{3 }},packageregexpsetstring

旧答案

您可以使用此命令获取所有网址:

lmap item [regexp -all -inline {URL\s+\S+} $line] {
    string trimright [lindex $item 1] .
}

如果您使用-all并匹配变量(在您的情况下为junkone),则只会获得最后一场比赛。相反,请同时使用-all-inline,这会为您提供匹配列表。您实际上只需要匹配序列"URL",一个或多个空格字符(\s+),然后是一系列非空格字符(\S+)。这给你列表

{{URL www.58.net} {URL static.58.com} {URL www.google-analytics} {URL track.58.co.in}}

如果$line的任何部分与正则表达式不匹配,则列表将为空。

如果要打印所有网址,可以写:

set urls [lmap item [regexp -all -inline {URL\s+\S+} $line] {
    string trimright [lindex $item 1] .
}]
foreach url $urls {
    puts $url
}

如果你有Tcl 8.6,你可以使用lmap命令将该列表映射到另一个列表,该列表包含第一个列表中每个元素的第二个元素。

如果您有旧版本的Tcl,则应执行以下操作:

set urls [list]
foreach item [regexp -all -inline {URL\s+\S+} $line] {
    lappend urls [string trimright [lindex $item 1] .]
}
foreach url $urls {
    puts $url
}

现在,您可以在正则表达式中使用\S+周围的捕获来获取列表,其中每个其他元素(元素#1,#3等)都是URL,但实际上是获取URL列表有点困难(glenn jackman在他的回答中采用了这条路线)。

请注意,第三个网址已损坏,因为其中有空格。粘贴示例时是否发生了这种情况,或者真实数据中是否会出现这种杂散空格字符?

(如何导出到Excel的说明转移到新答案。)

文档:trycatchchanforeachlappendlindexlmap,{{3 }},openputsregexpset

(注意:评论中提及的' Hoodiecrow'是我,我之前使用过那个昵称。)

答案 1 :(得分:1)

% regexp -inline -all {HTTP URL (\S+)\.} $line
{HTTP URL www.58.net.} www.58.net {HTTP URL static.58.com.} static.58.com {HTTP URL www.google-analytics.} www.google-analytics {HTTP URL track.58.co.in.} track.58.co.in
% foreach {match submatch} [regexp -inline -all {HTTP URL (\S+)\.} $line] {
    lappend urls $submatch
}
% set urls
www.58.net static.58.com www.google-analytics track.58.co.in