2014-08-27 44 views
1

使用变量我有结构类似于字符串列表:正则表达式中

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

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

谢谢!

回答

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绝不能有一个破折号,您可以使用否定类[^-]其中除了仪表板相匹配任何东西,你将不必担心重复逃逸:

    regexp -nocase -- {C:/Users/[^-]+-(.*)\.pgm} $list - out 
    puts $out 
    # => filter1 
    
+0

我遇到的唯一问题是,它包含超过100项的列表。对我来说,它将整个列表视为一个字符串,从第一个条目中删除'“C:/ Users/$ myname-”',从最后一个条目中删除'“.pgm”'。我只是有一个简单的'foreach'循环来处理每个条目。谢谢! – 2014-08-27 17:16:39

+0

@ScottJamesWalter啊,我没有想到'$ list'是一个*实际*列表!你的所有字符串都是相同的格式吗? (即像'C:/ Users/$ myname- {something here} .pgm',其中'$ myname'和'{here here}'不能包含短划线/连字符)。如果是这样,你可以使用一个单一的正则表达式:'set results [regexp -all -inline - {[^ - ] +(?= \。pgm)} $ list]'并且一次接收所有的正则表达式。 – Jerry 2014-08-27 17:21:57

+0

这工作非常出色!再次感谢你! – 2014-08-27 17:46:49

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

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]] ""] 
}