2012-08-28 92 views
3

我想從Tcl中的字符串中提取子串。我編寫了代碼並能夠做到,但我想知道是否還有其他有效的方法來執行此操作。所以確切的問題是我有一個字符串如何在tcl中執行子串提取和替換

name_ext_10a.string_10a.string.string.string

,我想提取「name_ext」,然後刪除「_」,並以「.」代替;我最終希望輸出爲「name.ext」。我寫的是這樣的:

set _File "[string replace $_File [string last "_" $_File] [string length $_File] "" ]" 
set _File "[string replace $_File [string last "_" $_File] [string length $_File] "" ]" 
set _File "[string replace $_File [string last "_" $_File] [string last "_" $_File] "." ]" 

這給我確切的輸出我想要的,但我想知道如果在Tcl的做到這一點任何其他有效的方式。

回答

5

你可以分割使用下劃線作爲一個分離器,其文件名,然後用點參加第2個部分:

% set f name_ext_10a.string_10a.string.string.string 
name_ext_10a.string_10a.string.string.string 
% set out [join [lrange [split $f _] 0 1] .] 
name.ext 

編輯

所以,如果「名」可以有任意數量的的下劃線:

set f "foo_bar_baz_ext_10a.string_10a.string.string.string" 
set pieces [split $f _] 
set name [join [lrange $pieces 0 end-3] _] 
set out [join [list $name [lindex $pieces end-2]] .] ;#==> foo_bar_baz.ext 

但是這變得越來越複雜。一個正則表達式應該足夠了 - 我假設「字符串」可以是任何非下劃線字符序列。做提取

set string {[^_]+} 
set regex "^(.+)_($string)_10a.${string}_10a.$string.$string.$string\$" 
regexp $regex $f -> name ext 
set out "$name.$ext" ;#==> foo_bar_baz.ext 
+0

是的,但問題是字符串「名稱」本身可以有任何數目的下劃線。所以不會改變的是「_ext_10a.str_10a.str.str.str.str」模式。所以這就是爲什麼我試圖用空字符串替換最後兩個下劃線後的字符串,這樣我就會得到「name_ext」,而不是用點來改變最後一個下劃線。 –

+0

@PuneetMittal,答案已更新。 –

1

一種方法是用regsub

regsub {^([^_]+)_([^_]+)_.*} $_File {\1.\2} _File 

正則表達式中包含([^_]+)組件,匹配的非下劃線字符的序列,其,以及一個錨定件和一些下劃線,和一尾隨非捕獲.*匹配一切(所以我們可以放棄它)。 regsub用兩個匹配的非下劃線部分(其間爲.)替換(整個字符串),並將其寫回到字符串來自的_File變量。

請注意,我把大括號中的正則表達式和替換。這是因爲它們包含Tcl元字符(方括號和反斜槓),我希望Tcl能夠逐字地傳入regsub

+0

謝謝Donal,但問題是「名稱」本身可以有任何數目的下劃線,所以唯一不會改變的模式是「_ext_10a.str_10a.str.str.str」,這就是爲什麼我搜索了第二個最後下劃線並用空字符串替換之後的所有內容,並用「.ext」替換「_ext」 –

+0

@Puneet這種細節非常重要;正則表達式非常依賴於正確理解要匹配的內容。 –