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.
(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
You can use ex
text-editor which is available in all Unix/Linux variants to achieve this, in simple/single line as
printf '%s\n' '/hideOFF' 'd' '/}' '-' 'put' 'wq' | ex file
The ex
editor constructs are similar to the vi
's syntax. The logic I adopted for this is as below (Remember as if you are opening the file in vi
/vim
)
- Searching for the pattern
hideOFF
as '/hideOFF'
, deleting it using d
command key.
- Now searching for the close-brace
/}
, -
and put
writes the line from the register above the brace
wq
writes back the contents to the file.
You can see it working below.
$ cat file
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"]
}
Running the command directly on command-line:-
$ printf '%s\n' '/hideOFF' 'd' '/}' '-' 'put' 'wq' | ex file
$ cat file
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
}
You need to re-write the file, and once you are doing that it's very simple with any language.
Go line by line and copy them to a new file. When you come to hideOFF
line do not write it to the new file, just save into a variable. Then, when you come to the closing brace of that block write out the variable (with the line) and the brace. This will have moved the line with hideOFF
right before the line with the brace.
You'll need a flag to know when you enter and leave a block.
Please try it out and let us know how it is going.
Tested following regex in VIM and it does exactly what you require:
%s/hideOFF\(\_.*\)}/\1\rhideOFF\r}/i
**Explanation:**
%s - Search across the file
\( \) - Used to capture a group of text to be used in replace section
\_.* - Capture everything, including new lines
\1 - Insert captured group here
\r - new line
I referred to following two sources:
http://vim.wikia.com/wiki/Search_across_multiple_lines &
Vim Regex Capture Groups
Original text:
After Regex: