Search code examples
ruby-on-railsrubystringreplacegsub

Ruby gsub capturing groups


This is my input (stored in content variable):

<p>some text</p>
[image=content_001]Some alt/legend text[/image]
<div>some div</div>

This is my desired output:

<p>some text</p>
<div>
  <img src="blog/content/content_001.webp" alt="Some alt/legend text" />
  <p>Some alt/legend text</p>
</div>
<div>some div</div>

This where I am so far:

  r = %r{\[image=(.*?)\](.*?)\[/image\]}

  content.gsub(r, content_tag(:div) do
    image_tag('blog/content/?.webp', alt: '?') +
    content_tag(:p, '?')
  end).html_safe

By what should I replace the '?' to use the captured groups?


Solution

  • Based on your comments you want to replace the "exact string" [image=?1]?2[/image] so that the output is "<div>#{image_tag(?1, alt: ?2)} <p>#{?2}</p><div>".

    In that case the following should work for you:

    r = /\[image=(.*?)\](.*?)\[\/image\]/
    str =<<DOC
    I have [image=?1]?2[/image] 
    with many other [image=?3]?4[/image] 
    and I need to replace the [image=?1]?2[/image] 
    with other formatting
    DOC
    
    result = str.gsub(r,'<div>#{image_tag(\1, alt: \2} <p>#{\2}</p></div>')
    
    puts result
    #=> I have <div>#{image_tag(?1, alt: ?2} <p>#{?2}</p></div>
    # with many other <div>#{image_tag(?3, alt: ?4} <p>#{?4}</p></div>
    # and I need to replace the <div>#{image_tag(?1, alt: ?2} <p>#{?2}</p></div>
    # with other formatting
    

    UPDATE Based on the context change to the question you need to use the block form of gsub and the "special variables" $1 and $2, which refer to capture groups 1 and 2 respectively (See globals for more information).

    r = /\[image=(.*?)\](.*?)\[\/image\]/
    str =<<DOC
    <p>some text</p>
    [image=content_001]Some alt/legend text[/image]
    <div>some div</div>
    DOC
    
    result = str.gsub(r) do
      content_tag(:div) do
        # had to create an img tag rather than the image_tag helper 
        # to avoid appending /images to the src path
        tag("img",src: "blog/content/#{$1}.webp", alt: $2) +
        content_tag(:p, $2)
      end
    end.html_safe
    
    puts result
    #=> <p>some text</p>
    # <div><img src="blog/content/content_001.webp" alt="Some alt/legend text" /><p>Some alt/legend text</p></div>
    # <div>some div</div>