Ruby (Rails) gsub: передать захваченную строку в метод

Я пытаюсь сопоставить строку как таковую:

text = "This is a #hastag"
raw(
  h(text).gsub(/(?:\B#)(\w*[A-Z]+\w*)/i, embed_hashtag('\1'))
)

def embed_hashtag('data')
  #... some code to turn the captured hashtag string into a link
  #... return the variable that includes the final string
end

Моя проблема в том, что когда я передаю '\1' в свой метод embed_hashtag, который я вызываю с помощью gsub, он просто передает "\1" буквально, а не первую захваченную группу из моего регулярного выражения. Есть ли альтернатива?

К вашему сведению:

  1. Я оборачиваю текст в h, чтобы избежать строк, но затем я встраиваю код в текст, введенный пользователем (т.е. хэштеги), который нужно передать в необработанном виде (отсюда raw).

  2. Важно отделить символ «#» от текста, поэтому я считаю, что мне нужна группа захвата.

  3. Если у вас есть лучший способ сделать это, не стесняйтесь, дайте мне знать, но я все равно хотел бы получить ответ ради ответа на вопрос на случай, если у кого-то еще возникнет этот вопрос.


person user2985898    schedule 15.06.2014    source источник
comment
Вам нужно использовать блочную версию #gsub.. Не ту, которую вы используете.. Это обсуждение поможет вам понять это.   -  person Arup Rakshit    schedule 15.06.2014


Ответы (3)


  • Используйте блочную форму gsub(regex){ $1 } вместо gsub(regex, '\1')
  • Вы также можете упростить регулярное выражение до /\B#(\w+)/i
  • Вы можете не использовать помощника h(), Rails 4 по умолчанию избежит вредоносного ввода.
  • Укажите аргументы метода как embed_hashtag(data) вместо embed_hashtag('data')
  • Вам нужно определить embed_hashtag перед выполнением замены
  • Чтобы построить ссылку, вы можете использовать link_to(text, url)

Это должно помочь:

def embed_hashtag(tag)
  url = 'http://example.com'
  link_to tag, url
end

raw(
  text.gsub(/\B#(\w+)/i){ embed_hashtag($1) }
)
person Patrick Oscity    schedule 15.06.2014
comment
Для альтернативной формы embed_hashtag должен получить x[1] в качестве параметра. - person Casimir et Hippolyte; 15.06.2014
comment
@CasimiretHippolyte извините, вы (почти) правы. Вторая форма не работает, но и ваша тоже не работает, потому что это означает первый символ всего совпадения. Таким образом, единственным решением является использование $1 - person Patrick Oscity; 15.06.2014
comment
и нет возможности передать в функцию первую группу захвата? - person Casimir et Hippolyte; 15.06.2014
comment
Да, есть — это решение, которое я разместил. $& содержит все последнее совпадение; $1 ... $9 содержат группы захвата 1 ... 9 последнего совпадения; $~ содержит объект MatchData и эквивалентен Regexp.last_match. См. документацию: ruby-doc.org /core-2.1.1/String.html#method-i-gsub - person Patrick Oscity; 15.06.2014

Здесь правильным будет использование блока.

Пример:

def embed_hashtag(data)
  puts "#{data}"
end

text = 'This is a #hashtag'
raw(
 h(text).gsub(/\B#(\S+)/) { embed_hashtag($1) }
)
person hwnd    schedule 15.06.2014

Попробуйте ярлык последнего совпадения с регулярным выражением:

=> 'zzzdzz'.gsub(/d/) { puts $~[0] }
=> 'd'
=> "zzzzz"
person Зелёный    schedule 15.06.2014