Regex: сопоставлять слова, заключенные в подчеркивания, если они не начинаются с @ / # - PullRequest
2 голосов
/ 18 марта 2020

Я пытаюсь обойти эту ошибку в Tiptap (редактор WYSIWYG для Vue), передавая пользовательское регулярное выражение, чтобы регулярное выражение, которое идентифицировало нотацию курсива в Markdown (_value_) не будет применяться к строкам, которые начинаются с @ или #, например, #some_tag_value не будет преобразовано в значение # some tag .

Это мое регулярное выражение до сих пор - /(^|[^@#_\w])(?:\w?)(_([^_]+)_)/g
Редактировать: новое регулярное выражение с помощью @ Wiktor Stribiżew /(^|[^@#_\w])(_([^_]+)_)/g

Несмотря на то, что оно удовлетворяет большинству распространенных случаев, в настоящее время оно по-прежнему завершается ошибкой, когда подчеркивания находятся в середине слова, например, ant_farm_ должен соответствовать (муравей ферма )

Я также предоставил здесь несколько случаев "должно совпадать" и "не совпадать" https://regexr.com/50ibf для упрощения тестирования

Должно совпадать (между подчеркиванием)

_italic text here_
police_woman_
_fire_fighter
a thousand _words_
_brunch_ on a Sunday

Не должно совпадать

@ta_g_
__value__
#some_tag_value
@some_value_here
@some_tag_
#some_val_
#_hello_

Ответы [ 3 ]

2 голосов
/ 18 марта 2020

Вы можете использовать следующий шаблон:

(?:^|\s)[^@#\s_]*(_([^_]+)_)

См. Демоверсию regex

Подробности

  • (?:^|\s) - начало строки или пробела
  • [^@#\s_]* - 0 или более символов, отличных от @, #, _ и пробела
  • (_([^_]+)_) - группа 1: _, 1+ символов, отличных от _ (включены в группу 2), а затем _.
2 голосов
/ 18 марта 2020

Для науки это чудовище работает в Chrome (и Node.js).

let text = `
<strong>Should match</strong> (between underscores)

_italic text here_
police_woman_
_fire_fighter
a thousand _words_
_brunch_ on a Sunday

<strong>Should not match</strong>

@ta_g_
__value__
#some_tag_value
@some_value_here
@some_tag_
#some_val_
#_hello_
`;

let re = /(?<=(?:\s|^)(?![@#])[^_\n]*)_([^_]+)_/g;
document.querySelector('div').innerHTML = text.replace(re, '<em>$1</em>');
div { white-space: pre; }
<div/>

Захватывает _something_ как полное совпадение и something как 1-ю группу захвата (для удаления подчеркиваний). Вы не можете захватить только something, потому что тогда вы потеряете способность определять, что находится внутри подчеркивания, а что снаружи (попробуйте с помощью (?<=(?:\s|^)(?![@#])[^_\n]*_)([^_]+)(?=_)).

Есть две вещи, которые мешают этому универсально применим:

  • Предварительные просмотры не поддерживаются во всех JavaScript двигателях
  • Большинство механизмов регулярных выражений не поддерживают предварительные просмотры переменной длины

РЕДАКТИРОВАТЬ: Это немного сильнее, и должно позволить вам дополнительно match_this_and_that_ but not @match_this_and_that правильно:

/(?<=(?:\s|^)(?![@#])(?!__)\S*)_([^_]+)_/

Объяснение:

_([^_]+)_    Match non-underscory bit between two underscores
(?<=...)     that is preceded by
(?:\s|^)     either a whitespace or a start of a line/string
             (i.e. a proper word boundary, since we can't use `\b`)
\S*          and then some non-space characters
(?![@#])     that don't start with `@`, `#`,
(?!__)       or `__`.

regex101 demo

0 голосов
/ 18 марта 2020

Вот что-то, оно не так компактно, как другие ответы, но я думаю, что легче понять, что происходит. Группа совпадений \3 - это то, что вы хотите.

Требуется многострочный флаг

^([a-zA-Z\s]+|_)(([a-zA-Z\s]+)_)+?[a-zA-Z\s]*?$
  • ^ - соответствует началу строки
  • ([a-zA-Z\s]+|_) - несколько слов или _
  • (([a-zA-Z\s]+)_)+? - несколько слов, за которыми следует _ хотя бы один раз, но минимальное совпадение.
  • [a-zA-Z\s]*? - любые заключительные слова
  • $ - конец строки

В итоге, разбивка вещей для соответствия одному из

  • _<words>_
  • <words>_<words>_
  • <words>_<words>_<words>
  • _<words>_<words>
...