Как преобразовать упоминания в ссылки с помощью регулярного выражения

Помогите, пожалуйста, разобраться с регулярными выражениями. Нужно, чтобы все слова, начинающиеся на @, делались ссылкой.

Получилось такое регулярное выражение:

$text = preg_replace('/\s@(.*)[^\s\,\.]+/ui', ' <a href="https://domen.ru/$1">@$1</a>', $text);

Однако если в тексте встречаются два пробела, то всё ломается. Например при обработке

@Tript  по поводу заказа

почему-то выдаётся

<a href=\"https://domen.ru/Tript  по поводу заказќ">@Tript  по поводу заказм/a>

Если один пробел, то все работает нормально, хотя + — это же квантификатор, обозначающий одно или более вхождений.


Ответы (2 шт):

Автор решения: web555
preg_replace('~(?<!\S)@([^\s,.]+)~u', '<a href="https://domen.ru/$1">$0</a>', $text) 

работает. Спасибо Wiktor Stribiżew

→ Ссылка
Автор решения: Wiktor Stribiżew

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

$text = preg_replace('~(?<!\S)@([^\s,.]+)~u', '<a href="https://domen.ru/$1">$0</a>', $text);

Модификатор u необходим, так как он включает опцию (*UTF) библиотеки PCRE, благодаря которой строка обрабатывается как массив символов Юникода, а не обчных байтов.

См. пример работы выражения.

Значение выражения:

  • (?<!\S) - блок предварительного просмотра назад, требует отсутствия непробельного символа сразу перед текущей позицией в строке
  • @ - символ @
  • ([^\s,.]+) - Захватывающая подмаска №1: один и более пробельных символов (\s), запятых (,) и точек (.).

В шаблоне замены $0 соответствует всему совпадению, а $1 — только значению первой подмаски.

См. пример работы кода на PHP:

<?php
 
$text = '@Tript по поводу заказа';
$text = preg_replace('~(?<!\S)@([^\s,.]+)~u', '<a href="https://' . 'domen.ru/$1">$0</a>', $text);
echo $text;
// -> <a href="https://domen.ru/Tript">@Tript</a> по поводу заказа
→ Ссылка