Ruby regex search and replace array
First of all, I find it strange that you are calling to_s
on value
, since value
is an array which will include array notation when converted to a string, so value.to_s
might look something like ["//subdomain.website.com/folder/image.exte"]
.
You can avoid this by changing your regex to not include a capture group:
/\/\/\w+\.\w+\.\w{2,4}\/\w+\/\w+\.\w{2,4}/
Now to the main part of your question, you should be calling map
on matches
, instead of each
. The map
method will change each element in the array to the result of calling the supplied block with the given element.
Put together it might look like this:
matches = source.scan(/\/\/\w+\.\w+\.\w{2,4}\/\w+\/\w+\.\w{2,4}/).uniq
matches.map { |value| value.gsub(/\/\//, 'https://') }
# => ["https://subdomain.website.com/folder/image.exte"]
How do I replace words in a string based on words in an Array in Ruby?
I suggest using the form of String#gsub that employs a hash for making substitutions.
strings_to_highlight = ['red', 'blue']
First construct the hash.
h = strings_to_highlight.each_with_object({}) do |s,h|
h[s] = "(#{s})"
ss = "#{s[0].swapcase}#{s[1..-1]}"
h[ss] = "(#{ss})"
end
#=> {"red"=>"(red)", "Red"=>"(Red)", "Blue"=>"(Blue)", "blue"=>"(blue)"}
Next define a default proc for it:
h.default_proc = ->(h,k) { k }
so that if h
does not have a key k
, h[k]
returns k
(e.g., h["cat"] #=> "cat"
).
Ready to go!
string = "Roses are Red, violets are blue"
string.gsub(/[[[:alpha:]]]+/, h)
=> "Roses are (Red), violets are (blue)"
This should be relatively efficient as only one pass through the string is needed and hash lookups are very fast.
How can I replace words in a string with elements in an array in ruby?
You can use
h = {"{{width}}"=>10, "{{length}}"=>20}
s = "The dimension of the square is {{width}} and {{length}}"
puts s.gsub(/\{\{(?:width|length)\}\}/, h)
# => The dimension of the square is 10 and 20
See the Ruby demo. Details:
\{\{(?:width|length)\}\}
- a regex that matches\{\{
- a{{
substring(?:width|length)
- a non-capturing group that matcheswidth
orlength
words\}\}
- a}}
substring
gsub
replaces all occurrences in the string withh
- used as the second argument, allows replacing the found matches that are equal to hash keys with the corresponding hash values.
You may use a bit simpler hash definition without {
and }
and then use a capturing group in the regex to match length
or width
. Then you need
h = {"width"=>10, "length"=>20}
s = "The dimension of the square is {{width}} and {{length}}"
puts s.gsub(/\{\{(width|length)\}\}/) { h[Regexp.last_match[1]] }
See this Ruby demo. So, here, (width|length)
is used instead of (?:width|length)
and only Group 1 is used as the key in h[Regexp.last_match[1]]
inside the block.
Return array of replacements from ruby
It is easy to do with pre_match
($`
) and post_match
($'
):
def replace_matches(str, re, repl)
return enum_for(:replace_matches, str, re, repl) unless block_given?
str.scan(re) do
yield "#$`#{repl}#$'"
end
end
str = "foofoofoo"
# block usage
replace_matches(str, /foo/, "bar") { |x| puts x }
# enum usage
puts replace_matches(str, /foo/, "bar").to_a
EDIT: If you have overlapping matches, then it becomes harder, as regular expressions aren't really equipped to deal with it. So you can do it like this:
def replace_matches(str, re, repl)
return enum_for(:replace_matches, str, re, repl) unless block_given?
re = /(?=(?<pattern>#{re}))/
str.scan(re) do
pattern_start = $~.begin(0)
pattern_end = pattern_start + $~[:pattern].length
yield str[0 ... pattern_start] + repl + str[pattern_end .. -1]
end
end
str = "oooo"
replace_matches(str, /oo/, "x") { |x| puts x }
Here we abuse positive lookahead, which are 0-width, so we can get overlapping matches. However, we also need to know how many characters we matched, which we can't do as before now that match is 0-width, so we'll make a new capture of the contents of the lookahead, and calculate the new width from that.
(Disclaimer: it will still only match once per character; if you want to consider multiple possibilities at each character, like in your /f|o|fo/
case, it complicates things yet more.)
EDIT: A bit of a tweak and we can even support proper gsub-like behaviour:
def replace_matches(str, re, repl)
return enum_for(:replace_matches, str, re, repl) unless block_given?
new_re = /(?=(?<pattern>#{re}))/
str.scan(new_re) do
pattern_start = $~.begin(0)
pattern_end = pattern_start + $~[:pattern].length
new_repl = str[pattern_start ... pattern_end].gsub(re, repl)
yield str[0 ... pattern_start] + new_repl + str[pattern_end .. -1]
end
end
str = "abcd"
replace_matches(str, /(?<first>\w)(?<second>\w)/, '\k<second>\k<first>').to_a
# => ["bacd", "acbd", "abdc"]
(Disclaimer: the last snippet can't handle cases where the pattern uses lookbehind or lookahead to check outside the match region.)
How to replace the captured group in Ruby
sub!
will replace the first match every iteration on part_number
which is outside of the loop.
What happens is:
In the first iteration, the first A will be replaced with A giving the same
R1L16SB#AA
^
In the second iteration, the first A will be replaced by B giving
R1L16SB#BA
^
In the third iteration, the first B will be replaced by C giving
R1L16SC#BA
^
One way to get the desired output is to put part_number = 'R1L16SB#AA'
inside the loop.
Ruby demo
Ruby: Gsub - multiple string replacements in a single line [in an array]
Looking at String#sub it seems there are many ways to do what you want:
One approach can be to use a hash as second parameter
def cleansed_log_line(line)
replacement_rules = {
'alex' => '',
'OUT: ' => 'OUT ',
'IN: ' => 'IN '
}
matcher = /#{replacement_rules.keys.join('|')}/
line.gsub(matcher, replacement_rules)
endAnother approach can be to to use block form
def cleansed_log_line(line)
replacement_rules = {
'alex' => '',
'OUT: ' => 'OUT ',
'IN: ' => 'IN '
}
matcher = /#{replacement_rules.keys.join('|')}/
line.gsub(matcher) do |match|
replacement_rules[match] || match
end
endAnother not so good implementation
def cleansed_log_line(line)
replacement_rules = {
/alex/ => '',
'OUT: ' => 'OUT ',
'IN: ' => 'IN '
}
replacement_rules.each do |match, replacement|
line = line.gsub(match, replacement)
end
line
end
Hashes and RegEx are nothing to worry about. This function can cleanse any line passed to it and would return a cleansed line.
Change all array elements which include a specific string
It's almost as you typed your title:
array.select {|s| s.include? "good"}
Here's the doc: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-select
replace values of an array within range
You can use Array#fill
method.
array.fill(7, 8..100)
Related Topics
Ruby - How to Retrieve Sum in Array Group by Multiple Keys with Condition Max
How to Verify Pacts Against an API That Requires an Auth Token
Utc Time Resets to 2000-01-01 (Ruby). How to Prevent the Time from Resetting
Print Unicode Escape Codes from Variable
Can't Run a Ruby Hello World Application in Aptana
How to Ignore Irrelevant Methods When Profiling Ruby Applications
Instagram Ruby Gem - Unable to Reach Callback Url
Enter & Ioerror: Byte Oriented Read for Character Buffered Io
Rails - How to Add Contacts to Sendgrid Marketing Campaigns via API
My Classes Can't Use Shoes Methods Like Para
Rails 3 + Daemons Gem: Exception When Querying Model
Using --No-Rdoc and --No-Ri with Bundler
How to Enable Auto Completion in Ruby's Irb
Why Must I Explicitly Call Self on Accessor When Using the Array Union Operator |= in Ruby