Divesh Rastogi Divesh Rastogi - 1 month ago 11
Perl Question

Move a pattern from specific line to end of that rule

I am wondering how can I move a pattern placed after certain line to another location of a rule.

Consider the following example,

rule tmap {

hideON
student_analysis Sam -expr "marks(Sam)" -gt 0
hideOFF

-Designate [ School = "ABC]
-Designate [ Name = "Sam" ]
-Designate [ Country= "ABC]
-Designate [ State = "Sam"]
-Designate [ ROLL Number= "Sam"]
}


where hideOFF needs to be moved from student_analysis to just before the end curly braces. Output file should have something like

rule tmap {

hideON
student_analysis Sam -expr "marks(Sam)" -gt 0


-Designate [ School = "ABC]
-Designate [ Name = "Sam" ]
-Designate [ Country= "ABC]
-Designate [ State = "Sam"]
-Designate [ ROLL Number= "Sam"]
hideOFF
}


Just to add these -Designate entries might be in a single row so number of row should not be a criterion. I might have my input file like

rule tmap {

hideON
student_analysis Sam -expr "marks(Sam)" -gt 0
hideOff

-Designate [ School = "ABC] -Designate [ Name = "Sam" ] -Designate [ Country= "ABC] -Designate [ State = "Sam"] -Designate [ ROLL Number= "Sam"]

}


In case if you need more clarification, please let me know.

Final solution Based on Peters help

#!/usr/bin/tclsh
set fileData [lindex $argv 0 ]
set fp [open $fileData r]
set data [read $fp]
set lines [split [string trim $data] \n]
set hideoff {}
foreach line $lines {
if {[regexp {^\s*hideoff\s*} $line match ] == 1 } {
set hideoff $line
} elseif {[regexp {^\s*\}\s*} $line match ] == 1 } {
puts $hideoff
puts $line
} else {
puts $line
}
}


Thanks everyone for so nice suggestions.

Answer

(Tcl solution) You can do that by reprinting lines. You look at them first, skip the line you want to move and then print it when you see the line you want it inserted before.

set lines [split [string trim $data] \n]

set hideoff {}
foreach line $lines {
    if {[string trim $line] eq "hideOFF"} {
        set hideoff $line
    } elseif {[string trim $line] eq "\}"} {
        puts $hideoff
        puts $line
    } else {
        puts $line
    }
}

Another Tcl solution:

regsub -all {(\s*hideOFF)([^\}]+)} $data \\2\\1\n

Both solutions work for multiple blocks.

Documentation: eq (operator), foreach, if, puts, regsub, set, split, string, Syntax of Tcl regular expressions

Comments