2014-08-27 41 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]] ""] 
}