0

I have a huge file. I need to find the line containing the pattern abc_x and replace its value 0.34 to 10% increased value. And then copy the entire file (with replaced values) into a new file. I am new to Tcl, please let me know how to do this. Thanks in advance.

sing20
  • 11
  • 2

1 Answers1

1

There are three key stages to this:

  1. Reading the old file in.

  2. Making the update to the data in memory.

  3. Writing the new file out.

The first and third stages are pretty standard:

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

So now it's just about doing the transformation in memory. The best answer to this depends on the version of Tcl you're using. In all current production versions, it's probably best to split the data into lines and iterate over them, checking whether a line matches and, if it does, performing the transformation.

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

OK, in that code above, matchesPattern and updateLine are stand-ins for the real code, which might look like this:

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
}

Composing all those pieces together gets this:

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

In 8.7 you'll be able to write the update more succinctly:

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}]
}}}]

(Getting shorter than this would really require a RE engine that supports lookbehinds; Tcl's standard one does not.)

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215