首页 > 解决方案 > 在 tcl 中查找并替换文件中的数字

问题描述

我有一个巨大的文件。我需要找到包含模式 abc_x 的行并将其值 0.34 替换为增加值的 10%。然后将整个文件(带有替换值)复制到一个新文件中。我是 Tcl 的新手,请告诉我该怎么做。提前致谢。

标签: replacetclregsub

解决方案


这包括三个关键阶段:

  1. 读入旧文件。

  2. 更新内存中的数据。

  3. 写出新文件。

第一阶段和第三阶段非常标准:

set f [open input.txt]
set data [read $f]
close $f
set f [open output.txt "w"]
puts -nonewline $f $data
close $f

所以现在只需要在内存中进行转换。对此的最佳答案取决于您使用的 Tcl 版本。在所有当前的生产版本中,最好将数据拆分为行并对其进行迭代,检查行是否匹配,如果匹配,则执行转换。

set lines {}
foreach line [split $data "\n"] {
    if {[matchesPattern $line]} {
        set line [updateLine $line]
    }
    lappend lines $line
}
set data [join $lines "\n"]

好的,在上面的代码中,matchesPattern并且updateLine是真实代码的替代品,可能如下所示:

if {[regexp {^(\s*abc_x\s+)([\d.]+)(.*)$} $line -> prefix value suffix]} {
    # Since we matched the prefix and suffix, we must put them back
    set line $prefix[expr {$value * 1.1}]$suffix
}

将所有这些部分组合在一起可以得到:

set f [open input.txt]
set data [read $f]
close $f

set lines {}
foreach line [split $data "\n"] {
    if {[regexp {^(\s*abc_x\s+)([\d.]+)(.*)$} $line -> prefix value suffix]} {
        set line $prefix[expr {$value * 1.1}]$suffix
    }
    lappend lines $line
}
set data [join $lines "\n"]

set f [open output.txt "w"]
puts -nonewline $f $data
close $f

在 8.7 中,您将能够更简洁地编写更新:

set data [regsub -all -line -command {^(\s*abc_x\s+)([\d.]+)} $data {apply {{-> prefix value} {
    # Since we matched the prefix, we must put it back
    string cat $prefix [expr {$value * 1.1}]
}}}]

(变得比这更短确实需要一个支持后视的 RE 引擎;Tcl 的标准引擎不支持。)


推荐阅读