TCL中的负正则表达式

时间:2014-06-16 14:53:15

标签: regex tcl

我有一个变量text,它是一个带或不带'_backup'的文件名。我需要一个正则表达式来选择一个没有'_backup'的文件名(如果它有*_backup.txt则排除)。我想在TCL(而不是Ruby)中实现这一点。我使用Ruby作为插图目的。我有正则表达式如下。

text = "some_thing.txt"
text =~ /\S+[^_backup]\.txt/
# => 0 #-> correct as filename does not have _backup

text = "some_thinp.txt"
text =~ /\S+[^_backup]\.txt/
# => nil #-> Wrong, filename does not have _backup (returns nil as last character before .txt 'p' is one among the characters given in exclude list.

上述代码的问题是排除按字符(任何字符)排序,并且失败的文件名以'p'之前的排除列表中给出的字符'.txt'之一结尾。如何构建排除单词部分的正则表达式?

1 个答案:

答案 0 :(得分:4)

有很多聪明的方法来陈述“负面匹配”,但最简单和最易读的方式是从外部否定直接匹配:

if {![regexp {_backup} $text]} {
    # do something with a name that does not contain '_backup'
    set filename [file tail $text]
}

(我假设标准操作是获取$text中给出的路径的文件名和扩展名部分)或

if {[regexp {_backup} $text]} {
    # do something with a name that does contain '_backup'
} else {
    # do something with a name that does not contain '_backup'
    set filename [file tail $text]
}

由于正则表达式变得更复杂,因此代码通常难以理解。如果可以使用直接匹配和if命令完成作业,那么总是优于神秘的正则表达式。

可以使用regexp代替string match

if {![string match {*_backup*} $text]} {
    # do something with a name that does not contain '_backup'
    set filename [file tail $text]
}

如果变量texts中有文件路径字符串列表,您应该能够过滤掉不包含字符串_backup的字符串,如下所示:

set filenames [lmap text $texts {
    expr {
        [regexp {_backup} $text]
            ? [continue]
            : [file tail $text]
    }
}]

或等同于:

set filenames [lmap text $texts {
    if {[regexp {_backup} $text]} continue
    file tail $text
}]

或者仍然等同于:

set filenames {}
foreach text $texts {
    if {[regexp {_backup} $text]} continue
    lappend filenames [file tail $text]
}

文档链接:regexpstringiffilelmapexprcontinue,{{ 3}},foreach

{1}}命令是在Tcl 8.6中引入的。可以找到与Tcl 8.4和Tcl 8.5兼容的Pure-Tcl实现lappend


(好吧,是的!对这个回答的回应使我的声誉达到了here的辉煌。谢谢!;))