Concatenating strings with << is adding unexpected new lines - ruby

As part of a data cleanup effort I need to append a string to the end of each line of data.
export = File.new('C:\clean_file.txt' , 'w+')
File.open('C:\dirty_file.txt').each_with_index do |line, index|
start_string = line.to_s
# start_string => "23-SEP-13","201309","208164","F5140"
# some gsub code on start_string...
# start_string => "09/23/2013","201309","208164","Customer1"
decoded_string = start_string
decoded_string << %q(,"Accounts")
export.puts decoded_string
end
However, when I attempt to append the string with the << operator, I'm getting an extra carriage return:
# clean_file.txt looks like this =>
line1: "09/23/2013","201309","208164","Customer1"
line2: ,"Accounts"
line3: "09/24/2013","201309","208165","Customer2"
line4: ,"Accounts"
# etc.
I tried:
decoded_string = start_string + %q("Accounts")
but got the same result, and it seems like << is the preferred way to concatenate strings in Ruby. How should I be appending strings to ensure 'clean_file.txt' looks like the below?
# clean_file.txt SHOULD love look like this =>
line1: "09/23/2013","201309","208164","Customer1","Accounts"
line2: "09/24/2013","201309","208165","Customer2","Accounts"
# etc.

Change
start_string = line.to_s
to
start_string = line.chomp
The newlines are coming from the lines read from the file.

Related

How to remove control characters in ruby

I used Open3 to get result of a command like this:
Open3.popen3(service_command) do |stdin, stdout, stderr|
result = stdout.read.delete(' ').split("\n")
end
In the string returned in stdout.read I found there are control characters like \e[2K, how can I remove those and get "clean" strings?
Thanks
Seems like these are CSI sequences (https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences)
You could remove them like this:
REGEXP = /\e\[[^\x40-\x7E]*[\x40-\x7E]/
input = ["\e[mstring1", "\e[2Kstring2", "string3", "\e[2Kstrin4"]
def remove_csi(line)
line.gsub(REGEXP, "")
end
output = input.map do |line|
remove_csi(line)
end
p input
p output
# => ["\e[mstring1", "\e[2Kstring2", "string3", "\e[2Kstrin4"]
# => ["string1", "string2", "string3", "strin4"]
The regexp is a simplified version that matches from the start of the string up to the "final byte" in the sequence.

Replace whole line with sub-string in a text file - 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('')

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

Overriding random points in file

I want to overwrite portions of a file based on a regex pattern. The ruby script will look for camelCase variable names and convert them to something like background-color. I have a list of all variables to convert (the keys) and what they need to be changed to (the values):
variables = {
"backgroundColor" => "background-color",
"fontSize" => "font-size",
"fontFamily" => "font-family",
"fontColor" => "font-color",
"formFont" => "form-font",
"linkColor" => "link-color",
"linkHoverColor" => "link-hover-color",
"linkDecoration" => "link-decoration",
"headingFamily" => "heading-family",
"headingColor" => "heading-color",
"baseWidth" => "base-width",
"baseColWidth" => "base-col-width",
"baseGutterWidth" => "base-gutter-width",
"isFluid" => "is-fluid",
"baseColCount" => "base-col-count",
"tabletWidth" => "tablet-width",
"mobilePortraitWidth" => "mobile-portrait-width",
"mobileLandscapeWidth" => "mobile-landscape-width"
}
I have a working shell script:
sed -i '' "s/${keys[i]}/${values[i]}/g" _MYconfig.scss
I am trying to translate this into Ruby. I tried reading the file line by line, but the lines in the file don't correspond to the items in the collection. Something like this will not work:
File.open("_skeleton.config.scss", "r+") do |file|
file.each_line do |line|
# use gsub here
end
end
Then I drew inspiration from this gist, and tried:
variables.each do |key, value|
%x(ruby -p -e "gsub /#{key}/, '#{value}' #{Dir.pwd}#{filename}")
end
but I can't seem to get it to work. I can't figure out how to write at random points in a file like sed. I can't figure out how to iterate through variables using the ruby version of sed. Any ideas?
Use this for each key:
newkey = oldkey.gsub(/(?<=[a-z])(?=[A-Z])/, '-').downcase
Explanation
The regex matches positions (not characters) located between the change in case by using a lookbehind and a lookahead
(?<=[a-z]) asserts that the previous char is lowercase
(?=[A-Z]) asserts that the next char is uppercase
the gsub replaces that position with a -
we downcase the result
To see the replacement before the downcase, see the substitutions at the bottom of this regex demo.
Try something like this:
# read all lines of the file into an array
file_lines = File.readlines("_skeleton.config.scss", "r+")
new_file_lines = []
# gsub each line with all your matches
file_lines.each do |line|
new_line = line
variables.each do |key, value|
new_line = new_line.gsub /#{key}/, value
end
new_file_lines << new_line
end
# then truncate the old file and write back the set of newlines
File.open("_skeleton.config.scss", "w") do |f|
new_file_lines.each do |line|
f.write line
end
end
note: not tested, may contain bugs...

Why can't I split a string on control characters?

I am trying to split a line when I find the characters ^C or ^B together. For some reason it is not splitting properly.
I have been on Rubular and tested this and supposedly it should split it.
The lines that I am reading in and trying to split look something like this:
SOME_KEY^CSOME_VALUE^BSOME_KEY^CSOME_VALUE
The code is:
final_array = []
temp_array = []
array__with_all_of_the_data.each do |x|
temp_array = x.split(/\^C/)
temp_array.each do |y|
final_array << y.split(/\^B/)
end
#final_array << final_array.join(",")
end
Split using the regular expression /\^[BC]/:
>> 'SOME_KEY^CSOME_VALUE^BSOME_KEY^CSOME_VALUE'.split(/\^[BC]/)
=> ["SOME_KEY", "SOME_VALUE", "SOME_KEY", "SOME_VALUE"]
If you want replace \B / \C with ,, use gsub instead of split + join:
>> 'SOME_KEY^CSOME_VALUE^BSOME_KEY^CSOME_VALUE'.gsub(/\^[BC]/, ',')
=> "SOME_KEY,SOME_VALUE,SOME_KEY,SOME_VALUE"

Resources