Replace whole line with sub-string in a text file - Ruby - ruby

New to ruby here!
How to replace the whole line in a text file which contains a specific string using ruby?
Example: I want to remove and add the whole line contains "DB_URL" and add something like "DB_CON=jdbc:mysql:replication://master,slave1,slave2,slave3/test"
DB_URL=jdbc:oracle:thin:#localhost:TEST
DB_USERNAME=USER
DB_PASSWORD=PASSWORD

Here is your solution.
file_data = ""
word = 'Word you want to match in line'
replacement = 'line you want to set in replacement'
IO.foreach('pat/to/file.txt') do |line|
file_data += line.gsub(/^.*#{Regexp.quote(word)}.*$/, replacement)
end
puts file_data
File.open('pat/to/samefile.txt', 'w') do |line|
line.write file_data
end

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('')

Related

How can I read lines from a file into an array that are not comments or empty?

I have a text file where a line may be either blank, a comment (begins with //) or an instruction (i.e. anything not blank or a comment). For instance:
Hiya #{prefs("interlocutor")}!
// Say morning appropriately or hi otherwise
#{(0..11).include?(Time.now.hour) ? 'Morning' : 'Hi'} #{prefs("interlocutor")}
I'm trying to read the contents of the file into an array where only the instruction lines are included (i.e. skip the blank lines and comments). I have this code (which works):
path = Pathname.new("test.txt")
# Get each line from the file and reject comment lines
lines = path.readlines.reject{ |line| line.start_with?("//") }.map{ |line| line.chomp }
# Reject blank lines
lines = lines.reject{ |line| line.length == 0 }
Is there a more efficient or elegant way of doing it? Thanks.
start_with takes multiple arguments, so you can do
File.open("test.txt").each_line.reject{|line| line.start_with?("//", "\n")}.map(&:chomp)
in one go.
I would do it like so, using regex:
def read_commands(path)
File.read(path).split("\n").reduce([]) do |results, line|
case line
when /^\s*\/\/.*$/ # check for comments
when /^\s*$/ # check for empty lines
else
results.push line
end
results
end
end
To break down the regexes:
comments_regex = %r{
^ # beginning of line
\s* # any number of whitespaces
\/\/ # the // sequence
.* # any number of anything
$ # end of line
}x
empty_lines_regex = %r{
^ # beginning of line
\s* # any number of whitespaces
$ # end of line
}x

how do you use multiple arguments with gsub? (Ruby)

I need to add multiple arguments to the gsub parenthesis, but whatever I try it doesn't seem to work.
# encoding: utf-8
# !/usr/bin/ruby
# create an empty array
original_contents = []
# open file to read and write
f = File.open("input.txt", "r")
# pass each line through the array
f.each_line do |line|
# push edited text to the array
original_contents << line.gsub(/[abc]/, '*')
end
f.close
new_file = File.new("output.txt", "r+")
new_file.puts(original_contents)
new_file.close
I need it so I can do a lot of different search and replaces like this:
original_contents << line.gsub(/[abc]/, '*' || /[def]/, '&' || /[ghi]/, '£')
Of course I know this code doesn't work but you get the idea. I've tried using an array for each argument but it ends up printing the text into the output file multiple times.
Any ideas?
As Holger Just said, I also suggest you run gsub multiple times. You can make the code a bit prettier when you store the replacements in a hash and then iteratively apply them to the string with Enumerable#reduce.
replacements = {
/[abc]/ => '*',
/[def]/ => '&',
/[ghi]/ => '£'
}
f = File.open("input.txt", "r")
original_contents = f.lines.map do |line|
replacements.reduce(line) do |memo, (pat, replace)|
memo.gsub(pat, replace)
end
end
f.close
new_file = File.new("output.txt", "r+")
new_file.puts(original_contents)
new_file.close

Regular Expression matching in ruby, checking for white space

I am trying to check a file for white spaces at the beginning of each line. I want the white-space at the beginning of the line to be consistent, all start with spaces or all start with tabs. I wrote the code below but it isn't working for me. If there exist a space at a beginning of one line and then a tab exists in the beginning of another line print a warning or something.
file = File.open("file_tobe_checked","r") #I'm opening the file to be checked
while (line = file.gets)
a=(line =~ /^ /).nil?
b=(line =~/^\t/).nil?
if a==false && b==false
print "The white spaces at the beginning of each line are not consistent"
end
end
file.close
This is one solution where you don't read the file or the extracted lines array twice:
#!/usr/bin/env ruby
file = ARGV.shift
tabs = spaces = false
File.readlines(file).each do |line|
line =~ /^\t/ and tabs = true
line =~ /^ / and spaces = true
if spaces and tabs
puts "The white spaces at the beginning of each line are not consistent."
break
end
end
Usage:
ruby script.rb file_to_be_checked
And it may be more efficient to compare lines with these:
line[0] == "\t" and tabs = true
line[0] == ' ' and spaces = true
You can also prefer to use each_line over readlines. Perhaps each_line allows you to read the file line by line instead of reading all the lines in one shot:
File.open(file).each_line do |line|
How important is it that you check for the whitespace (and warn/notify accordingly)? If you are aiming to just correct the whitespace, .strip is great at taking care of errant whitespace.
lines_array = File.readlines(file_to_be_checked)
File.open(file_to_be_checked, "w") do |f|
lines_array.each do |line|
# Modify the line as you need and write the result
f.write(line.strip)
end
end
I assume that no line can begin with one or more spaces followed by a tab, or vice-versa.
To merely conclude that there are one or more inconsistencies within the file is not very helpful in dealing with the problem. Instead you might consider giving the line number of the first line that begins with a space or tab, then giving the line numbers of all subsequent lines that begin with a space or tab that does not match the first line found with such. You could do that as follows (sorry, untested).
def check_file(fname)
file = File.open(fname,"r")
line_no = 0
until file.eof?
first_white = file.gets[/(^\s)/,1]
break if first_white
line_no += 1
end
unless file.eof?
puts "Line #{line_no} begins with a #{(first_white=='\t') ? "tab":"space"}"
until file.eof?
preface = file.gets[/(^\s)/,1))]
puts "Line #{line_no} begins with a #{(preface=='\t') ? "tab":"space"}" \
if preface && preface != first_white
line_no += 1
end
end
file.close
end

ruby each_line comparison only returns last string

Code:
class Comparer
words = "asdf-asdf-e-e-a-dsf-bvc-onetwothreefourfive-bob-john"
foundWords = []
File.foreach('words.txt') do |line|
substr = "#{line}"
if words.include? substr
puts "Found " + substr
foundWords << substr
end
end
wordList = foundWords.join("\n").to_s
puts "Words found: " + wordList
end
words.txt:
one
blah-blah-blah
123-5342-123123
onetwo
onetwothree
onetwothreefour
I'd like the code to return all instances of include?, however when the code is run, wordList only contains the last line of words.txt ("onetwothreefour".) Why don't the other lines in words.txt get factored?
Because all other lines you expect to be found, they have "hidden" newline character at the end. You can see for yourself.
File.foreach('words.txt') do |line|
puts line.inspect
# or
p line
end
You can get rid of newlines by using chomp! method on line.
File.foreach('words.txt') do |line|
line.chomp!
# proceed with your logic
end

Ruby - Remove only specific duplicate lines in a file

I want to remove duplicate lines from a file but only remove duplicate lines that match a specific regular expression, leaving all other duplicates in the file. Here is what I currently have:
unique_lines = File.readlines("Ops.Web.csproj").uniq do |line|
line[/^.*\sInclude=\".*\"\s\/\>$/]
end
File.open("Ops.Web.csproj", "w+") do |file|
unique_lines.each do |line|
file.puts line
end
end
This will deduplicate the lines correctly but will only add the lines that meet the regular expression back into the file. I need all the other lines in the file to be added back unchanged. I know I am missing something small here. Ideas?
Try this:
lines = File.readlines("input.txt")
out = File.open("output.txt", "w+")
seen = {}
lines.each do |line|
# check if we want this de-duplicated
if line =~ /Include/
if !seen[line]
out.puts line
seen[line] = true
end
else
out.puts line
end
end
out.close
Demo:
➜ 12980122 cat input.txt
a
b
c
Include a
Include b
Include a
Include a
d
e
Include b
f
➜ 12980122 ruby exec.rb
➜ 12980122 cat output.txt
a
b
c
Include a
Include b
d
e
f

Resources