Tcl regexp未返回所有匹配项
我正在读一个文件,内容如下:Tcl regexp未返回所有匹配项,regex,tcl,Regex,Tcl,我正在读一个文件,内容如下: Aug2017: -------------------------------------- Name Age Phone -------------------------------------- Jack 25 128736372 Peter 26 987840392 -------------------------------------- Sep2017: --------------------
Aug2017:
--------------------------------------
Name Age Phone
--------------------------------------
Jack 25 128736372
Peter 26 987840392
--------------------------------------
Sep2017:
--------------------------------------
Name Age Phone
--------------------------------------
Jared 21 874892032
Eric 24 847938427
--------------------------------------
所以我想提取每条虚线之间的信息,并将它们放入一个列表中。假设$data
包含文件内容,我将使用下面的tcl regexp来提取信息:
regexp -all -inline -- {\s+\-{2,}\s+(.*?)\s+\-{2,}\s+} $data
据我所知,返回的匹配结果将存储为包含fullMatch
和subMatch
的列表
llength $data
2
我用llength
命令再次检查,只有一个fullMatch
和subMatch
llength $data
2
为什么只有1个子匹配?应该有5个匹配项,如下所示:
Aug2017:
--------------------------------------
Name Age Phone --> 1st Match
--------------------------------------
Jack 25 128736372
Peter 26 987840392 --> 2nd Match
--------------------------------------
Sep2017: --> 3rd Match
--------------------------------------
Name Age Phone --> 4th Match
--------------------------------------
Jared 21 874892032
Eric 24 847938427 --> 5th Match
--------------------------------------
因此,在本例中,我使用lindex
选择第二个列表元素(subMatch
)
lindex [regexp -all -inline -- {\s+\-{2,}\s+(.*?)\s+\-{2,}\s+} $data] 1
但是我得到的结果是这样的,似乎从内容的开始和结束都是匹配的:
Name Age Phone
--------------------------------------
Jack 25 128736372
Peter 26 987840392
--------------------------------------
Sep2017:
--------------------------------------
Name Age Phone
--------------------------------------
Jared 21 874892032
Eric 24 847938427
我的印象是regexp应该从字符串的开头开始匹配,并按顺序匹配到字符串的结尾,不知道为什么tcl regex会这样?我错过什么了吗
**这里我想实现的主要功能是提取虚线分隔符之间的数据,上面的数据只是一个示例
预期结果:包含所有匹配项的列表
{ {Name Age Phone} -->1st match
{Jack 25 128736372
Peter 26 987840392} -->2nd match
{Sep2017:} -->3rd match
{Name Age Phone} -->4th match
{Jared 21 874892032
Eric 24 847938427} -->5th match
}
更新:
我对我的tcl正则表达式做了如下细微的更改,以包括前瞻性和@glenn的建议:
regexp -all -inline -expanded -- {\s+?-{2,}\s+?(.*?)(?=\s+?-{2,}\s+?)} $data
我得到的结果(10个子匹配):
这非常接近预期的结果,但我仍然想知道如何使用正则表达式来完美匹配预期的5个子匹配 正则表达式匹配不是解决此类问题的好工具。使用某种线路过滤器会更好 基于正则表达式的筛选器,与示例行非常匹配:
set f [open data.txt]
while {[gets $f line] >= 0} {
if {[regexp {:} $line]} continue
if {![regexp {\d} $line]} continue
puts $line
}
close $f
理由:只有月份名称行有冒号,标题行和分隔符中没有数字
不太依赖正则表达式的筛选器:
set f [open data.txt]
set skip 4
while {[gets $f line] >= 0} {
if {$skip < 1} {
if {[regexp {\-{2,}} $line]} {
set skip 4
} else {
puts $line
}
} else {
incr skip -1
}
}
close $f
或:
这也应该起作用:
regsub -all -line {^\s+-{2,}.*(\n|\Z)} $data {}
启用对换行符敏感的匹配,将匹配并删除仅由空格、破折号、可选非换行符以及换行符或外部字符串结尾组成的所有行
要收集匹配项列表,而不仅仅是打印筛选行,请执行以下操作:
set matches {}
set matchtext {}
::fileutil::foreachLine line data.txt {
if {![regexp {\-{2,}} $line]} {
append matchtext $line\n
} else {
lappend matches $matchtext
set matchtext {}
}
}
运行此操作后,变量matches
包含一个列表,其项目是分隔符之间的连续行
另一种方法是:
::textutil::splitx $data {(?n)^\s+-{2,}.*(?:\n|\Z)}
(它还会在列表末尾添加一个空元素,如果出现问题,可以很容易地将其删除。)
文件:
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
以上数据只是一个例子。如果我想在虚线分隔符之间提取数据,我该如何实现?请给出建议。@user3635458:添加了一些建议。我不想过滤掉破折号字符。我想提取每个“-”分隔符之间的单词,就像我刚才在“预期结果”下添加的一样。我知道这可以通过逐行处理来完成,但我的意图是使用regexp来进行提取。谢谢。@TattEhian:最后也添加了一个解决方案(它与预期结果的不同之处在于包含了August标记。与perl不同,Tcl正则表达式要么完全贪婪,要么完全不贪婪,并且由看到的第一个量词进行选择。您需要仔细阅读。前面的
\s+
为整个正则表达式设置贪婪首选项。如果将其改为\s+?
您将更接近您想要的结果,但只会得到奇数子匹配。这是因为正则表达式正在使用第2行连字符,因此下一次尝试不再使用第1行连字符。我提供的文档链接中的关键句子如下:“一个分支与其中第一个有偏好的量化原子具有相同的偏好。”@glennjackman:谢谢你的建议。现在的结果与预期结果非常接近,但我仍然想找出如何在5个子匹配中完美匹配。你可以在“更新”部分看到更新的结果。
set matches {}
set matchtext {}
::fileutil::foreachLine line data.txt {
if {![regexp {\-{2,}} $line]} {
append matchtext $line\n
} else {
lappend matches $matchtext
set matchtext {}
}
}
::textutil::splitx $data {(?n)^\s+-{2,}.*(?:\n|\Z)}