kbr85
kbr85

Reputation: 1436

Working with file containing unmatched braces

I need to modify a file containing several lines with unmatched braces like:

  rmsd {
    atoms {
      atomsFile 
      atomsCol B
      atomsColValue 1
    }

So if I do this:

set fp [open "fpor.conf" r]
set file_data [read $fp]
close $fp
set confFile [split $file_data "\n"]

set inOut [open "us.in" w]

foreach line $inFile {
     if {[lindex $line 0] == "atomsFile"} {
        lappend line "us.pdb"
     }
     puts $inOut "$line"
}
close $inOut

The script fails with the error: unmatched open brace in list. Is there a way to avoid this?

Upvotes: 2

Views: 1438

Answers (3)

Peter Lewerin
Peter Lewerin

Reputation: 13252

When the contents of a file are an improper list, it's better to treat it as text only.

set fp [open "fpor.conf" r]
set file_data [read $fp]
close $fp
set fp [open "us.in" w]
puts -nonewline $fp [regsub -line -all {^(\s*atomsFile.*)$} $file_data {\1us.pdb}]
close $fp

or, a little more high-level:

package require fileutil

proc appendIt file_data {
    regsub -line -all {^(\s*atomsFile.*)$} $file_data {\1us.pdb}   
}

::fileutil::writeFile us.in [appendIt [::fileutil::cat fpor.conf]]

Documentation: close, fileutil (package), open, package, proc, puts, read, regsub, set, Syntax of Tcl regular expressions

Upvotes: 0

glenn jackman
glenn jackman

Reputation: 246744

You read the file into a list of lines, then you iterate over the lines. Your mistake is treating the line like a list instead of a string. This will help you:

foreach line $confFile {
    set fields [regexp -all -inline {\S+} $line]
    if {[lindex $fields 0] eq "atomsFile"} { ...
  • Here, split is insufficient to find the whitespace-separated words, because split splits on individual characters:

    % set line {      atomsFile }
          atomsFile 
    % split $line
    {} {} {} {} {} {} atomsFile {}
    

Or just do regex matching:

foreach line $confFile {
    if {[regexp {^\s*atomsFile} $line]} { ...

As you noticed, you cannot handle any arbitrary string as if it is a list.

% set line "no { match here"
no { match here
% lindex $line 0
unmatched open brace in list
% lindex [split $line] 0
no

Upvotes: 2

Dinesh
Dinesh

Reputation: 16428

If your intention is to update the file as follows,

atomsFile us.pdb

then, instead of checking for the list index of presence, check only the word.

i.e.

if {[regexp atomsFile $line]} {
    lappend line "us.pdb"
}

Upvotes: 1

Related Questions