使用tcl查找并替换文件中的值

时间:2016-09-16 15:07:59

标签: split tcl

我需要更新文件中的日期。因此,我正在搜索当天的行(#define __VERSION_DAY 23)并拼命尝试更新它。

while {([gets $fp_Vers line] >= 0)} {

   if { [string match -nocase "#define*__VERSION_DAY*" $line] } {
      # Get the current day
      set day [clock format $systemTime -format {%d}]
      set line [split $line]
      # Replace the old value 
      set line [lreplace $line 2 $day]
      puts $fp_Vers $line
   }
}

它将以下内容放在文件{#define} __VERSION_DAY的末尾。我不明白...... 1)为什么周围有括号定义
2)为什么缺少当天(即16)的价值。

感谢您的贡献!

2 个答案:

答案 0 :(得分:0)

通过在getActivity().setTitle("title"); 等Tcl shell中运行命令,您可以轻松找出问题所在。强烈建议这样做,以避免逃跑并做一些没有意义的事情。在下文中,命令(以tkcon开头的行与结果混合。

%

将字符串拆分为列表时,字符串表示会更改,以便以后可以重新生成列表,因此% set line {#define __VERSION_DAY 23} #define __VERSION_DAY 23 set day 16 16 % set line [split $line] {#define} __VERSION_DAY 23 周围的大括号(否则将是无效的列表项)。

#define

set line [lreplace $line 2 $day] {#define} __VERSION_DAY 命令采用以下参数:lreplace list(索引)first(索引)last(零个或多个元素替换范围用)。 ?element ...?(16)的内容被解释为您想要替换为任何内容的范围中的最后一个索引。

请改为尝试:

day

关于更新文件中的日期字段,最好的选择可能是这样做:

% set line [join [lreplace [split $line] 2 2 $day]]
#define __VERSION_DAY 16

注意:不要直接输出set day 16 set f [open $filename] set lines [split [string trim [read $f]] \n] close $f set result {} set tag {#define __VERSION_DAY } set pattern [string map {{ } *} $tag] foreach line $lines { if {[string match -nocase $pattern $line]} { lappend result $tag$day } else { lappend result $line } } set f [open $filename2 w] puts -nonewline $f [join $result \n] close $f ,因为引用变量的内容是为了保留列表附加行创建的列表结构。通过使用换行符连接行,结构将更改为平面文本,该文本在输出中起作用。

或者,使用Tcllib中的$result

fileutil

请注意,策略基本相同。第一个解决方案使用列表追加行进入变量,然后在其中打印连接文本。第二种解决方案是直接打印每一行。没有什么可以阻止您使用直接打印的低级package require fileutil set day 16 set tag {#define __VERSION_DAY } set pattern [string map {{ } *} $tag] set f [open $filename2 w] ::fileutil::foreachLine line $filename { if {[string match -nocase $pattern $line]} { puts $f $tag$day } else { puts $f $line } } close $f - open - read解决方案或带有行列表的close解决方案附加到变量中。

文档: closefileutil (package)foreachifjoinlappendlreplaceopenpackageputsreadsetsplitstring

答案 1 :(得分:0)

问题是split正在添加您不期望的引用,因为它满足其他情况下有意义的Tcl列表序列化的其他规则。在这种情况下,最简单的解决方法是切换到使用regsub来执行替换。正则表达式绝对是锋利的工具,但无论如何它们有时也是完全正确的方法。

# Factor a few bits out for convenience

# The RE pattern we're looking for.
set VERSION_RE {(#define\s+_VERSION_DAY\s*).+}

# Get the current day as a replacement pattern
set dayReplacement [clock format $systemTime -format {\1%d}]

while {[gets $fp_Vers line] >= 0} {
    if {[regsub $VERSION_RE $line $dayReplacement line]} {
        # If we did the replacement, write the new value out
        puts $fp_Vers $line
    }
}

我怀疑您可能需要seekchan truncate重置您要写入的位置,但这是您的问题。

这是有效的,因为当regsub与变量写入参数一起使用时,其Tcl结果是执行的替换次数。没有-all开关,那实际上是一个布尔值:是否找到(并替换)了模式?