Regex для соответствия хэштегам в предложении с помощью ruby

Я пытаюсь извлечь хэштеги для простого проекта колледжа, используя ruby on rails. Я столкнулся с проблемой с тегами, которые включают только цифры и теги без пространства.

text = "Pack my #box with #5 dozen liquor.#jugs link.com/liquor#jugs #2good #first#second"

регулярное выражение у меня есть /(?:^|s)#(w+)/i (источник)

это регулярное выражение возвращает #["box", "5", "2good", "first"]

как убедиться, что он возвращает только #["box", "2good"] и игнорировать остальные, поскольку они не являются "реальным" хэштеги?

3 ответов


можете ли вы попробовать это регулярное выражение:

/(?:^|\s)(?:(?:#\d+?)|(#\w+?))\s/i

обновление 1:
Есть несколько случаев, когда вышеуказанное регулярное выражение не будет соответствовать: #blah23blah и #23blah23. Следовательно, изменено регулярное выражение, чтобы позаботиться обо всех случаях.

регулярное выражение:

/(?:\s|^)(?:#(?!\d+(?:\s|$)))(\w+)(?=\s|$)/i

поломки:

  • (?:\s|^) --соответствует предыдущему пробелу или началу строки. Не захватите матч.
  • # --совпадает хэш но не захватывает.
  • (?!\d+(?:\s|$))) --отрицательный Lookahead, чтобы избежать всех числовых символов между # и пробелом (или концом строки)
  • (\w+) --соответствует и захватывает все символы слова
  • (?=\s|$) --положительный Lookahead для обеспечения следующих космоса или конца линия. Это необходимо, чтобы убедиться, что он соответствует соседним допустимым хэш-тегам.

образец текста изменен, чтобы захватить большинство случаев:

#бла Пак мой # коробка с #5 дюжиной #good2 # 3good ликер.#кувшины link.com/liquor#jugs #mkvef214asdwq sd #3e4 flsd #2good #первый#второй #3

матчи:

матч 1: мля
Матч 2: Поле
Матч 3: good2
Матч 4: 3good
Матч 5: mkvef214asdwq
Матч 6: 3e4
Матч 7: сайту 2good

Rubular link

обновление 2:

исключить слова начиная или заканчивая подчеркиванием, просто включите свои исключения в отрицательный lookahead следующим образом:

/(?:\s|^)(?:#(?!(?:\d+|\w+?_|_\w+?)(?:\s|$)))(\w+)(?=\s|$)/i

образца, regex и матчи записываются в этот Rubular link


Я бы об этом так:

text.scan(/ #[[:digit:]]?[[:alpha:]]+ /).map{ |s| s.strip[1..-1] }

возвращает:

[
    [0] "box",
    [1] "2good"
]

Я не пытаюсь делать все в регулярном выражении. Я предпочитаю держать их как можно проще, а затем фильтровать и калечить, как только я получу основные данные. Мое рассуждение заключается в том, что регулярное выражение тем сложнее поддерживать, чем сложнее оно становится. Я бы предпочел потратить свое время на что-то другое, чем поддерживать шаблоны.


попробуйте это:

/\s#([[\d]]?[[a-z]]+\s)/i

выход:

1.9.3-p194 :010 > text = "Pack my #box with #5 dozen liquor.#jugs link.com/liquor#jugs #2good #first#second"
 => "Pack my #box with #5 dozen liquor.#jugs link.com/liquor#jugs #2good #first#second" 
1.9.3-p194 :011 > puts text.scan /\s#([[\d]]?[[a-z]]+\s)/i 
box 
2good 
 => nil