Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Tcl regexp未返回所有匹配项_Regex_Tcl - Fatal编程技术网

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)}