0

I try to gsub in file like following:

def meth(*args, &blk)
  "non-replaced"
end

# "replaced string starting"
def meth(*args, &blk)
  "replaced"
end
# "replaced string ending"

def meth(*args, &blk)
  "non-replaced"
end

my question is: How to only replace middle "meth" with a effective way, i can do it with stupid way, such as realines > lines[from..to] > and then lines.join("\n"), it will waste too time, i hope a effective way, such as a native method to do it.

cimi3386284gt
  • 301
  • 1
  • 2
  • 8

2 Answers2

0

I guess you want something like this:

contents = IO.read(filename)
replaced = contents.gsub(/# "replaced string starting"\n(.*)# "replaced string ending"/m, replace_contents)
IO.write(output_filename, replaced)

IO.read reads the whole file as a single text string, gsub(/.../m, replaced_contents) replaces the block within the two comments with what you would like there instead, and IO.write writes it back to an output file.

Uri Agassi
  • 36,848
  • 14
  • 76
  • 93
0

You should find markers or landmarks in the file that you use to turn on your gsub processing, and then turn it off again. Using File.foreach makes it easy to read the file line-by-line, which is very fast, and provides the granularity needed to do what you want. (See "Why is "slurping" a file not a good practice?" for reasons why "slurping" using read or deadlines should usually be avoided.)

Ruby has the .. operator (AKA "flip-flop) which is designed for this purpose, and makes it very easy to process only certain chunks of something you are enumerating. See "Why does a Flip-Flop operator include the second condition?" and "Ruby - Get file contents with in a separator in an array" for ideas on how to use it.

The basic idea is to read the file line by line, looking for your block markers, and toggle processing. Something like this untested code is a general outline for it:

File.open('/path/to/some/new_file.txt', 'w') do |fo|
  File.foreach('/path/to/some/file.txt') do |li|
    if (li[/some_start_pattern/] .. li[/some_stop_pattern/])
      li.gsub!(/pattern_of_thing_to_change/, 'text to substitute')
    end
    fo.puts li
  end
end

By doing it this way, you can easily expand the number of blocks you're processing in a file, or the things you're replacing.

Back to .. AKA "flip-flop". It's an operator borrowed from Perl, which got it from AWK. It remembers the state of the first test, to the left of the .., and when that switches to true, .. remembers that, and returns true until the second test returns true, at which point .. begins to returning false again. Once you get the hang of it it's amazing how fast you can grab chunks of files to process.

Community
  • 1
  • 1
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
  • seems to empty my file: find ./test -type f | xargs -d '\n' ruby -e "ARGV.each do |filepath|; File.open(filepath, 'w') do |file|; File.foreach(filepath) do |line|; line.gsub(\"install\",\"latest\"); file.puts line; end; end; end; " – user1767316 Oct 14 '20 at 09:03