简体   繁体   中英

Ruby: sub/gsub at a particular line OR before/after a pattern

I know that I can replace text as below in a file

File.write(file, File.read(file).gsub(/text/, "text_to_replace"))

Can we also use sub/gsub to:-

  • Replace a string on a particular line number (useful when there is a same string at different locations in a file)

Example

 root@vikas:~# cat file.txt
 fix grammatical or spelling errors
 clarify meaning without changing it
 correct minor mistakes
 add related resources or links
 root@box27:~#

I want to insert some text at 3rd line

 root@vikas:~# cat file.txt
 fix grammatical or spelling errors
 clarify meaning without changing it
 Hello, how are you ?
 correct minor mistakes
 add related resources or links
 root@box27:~
  • Replace a string on the line just before/after matching a pattern

Example

 root@vikas:~# cat file.txt
 fix grammatical or spelling errors
 clarify meaning without changing it
 correct minor mistakes
 add related resources or links
 root@box27:~#

I want to search 'minor mistakes' and put text 'Hello, how are you ?' before that.

 root@vikas:~# cat file.txt
 fix grammatical or spelling errors
 clarify meaning without changing it
 Hello, how are you ?
 correct minor mistakes
 add related resources or links
 root@box27:~

Here is the answer.

File.open("file.txt", "r").each_line do |line|
  if line =~ /minor mistakes/
     puts "Hello, how are you ?"
  end
  puts "#{line}"
end

Here is ruby one-liner.

ruby -pe 'puts "Hello, how are you ?" if $_ =~ /minor mistakes/' < file.txt

You can find this functionality in a gem like Thor. Check out the documentation for the inject_into_file method here:

http://www.rubydoc.info/github/erikhuda/thor/master/Thor/Actions#inject_into_file-instance_method .

Here is the source code for the method:

https://github.com/erikhuda/thor/blob/067f6638f95bd000b0a92cfb45b668bca5b0efe3/lib/thor/actions/inject_into_file.rb#L24-L32

If you wish to match on line n (offset from zero):

def match_line_i(fname, linenbr regex)
  IO.foreach(fname).with_index { |line,i| 
    return line[regex] if i==line_nbr }
end

or

return scan(regex) if i==line_nbr }

depending on your requirements.

If you wish to match on a given line, then return the previous line, for application of gsub (or whatever):

def return_previous_line(fname, regex)
  last_line = nil
  IO.foreach(fname) do |line|
    line = f.readline
    return last_line if line =~ regex
    last_line = line
  end
end

Both methods return nil if there is no match.

Okay, as there is no such option available with sub/gsub, I am pasting here my code (with slight modifications to BMW's code) for all three options. Hopefully, this helps someone in a similar situation.

  1. Insert text before a pattern
  2. Insert text after a pattern
  3. Insert text at a specific line number

     root@box27:~# cat file.txt fix grammatical or spelling errors clarify meaning without changing it correct minor mistakes add related resources or links always respect the original author root@box27:~# root@box27:~# cat ruby_script puts "#### Insert text before a pattern" pattern = 'minor mistakes' File.open("file.txt", "r").each_line do |line| puts "Hello, how are you ?" if line =~ /#{pattern}/ puts "#{line}" end puts "\\n\\n#### Insert text after a pattern" pattern = 'meaning without' File.open("file.txt", "r").each_line do |line| found = 'no' if line =~ /#{pattern}/ puts "#{line}" puts "Hello, how are you ?" found = 'yes' end puts "#{line}" if found == 'no' end puts "\\n\\n#### Insert text at a particular line" insert_at_line = 3 line_number = 1 File.open("file.txt", "r").each_line do |line| puts "Hello, how are you ?" if line_number == insert_at_line line_number += 1 puts "#{line}" end root@box27:~# 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM