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.
Related
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('')
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
I have a string called "example", like this:
192.168.1.40,8.8.8.8,12.34.45.56,408,-,1812
192.168.1.128,192.168.101.222,12.34.45.56,384,-,1807
and I would like to obtain this output:
{"string1":"192.168.1.40","string2":"8.8.8.8",“string3":“12.34.45.56”,“string4”:408,“string5”:“-”,"string6":1812}
{"string1":"192.168.1.128","string2":"192.168.101.222",“string3":“12.34.45.56”,“string4”:384,“string5”:“-”,"string6":1807}
I did this:
example = example.gsub("\n","}\n{\"string1\": \"")
example = example.insert(0, "{\"string1\": \"")
example = example.concat("}")
and I obtained:
{"string1":"192.168.1.40,8.8.8.8,12.34.45.56,408,-,1812}
{"string1":"192.168.1.128,192.168.101.222,12.34.45.56,384,-,1807}
but I don't know how can I do the others changes. Thanks!!
Well, to get it as a ruby hash, which you can output as json or whatever you need:
out = {}
your_input_data.split(",").each_with_index { |val, i| out["string#{i}"] = val }
(but you would need to do this for each line: input.lines.each { |line| ... do the above here } - but I am not clear - do you want a list of maps?)
I made the assumption that you didn't want values that were just numbers to be double-quoted.
DATA.each_line do |line|
l = line.chomp.split(',').map.with_index do |v, i|
v = v =~ /^\d+$/ ? v : "\"#{v}\""
"\"string#{i+1}\":#{v}"
end
print "{", l.join(','), "}\n"
end
__END__
192.168.1.40,8.8.8.8,12.34.45.56,408,-,1812
192.168.1.128,192.168.101.222,12.34.45.56,384,-,1807
Result:
{"string1":"192.168.1.40","string2":"8.8.8.8","string3":"12.34.45.56","string4":408,"string5":"-","string6":1812}
{"string1":"192.168.1.128","string2":"192.168.101.222","string3":"12.34.45.56","string4":384,"string5":"-","string6":1807}
It seems from the code you wrote that you are looking for a single string as output rather than a more elaborate Ruby data structure or output to a printed stream.
This is working for me:
example = '192.168.1.40,8.8.8.8,12.34.45.56,408,-,1812
192.168.1.128,192.168.101.222,12.34.45.56,384,-,1807'
result = example.split("\n").map do |line|
n = 0
line.split(',').map{|s| %Q|"string#{n+=1}":"#{s}"|}.join(',')
end.map{|c| "{#{c}}"}.join("\n")
puts result
{"string1":"192.168.1.40","string2":"8.8.8.8","string3":"12.34.45.56","string4":"408","string5":"-","string6":"1812"}
{"string1":" 192.168.1.128","string2":"192.168.101.222","string3":"12.34.45.56","string4":"384","string5":"-","string6":"1807"}
This splits into lines then splits each line into separate strings, then concatenates each string with its JSON key and finally reassembles with join first with commas and then with newline. If you'd rathet have lists than reassembled strings, just omit the respective join.
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.
Is there any way to create the regex /func:\[sync\] displayPTS/ from string func:[sync] displayPTS?
The story behind this question is that I have serval string pattens to search against in a text file and I don't want to write the same thing again and again.
File.open($f).readlines.reject {|l| not l =~ /"#{string1}"/}
File.open($f).readlines.reject {|l| not l =~ /"#{string2}"/}
Instead , I want to have a function to do the job:
def filter string
#build the reg pattern from string
File.open($f).readlines.reject {|l| not l =~ pattern}
end
filter string1
filter string2
s = "func:[sync] displayPTS"
# => "func:[sync] displayPTS"
r = Regexp.new(s)
# => /func:[sync] displayPTS/
r = Regexp.new(Regexp.escape(s))
# => /func:\[sync\]\ displayPTS/
I like Bob's answer, but just to save the time on your keyboard:
string = 'func:\[sync] displayPTS'
/#{string}/
If the strings are just strings, you can combine them into one regular expression, like so:
targets = [
"string1",
"string2",
].collect do |s|
Regexp.escape(s)
end.join('|')
targets = Regexp.new(targets)
And then:
lines = File.readlines('/tmp/bar').reject do |line|
line !~ target
end
s !~ regexp is equivalent to not s =~ regexp, but easier to read.
Avoid using File.open without closing the file. The file will remain open until the discarded file object is garbage collected, which could be long enough that your program will run out of file handles. If you need to do more than just read the lines, then:
File.open(path) do |file|
# do stuff with file
end
Ruby will close the file at the end of the block.
You might also consider whether using find_all and a positive match would be easier to read than reject and a negative match. The fewer negatives the reader's mind has to go through, the clearer the code:
lines = File.readlines('/tmp/bar').find_all do |line|
line =~ target
end
How about using %r{}:
my_regex = "func:[sync] displayPTS"
File.open($f).readlines.reject { |l| not l =~ %r{#{my_regex}} }