How to Replace a Pattern in Ruby Array

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 matches width or length words
    • \}\} - a }} substring
  • gsub replaces all occurrences in the string with
  • h - 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:

  1. 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)
    end
  2. Another 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
    end
  3. Another 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



Leave a reply



Submit