在正则表达式中使用变量

时间:2014-08-27 16:07:27

标签: regex tcl

我有一个字符串列表,结构如下:

C:/Users/scott-filter1.pgm C:/Users/scott-filter2.pgm C:/Users/scott-filter3.pgm

基本上,我想要做的就是删除C:/Users/scott-.pgm,例如只留下filter1

所以,这是我的正则表达式:

regsub -nocase {.pgm} [regsub -nocase {C:/Users/scott-} $list ""] ""

虽然有点笨重,但效果很好。现在,当我用包含变量的正则表达式替换内部正则表达式时,例如:

set myname scott 
{C:/Users/$myname-}

它不再有效。关于如何实现我想要实现的目标的任何想法?

谢谢!

3 个答案:

答案 0 :(得分:2)

您需要删除大括号,因为它们会阻止替换(即您不会将变量替换为该变量的值,而是在正则表达式中使用文字字符串$myname - 也可能值得注意的是,字符串末尾的正则表达式匹配$

regsub "C:/Users/$myname-" $in "" out

或者你可以用一个regsub

来完成
set list "C:/Users/scott-filter1.pgm"
set myname "scott"
regsub -nocase -- "C:/Users/$myname-(.*)\\.pgm" $list {\1} out
puts $out
# => filter1

注意:

  • 如果你删除大括号并使用引号,你需要加倍逃避你曾经逃过的东西。
  • 当我使用parens并且.*匹配任何字符时,我使用了捕获组。然后,使用替换部分中的\1将捕获的部分放回到名为out的变量中。
  • 严格来说,您需要转义.,因为这是正则表达式中的通配符并匹配任何1个字符。因为我使用引号,所以我需要使用两个反斜杠来双重转义。
  • 匹配可能比替换更简单,更直接:

    regexp -nocase -- "C:/Users/$myname-(.*)\\.pgm" $list - out
    puts $out
    # => filter1
    
  • 如果'名称'可以是任何东西,那么你可以使用更通用的正则表达式来避免必须将名称放在正则表达式中...例如,如果$myname永远不能有破折号,你可以使用否定的类{{1}除了破折号之外的任何东西都匹配,你不必担心双重逃脱:

    [^-]

答案 1 :(得分:1)

还有另一种方法可以做到这一点,假设你想要的部分总是在短划线和扩展名之前的最后一个点之间的文件名中。

set foo C:/Users/scott-filter1.pgm
# => C:/Users/scott-filter1.pgm
set bar [file rootname [file tail $foo]]
# => scott-filter1
set baz [split $bar -]
# => scott filter1
set qux [lindex $baz end]
# => filter1

lindex [split [file rootname [file tail $foo]] -] end
# => filter1

file命令适用于任何可识别为文件路径的字符串。 file tail产生文件路径减去包含目录的部分,即仅产生实际文件名。 file rootname生成文件名减去扩展名。 split将字符串转换为列表,在每个破折号处将其拆分。 lindex从列表中获取一个项目,在这种情况下是最后一项。

更具特色性(但实际上非常通用)的解决方案:

lindex [split [lindex [split $foo -] end] .] 0
# => filter1

此调用在每个短划线处分割文件路径并选择最后一个项目。此项在每个点处再次分割,并选择结果列表的第一项。

文档:filelindexsetsplit

答案 2 :(得分:0)

由于这是一个文件名列表,我们可以使用lmap(将操作应用于列表的每个元素,需要8.6)和file(特别是file tailfile rootname)完成大部分工作。一个简单的string map将完成它,虽然也可以使用regsub

set filenames {C:/Users/scott-filter1.pgm C:/Users/scott-filter2.pgm C:/Users/scott-filter3.pgm}
set filtered [lmap name $filenames {
    string map {"scott-" ""} [file rootname [file tail $name]]
    # Regsub version:
    #regsub {^scott-} [file rootname [file tail $name]] ""
}]

旧版本的Tcl需要使用foreach

set filtered {}
foreach name $filenames {
    lappend filtered [string map {"scott-" ""} [file rootname [file tail $name]]]
    # Regsub version:
    #lappend filtered [regsub {^scott-} [file rootname [file tail $name]] ""]
}