0

I'm trying to write a very simple regex to find all words in a string that start with the symbol @. Then change the word to a link. Like you would see in a Twitter where you can mention other usernames.

So far I have written this

def username_link(s)
  s.gsub(/\@\w+/, "<a href='/username'>username</a>").html_safe
end

I know it's very basic and not much, but I'd rather write it on my own right now, to fully understand it, before searching GitHub to find a more complex one.

What I'm trying to find out is how can I reference that matched word and include it in the place of username. Once I can do that i can easily strip the first character, @, out of it.

Thanks.

Justin
  • 4,922
  • 2
  • 27
  • 69

4 Answers4

1

You can capture using parentheses and backreference with \1 (and \2, and so on):

def username_link(s)
    s.gsub(/@(\w+)/, "<a href='/\\1'>\\1</a>").html_safe
end

See also this answer

Community
  • 1
  • 1
rjz
  • 16,182
  • 3
  • 36
  • 35
0

You should use gsub with back references:

str = "I know it's very basic and not much, but @tim I'd rather write it on my own."

def username_to_link(str)
  str.gsub(/\@(\w+)/, '<a href="\1">@\1</a>')
end

puts username_to_link(str)
#=> I know it's very basic and not much, but <a href="tim">@tim</a> I'd rather write it on my own.
MrPizzaFace
  • 7,807
  • 15
  • 79
  • 123
  • But I'm still trying to display the entire string, just replacing the matched word, with the link. – Justin May 18 '14 at 01:45
  • @Justin good clarification. rjz has the best answer.. Just his gsub is a little fugly. I updated my answer. Cheers. – MrPizzaFace May 18 '14 at 01:59
0

Following Regex should handle corner cases which other answers ignore

def auto_username_link(s)
  s.gsub(/(^|\s)\@(\w+)($|\s)/, "\\1<a href='/\\2'>\\2</a>\\3").html_safe
end

It should ignore strings like "someone@company" or "@username-1" while converting everything like "Hello @username rest of message"

amitamb
  • 1,067
  • 11
  • 22
  • What about: `str = "@tim @tim @tim, @@tim,@tim t@mmy?"`. Arguably there should be at least 4 substitutions in that string. Your regex produces only one substitution and it incorrectly removes a space. And if there should be a substitution at ",@tim", then why not at "@@tim"? Both the characters "," and "@" are non-word characters, so why treat them differently? – 7stud May 18 '14 at 18:53
0

How about this:

def convert_names_to_links(str)
  str = " " + str

  result = str.gsub(
    /
      (?<=\W)   #Look for a non-word character(space/punctuation/etc.) preceeding
      @         #an "@" character, followed by
      (\w+)     #a word character, one or more times
    /xm,        #Standard normalizing flags
    '<a href="/\1">@\1</a>'
  )

  result[1..-1]
end

my_str = "@tim @tim @tim, @@tim,@tim t@mmy?"
puts convert_names_to_links(my_str)

--output:--

@tim @tim @tim, @@tim,@tim t@mmy?

7stud
  • 46,922
  • 14
  • 101
  • 127
  • Note the code will also produce two substitutions here: `"Hi @tim!@tim, you are great!"` and one substitution here `"Hello !@tim."` – 7stud May 18 '14 at 18:59