Tcl regexp没有转义星号(*)

时间:2014-09-17 10:55:34

标签: regex escaping tcl

在我的脚本中,我得到一个如下所示的字符串:

Reading thisfile.txt
"lib" maps to directory somedir/work.
"superlib" maps to directory somedir/work.
"anotherlib" maps to directory somedir/anotherlib.
** Error: (errorcode) Cannot access file "somedir/anotherlib". <--
No such file or directory. (errno = ENOENT)                    <--  
Reading anotherfile.txt
.....

但带有错误代码的两条带标记的行只会不时出现。 我正在尝试使用regexpression将Reading thisfile.txt之后的行放到Reading anotherfile.txt之前的行,或者**之前的行,如果它在result之前。

所以"lib" maps to directory somedir/work. "superlib" maps to directory somedir/work. "anotherlib" maps to directory somedir/anotherlib. 在每种情况下应该是这样的:

set pattern ".*Reading thisfile.txt\n(.*)\n.*Reading .*$"

我试过这个正则表达式:

regexp -all $pattern $data -> result

然后我做

set pattern ".*Reading thisfile.txt\n(.*)\n.*\[\*|Reading\].*$"

但是只有在没有错误消息的情况下才有效。 所以我试图寻找*。

** Error

但这也行不通。 set pattern ".*Reading thisfile.txt\n(.*)\n.*\*?.*Reading .*$" 的部分仍在那里。

我想知道为什么。这个甚至不编译:

{{1}}

任何想法如何找到并且不匹配*?

2 个答案:

答案 0 :(得分:1)

从您编写正则表达式的方式来看,您将不得不使用大括号:

set pattern {.*Reading thisfile\.txt\n(.*)\n.*\*?.*Reading .*$}

如果使用引号,则必须使用:

set pattern ".*Reading thisfile\\.txt\n(.*)\n.*\\*?.*Reading .*$"

即。基本上放了第二个反斜杠来逃避第一个。

以上将能够抓住一些东西;虽然是第一个和最后一个Reading之间的所有内容。

如果您想从Reading thisfile.txt匹配到以星号开头的下一行,那么您可以使用:

set pattern {^Reading thisfile\.txt\n(.*?)\n(?=^Reading|^\*)}
regexp -all -lineanchor -- $pattern $data -> result

(?=^Reading|^\*)是一个积极的向前看,我将您的(.*)更改为(.*?),以便您真正得到所有事件,而不是从第一个到Reading。< / p>

如果Reading*位于前方并且都在新行上开始,则前瞻性前瞻将匹配。

-lineanchor会使^在每行的开头而不是在字符串的开头匹配。

codepad demo


我忘了提及如果你有多个匹配,你必须set正则表达式的结果并使用-inline修饰符而不是使用上面的结构(否则你&#39) ; ll只获取最后一个子匹配)...

set results [regexp -all -inline -lineanchor -- $pattern $data]
foreach {main sub} $results {
  puts $sub
}

答案 1 :(得分:1)

我不熟悉tcl,但是下面的正则表达式会给你匹配,其中第一个捕获组包含文件名,第二个捕获组包含你想要的所有行:

^Reading ([^\n]*)\n((?:[^\n]|\n(?!Reading|\*\*))*)

Regular expression visualization

Debuggex Demo

基本上(?:[^\n]|\n(?!Reading|\*\*))*正在说“匹配任何不是换行符的字符或不跟Reading** < / em>的

我从杰里的答案中得到的是你在tcl中定义的那样:

set pattern {^Reading ([^\n]*)\n((?:[^\n]|\n(?!Reading|\*\*))*)}