Ruby - Open file, find and replace multiple lines
Change the third line to
replace = replace.gsub(/bbb/, "Replace bbb with 222")
How to search file text for a pattern and replace it with a given value
Disclaimer: This approach is a naive illustration of Ruby's capabilities, and not a production-grade solution for replacing strings in files. It's prone to various failure scenarios, such as data loss in case of a crash, interrupt, or disk being full. This code is not fit for anything beyond a quick one-off script where all the data is backed up. For that reason, do NOT copy this code into your programs.
Here's a quick short way to do it.
file_names = ['foo.txt', 'bar.txt']
file_names.each do |file_name|
text = File.read(file_name)
new_contents = text.gsub(/search_regexp/, "replacement string")
# To merely print the contents of the file, use:
puts new_contents
# To write changes to the file, use:
File.open(file_name, "w") {|file| file.puts new_contents }
end
Replace line in text file with a new line
First, open the file and save the actual content. Then, replace the string and write the full content back to file.
def remove_line(string)
# save the content of the file
file = File.read('test.txt')
# replace (globally) the search string with the new string
new_content = file.gsub(string, 'removed succesfully')
# open the file again and write the new content to it
File.open('test.txt', 'w') { |line| line.puts new_content }
end
Or, instead of replacing globally:
def remove_line(string)
file = File.read('test.txt')
new_content = file.split("\n")
new_content = new_content.map { |word| word == string ? 'removed succesfully' : word }.join("\n")
File.open('test.txt', 'w') { |line| line.puts new_content }
end
Search and replace multiple words in file via Ruby
Your loop was kind of inside-out ... do this instead ...
f.each_line do |line|
_patterns.each_slice 2 do |a, b|
line.sub! a, b
end
g.puts line
end
Ruby: How to replace text in a file?
There is no possibility to modify a file content in one step (at least none I know, when the file size would change).
You have to read the file and store the modified text in another file.
replace="100"
infile = "xmlfile_in"
outfile = "xmlfile_out"
File.open(outfile, 'w') do |out|
out << File.open(infile).read.gsub(/<appId>\d+<\/appId>/, "<appId>#{replace}</appId>")
end
Or you read the file content to memory and afterwords you overwrite the file with the modified content:
replace="100"
filename = "xmlfile_in"
outdata = File.read(filename).gsub(/<appId>\d+<\/appId>/, "<appId>#{replace}</appId>")
File.open(filename, 'w') do |out|
out << outdata
end
(Hope it works, the code is not tested)
Delete first two lines and add two lines to file
I'd start with something like this:
NEWLINES = {
0 => "New Title",
1 => "\nfff"
}
File.open('test.txt.new', 'w') do |fo|
File.foreach('test.txt').with_index do |li, ln|
fo.puts (NEWLINES[ln] || li)
end
end
Here's the contents of test.txt.new
after running:
New Title
fff
aaa
bbb
ccc
The idea is to provide a list of replacement lines in the NEWLINES
hash. As each line is read from the original file the line number is checked in the hash, and if the line exists then the corresponding value is used, otherwise the original line is used.
If you want to read the entire file then substitute, it reduces the code a little, but the code will have scalability issues:
NEWLINES = [
"New Title",
"",
"fff"
]
file = File.readlines('test.txt')
File.open('test.txt.new', 'w') do |fo|
fo.puts NEWLINES
fo.puts file[(NEWLINES.size - 1) .. -1]
end
It's not very smart but it'll work for simple replacements.
If you really want to do it right, learn how diff
works, create a diff file, then let it do the heavy lifting, as it's designed for this sort of task, runs extremely fast, and is used millions of times every day on *nix systems around the world.
Replace whole line with sub-string in a text file - Ruby
Here is my attempt :
file.txt
First line
Second line
foo
bar
baz foo
Last line
test.rb
f = File.open("file.txt", "r")
a = f.map do |l|
(l.include? 'foo') ? "replacing string\n" : l # Please note the double quotes
end
p a.join('')
Output
$ ruby test.rb
"First line\nSecond line\nreplacing string\nbar\nreplacing string\nLast line"
I commented # Please note the double quotes
because single quotes will escape the \n
(that will become \\n
). Also, you might want to think about the last line of your file since it will add \n
at the end of the last line when there will not have one at the end of your original file. If you don't want that you could make something like :
f = File.open("file.txt", "r")
a = f.map do |l|
(l.include? 'foo') ? "replacing string\n" : l
end
a[-1] = a[-1][0..-2] if a[-1] == "replacing string\n"
p a.join('')
How to delete lines from multiple files
There are a number of things wrong with your code, and you're not safely handling your file changes.
Meditate on this untested code:
ACCESS_FILES = Dir.glob("D:/new_work/*-access.txt")
File.foreach('D:/mywork/list.txt') do |target|
target = target.strip.sub(/,$/, '')
ACCESS_FILES.each do |filename|
new_filename = "#{filename}.new"
old_filename = "#{filename}.old"
File.open(new_filename, 'w') do |fileout|
File.foreach(filename) do |line_in|
fileout.puts line_in unless line_in[target]
end
end
File.rename(filename, old_filename)
File.rename(new_filename, filename)
File.delete(old_filename)
end
end
In your code you use:
File.open('D:\\mywork\\list.txt').read
instead, a shorter, and more concise and clear way would be to use:
File.read('D:/mywork/list.txt')
Ruby will automatically adjust the pathname separators based on the OS so always use forward slashes for readability. From the IO documentation:
Ruby will convert pathnames between different operating system conventions if possible. For instance, on a Windows system the filename "
/gumby/ruby/test.rb
" will be opened as "\gumby\ruby\test.rb
".
The problem using read
is it isn't scalable. Imagine if you were doing this in a long term production system and your input file had grown into the TB range. You'd halt the processing on your system until the file could be read. Don't do that.
Instead use foreach
to read line-by-line. See "Why is "slurping" a file not a good practice?". That'll remove the need for
value.gsub!(/\r\n?/, "\n")
value.each_line do |line|
line.chomp!
While
Dir.glob("D:/new_work/*-access.txt") do |fn|
is fine, its placement isn't. You're doing it for every line processed in your file being read, wasting CPU. Read it first and store the value, then iterate over that value repeatedly.
Again,
text = File.read(fn)
has scalability issues. Using
foreach
is a better solution. Again.Replacing the text using
gsub
is fast, but it doesn't outweigh the potential problems of scalability when line-by-line IO is just as fast and sidesteps the issue completely:replace = text.gsub(line.strip, "")
Opening and writing to the same file as you were reading is an accident waiting to happen in a production environment:
File.open(fn, "w") { |file| file.puts replace }
A better practice is to write to a separate, new, file, rename the old file to something safe, then rename the new file to the old file's name. This preserves the old file in case the code or machine crashes mid-save. Then, when that's finished it's safe to remove the old file. See "How to search file text for a pattern and replace it with a given value" for more information.
A final recommendation is to strip all the trailing commas from your input file. They're not accomplishing anything and are only making you do extra work to process the file.
Related Topics
How to Do Fuzzy Substring Matching in Ruby
Determining Whether One Array Contains the Contents of Another Array in Ruby
Ruby Metaprogramming, How Does Rspec's 'Should' Work
Carrierwave: Create 1 Uploader for Multiple Types of Files
How to Merge Two Hashes That Have Same Keys in Ruby
Port in Use When Not Using a Port
How to Send a Parameter to a Before Filter
How Does Rake Db::Migrate Actually Work
Ruby on Rails Foreach with Bootstrap3 Row Class
How Does Ruby Handle Array Range Accessing
Raise Exception on Shell Command Failure
How to Download a Ruby Gem Without Installing It Automatically
What's The Impact of Eager_Load=True
Installing Pl/Ruby for Postgresql 8.3
How to Daemonize Rails Rake Task on Elastic Beanstalk Start Up