我正在尝试从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中是否还有其他有效的方法可以做到这一点。
答案 0 :(得分: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
修改强>
因此,如果“name”可以有任意数量的下划线:
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
答案 1 :(得分:2)
进行提取的一种方法是使用regsub
:
regsub {^([^_]+)_([^_]+)_.*} $_File {\1.\2} _File
正则表达式包含([^_]+)
个组件,它们匹配一系列非下划线字符,加上一个锚点和一些下划线,以及一个与其他所有内容匹配的尾随非捕获.*
(所以我们可以丢弃它)。 regsub
将两个匹配的非下划线部分的串联替换为.
之间的整数字符串(这是整个字符串),并将其写回_File
变量所在的regsub
变量来自。
请注意,我将正则表达式和替换放在大括号中。这是因为它们包含Tcl元字符(方括号和反斜杠),我希望Tcl逐字传递给{{1}}。< / p>