Question

I need to convert a string from 2 dimensional array to 1 dimension in Tcl.

Eg

lane_out[0][7]  -> lane_out[7]  
lane_out[1][0]  -> lane_out[8]

The initial string is read from a file, modified and stored in another file. Also, the input file has a lot of different kinds of strings that need replacement so the user provides the find and replace regex in another file.

I have successfully done this for simple strings that required no additional calculations. But I need help in executing expressions. I was thinking that I could have the user provide the expression in the file and execute that but I have not been successful.

User Input File:

lappend userinput {\[(\d+)]\*$ *}
lappend userinput {\[(\d+)]\[(\d+)]$ [expr{\1*8+\2}]}

My broken code:

set line "lane_out[1][0]"
foreach rule $userinput {
  foreach {find replace} [regexp -all -inline {\S+} $rule] break
  regsub -all $find $line $replace line
  set match [regexp -all -inline {expr{.*}} $line] #match = expr{1*8+0}
  set val [$match] #supposed to execute what is in match
  regsub expr{.*} $line $val line
}
Était-ce utile?

La solution

What you do is very complex: you have an input file, a set of search/replace rules, and produce some output. The rules, however, require calling expr.

Here is a made-up data file (data.txt):

lane_out[0][7] = "foo bar"
lane_out[1][0] = "foo bar" 
lane_out[1][1] = "foo bar"
lane_out[2][0] = "foo bar"
lane_out[2][1] = "foo bar" 

And the rules file (rules.txt):

{\[(\d+)\]\[(\d+)\]} {\[[expr {\1 * 8 + \2}]\]}

Here is my script (search_replace.tcl):

package require Tclx

# Read the rules file
set rules {}
for_file line rules.txt {
    lassign $line find replace
    lappend rules $find $replace
}

# Read the data, apply rules
for_file line data.txt {
    foreach {find replace} $rules {
        regsub -all $find $line $replace line
        set line [subst $line]
        puts $line
    }
}

Output:

lane_out[7] = "foo bar"
lane_out[8] = "foo bar" 
lane_out[9] = "foo bar"
lane_out[16] = "foo bar"
lane_out[17] = "foo bar" 

Discussion

  • The rules.txt's format: each line contains search- and replace expressions, separated by a space
  • The code will translate a line such as

    lane_out[2][1] = "foo bar"
    

    to:

    lane_out\[[expr {2 * 8 + 1}]\] = "foo bar"
    
  • Then, the subst command replaces that with:

    lane_out[17] = "foo bar" 
    
  • The tricky part is to escape the square brackets so that expr can do the right thing.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top