Regex to replace directory to get only filenames in array - ruby

I have the array containing several paths. I want to store in an array only the file names.
arr = ["/This/is/MyFirst/Path/file1","/This/is/MySecond/Path/file2","/This/is/MyThird/Path/file3"]
I'm trying to remove all except the filename with gsub, but I'm not sure why the regex I'm using is not working, since
when I run the code below, is not removing anything.
arr.each {|f| puts f.gsub( /\/\(.+\)*/, '')}
This is my test:
irb(main):172:0* arr = ["/This/is/MyFirst/Path/file1","/This/is/MySecond/Path/file2","/This/is/MyThird/Path/file3"]
=> ["/This/is/MyFirst/Path/file1", "/This/is/MySecond/Path/file2", "/This/is/MyThird/Path/file3"]
irb(main):173:0> arr.each {|f| puts f.gsub( /\/\(.+\)*/, '')}
/This/is/MyFirst/Path/file1
/This/is/MySecond/Path/file2
/This/is/MyThird/Path/file3
=> ["/This/is/MyFirst/Path/file1", "/This/is/MySecond/Path/file2", "/This/is/MyThird/Path/file3"]
irb(main):174:0>
Thanks in advance for any help.

Why not ?
arr.map { |file_path| File.basename(file_path) }

You should not escape the parentheses. Otherwise they are treated as characters. Try the following
arr.each {|f| puts f.gsub( /\/(.+)*/, '')}

Related

Checking for words inside folders/subfolders and files

I am having issue with regular expressions. So basically I have a folder and this folder contains sub folders as well as files. I have to check for certain words in those folders. The words I have to check for are located in a file called words.txt file.
This is the code that I have so far in Ruby:
def check_words
array_of_words = File.readlines('words.txt')
re = Regexp.union(array_of_words)
new_array_of_words = [/\b(?:#{re.source})\b/]
Dir['source_test/**/*'].select{|f| File.file?(f) }.each do |filepath|
new_array_of_words.each do |word|
puts File.foreach(filepath).include?(word)
end
end
end
When I execute this code I keep getting false even though some of the files inside the folders/subfolders contains those words.
new_array_of_words is a single regex, and the include? methods acts on strings (and it doesn't make much sense to iterate over a single regex anyway).
You can keep using the regex, but use regex methods instead.
You can also fix your current code as follows:
arr = File.readlines('/home/afifit/Tests/word.txt')
arr.select { |e| e.strip! }
Dir['yourdir/*'].select{|f| File.file?(f) }.each do |filepath|
arr.each do |word|
puts File.foreach(filepath).include?(word)
end
end
I also used strip to remove any unnecessary whitespaces and newlines.

Ruby regex method

I need to get the expected output in ruby by using any method like scan or match.
Input string:
"http://test.com?t&r12=1&r122=1&r1=1&r124=1"
"http://test.com?t&r12=1&r124=1"
Expected:
r12=1,r122=1, r1=1, r124=1
r12=1,r124=1
How can I get the expected output using regex?
Use regex /r\d+=\d+/:
"http://test.com?t&r12=1&r122=1&r1=1&r124=1".scan(/r\d+=\d+/)
# => ["r12=1", "r122=1", "r1=1", "r124=1"]
"http://test.com?t&r12=1&r124=1".scan(/r\d+=\d+/)
# => ["r12=1", "r124=1"]
You can use join to get a string output. Here:
"http://test.com?t&r12=1&r122=1&r1=1&r124=1".scan(/r\d+=\d+/).join(',')
# => "r12=1,r122=1,r1=1,r124=1"
Update
If the URL contains other parameters that may include r in end, the regex can be made stricter:
a = []
"http://test.com?r1=2&r12=1&r122=1&r1=1&r124=1&ar1=2&tr2=3&xy4=5".scan(/(&|\?)(r+\d+=\d+)/) {|x,y| a << y}
a.join(',')
# => "r12=1,r122=1,r1=1,r124=1"
While input strings are urls with queries, I would safeguard myself from the false positives:
input = "http://test.com?t&r12=1&r122=1&r1=1&r124=1"
query_params = input.split('?').last.split('&')
#⇒ ["t", "r12=1", "r122=1", "r1=1", "r124=1"]
r_params = query_params.select { |e| e =~ /\Ar\d+=\d+/ }
#⇒ ["r12=1", "r122=1", "r1=1", "r124=1"]
r_params.join(',')
#⇒ "r12=1,r122=1,r1=1,r124=1"
It’s safer than just scan the original input for any regexp.
If you really need to do it with regex correctly, you'll need to use a regex like this:
puts "http://test.com?t&r12=1&r122=1&r1=1&r124=1".scan(/(?:http.*?\?t|(?<!^)\G)\&*(\br\d*=\d*)(?=.*$)/i).join(',')
puts "http://test.com?t&r12=1&r124=1".scan(/(?:http.*?\?t|(?<!^)\G)\&*(\br\d*=\d*)(?=.*$)/i).join(',')
Sample program output:
r12=1,r122=1,r1=1,r124=1
r12=1,r124=1

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...

How do I remove a substring after a certain character in a string using Ruby?

How do I remove a substring after a certain character in a string using Ruby?
new_str = str.slice(0..(str.index('blah')))
I find that "Part1?Part2".split('?')[0] is easier to read.
I'm surprised nobody suggested to use 'gsub'
irb> "truncate".gsub(/a.*/, 'a')
=> "trunca"
The bang version of gsub can be used to modify the string.
str = "Hello World"
stopchar = 'W'
str.sub /#{stopchar}.+/, stopchar
#=> "Hello W"
A special case is if you have multiple occurrences of the same character and you want to delete from the last occurrence to the end (not the first one).
Following what Jacob suggested, you just have to use rindex instead of index as rindex gets the index of the character in the string but starting from the end.
Something like this:
str = '/path/to/some_file'
puts str.slice(0, str.index('/')) # => ""
puts str.slice(0, str.rindex('/')) # => "/path/to"
We can also use partition and rpartitiondepending on whether we want to use the first or last instance of the specified character:
string = "abc-123-xyz"
last_char = "-"
string.partition(last_char)[0..1].join #=> "abc-"
string.rpartition(last_char)[0..1].join #=> "abc-123-"

Resources