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 
обновление 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
