Регулярное выражение python игнорирует слово, за которым следует данный символ

#python #regex

Вопрос:

У меня есть регулярное (?<=^|(?<=[^a-zA-Z0-9-_.]))@([A-Za-z] [A-Za-z0-9-_] )(?!w) выражение .

Учитывая строку @first@nope @second@Hello @my-friend, email@ whats.up@example.com @friend , что я могу сделать, чтобы исключить строки @first , и @second поскольку они сами по себе не являются целыми словами ? Другими словами, исключите их, так как за ними следует @ .

Комментарии:

1. ДА. Я хочу получить ['my-friend', 'friend']

Ответ №1:

Вы можете использовать

 (?<![a-zA-Z0-9_.-])@(?=([A-Za-z] [A-Za-z0-9_-]*))1(?![@w])
(?a)(?<![w.-])@(?=([A-Za-z][w-]*))1(?![@w])
 

Смотрите демонстрацию регулярных выражений. Подробные сведения:

  • (?<![a-zA-Z0-9_.-]) — отрицательный внешний вид, соответствующий местоположению, которому непосредственно не предшествуют цифры ASCII , буквы _ . и -
  • @ — а @ чар
  • (?=([A-Za-z] [A-Za-z0-9_-]*)) — положительный внешний вид с группой захвата внутри, которая захватывает одну или несколько букв ASCII, а затем ноль или более букв ASCII, цифр - или _ символов
  • 1 — значение группы 1 (обратные ссылки являются атомарными, возврат через них не допускается)
  • (?![@w]) — отрицательный указатель, который не соответствует, если есть символ слова (буква, цифра или _ ) или @ символ непосредственно справа от текущего местоположения.

Обратите внимание, что я ставлю дефисы в конце классов персонажей, это лучшая практика.

В (?a)(?<![w.-])@(?=([A-Za-z][w-]*))1(?![@w]) альтернативе используются классы сокращенных символов и (?a) встроенный модификатор (эквивалент re.ASCII / re.A w ), который соответствует только символам ASCII (как в оригинальной версии). Удалите (?a) , если вы планируете сопоставлять какие-либо цифры/буквы Юникода.

Комментарии:

1. Спасибо, это работает. Можете ли вы объяснить, чем он отличается от моего ?

2. @ImportError Два основных отличия: 1) окончательный внешний вид не работает, если справа есть a @ , 2) основная часть выполнена атомарной , так что окончательный внешний вид был запущен только один раз, и если он не сработает, это не может привести к возврату в основную часть шаблона. Первое, что бросается в глаза, — это просто усовершенствование.

3. Я думаю (?<![w.-])@(?=([A-Za-z] [w-]*))1(?![@w]) , это тоже сработало бы?

4. @rv.kvetch Я обновил ответ.

5.@rv.kvetch Просто хотел объяснить, почему используется атомарный подход: в @my-friend-@friend строке не должно быть найдено совпадения, так как - это часть слова, которое вы хотите извлечь , и если вы удалите атомарный эквивалент и используете (?<![w.-])@([A-Za-z][w-]*)(?![@w]) , вы получите @my-friend совпадение.

Ответ №2:

Другой вариант-указать границу пробела слева и не указывать символ слова или знак @ справа.

 (?<!S)@([A-Za-z] [w-] )(?![@w])
 

Шаблон совпадает:

  • (?<!S) Отрицательный взгляд назад, не утверждайте, что символ без пробелов слева
  • @ Совпадение буквально
  • ([A-Za-z] [w-] ) Захватите группу 1, сопоставьте 1 символов A-Za-z, а затем 1 словесных символов или -
  • (?![@w]) Отрицательный внешний вид, утверждение не @ или символ слова справа

Демонстрация регулярных выражений

Или сопоставьте границу без слов B перед @ вместо поиска.

 B@([A-Za-z] [w-] )(?![@w])
 

Демонстрация регулярных выражений