#php #html
#php #HTML
Вопрос:
Я хотел знать , возможно ли создать систему упоминания PHP с именами пользователей через пробел ? Я попробовал это
preg_replace_callback('#@([a-zA-Z0-9] )#', 'mentionUser', htmlspecialchars_decode($r['content']))
Моя функция:
function mentionUser($matches) {
global $db;
$req = $db->prepare('SELECT id FROM members WHERE username = ?');
$req->execute(array($matches[1]));
if($req->rowCount() == 1) {
$idUser = $req->fetch()['id'];
return '<a class="mention" href="members/profile.php?id='.$idUser.'">'.$matches[0].'</a>';
}
return $matches[0];
Это работает, но не для имен пользователей с пробелом…
Я попытался добавить s
, это работает, но не очень хорошо, preg_replace_callback определяет имя пользователя и другие части сообщения, поэтому упоминание не появляется…
Есть ли какое-нибудь решение?
Спасибо!
Комментарии:
1. Можете ли вы
str_replace()
для каждого[SPACE]
указать заполнитель типа, а затем
str_replace
вернуться обратно, когда вернете разметку?2. Вы хотите ограничить ее только одним пробелом, поэтому я думаю,
@(w (?:sw )?)
это то, что вы ищете? Я переключился на символьный классw
, который такой же, как у вас, но также допускает подчеркивание, вы могли бы легко поменять местами обратно3. Решение Криса Хааса работает, но есть проблема, если есть «@Mention [некоторый текст]», упоминание не работает…
4. Я сказал это для его комментария, а не для его ответа, потому что ответ работает так, как я хотел
Ответ №1:
Я знаю, вы сказали, что просто удалили возможность добавлять пробел, но я все равно хотел опубликовать решение. Для ясности, я не обязательно думаю, что вам следует использовать этот код, потому что, вероятно, так проще упростить задачу, но я думаю, что он все равно должен работать.
Ваша основная проблема заключается в том, что почти каждое упоминание требует двух поисковых запросов, потому что @bob johnson went to the store
это может быть либо bob
, либо bob johnson
, и нет способа определить это, не обращаясь к базам данных. К счастью, кэширование значительно уменьшит эту проблему.
Ниже приведен некоторый код, который обычно делает то, что вы ищете. Я создал поддельную базу данных, используя только массив для наглядности и воспроизводимости. Надеюсь, встроенные комментарии к коду должны иметь смысл.
function mentionUser($matches)
{
// This is our "database" of users
$users = [
'bob johnson',
'edward',
];
// First, grab the full match which might be 'name' or 'name name'
$fullMatch = $matches['username'];
// Create a search array where the key is the search term and the value is whether or not
// the search term is a subset of the value found in the regex
$names = [$fullMatch => false];
// Next split on the space. If there isn't one, we'll have an array with just a single item
$maybeTwoParts = explode(' ', $fullMatch);
// Basically, if the string contained a space, also search only for the first item before the space,
// and flag that we're using a subset
if (count($maybeTwoParts) > 1) {
$names[array_shift($maybeTwoParts)] = true;
}
foreach ($names as $name => $isSubset) {
// Search our "database"
if (in_array($name, $users, true)) {
// If it was found, wrap in HTML
$ret = '<span>@' . $name . '</span>';
// If we're in a subset, we need to append back on the remaining string, joined with a space
if ($isSubset) {
$ret .= ' ' . array_shift($maybeTwoParts);
}
return $ret;
}
}
// Nothing was found, return what was passed in
return '@' . $fullMatch;
}
// Our search pattern with an explicitly named capture
$pattern = '#@(?<username>w (?:sw )?)#';
// Three tests
assert('hello <span>@bob johnson</span> test' === preg_replace_callback($pattern, 'mentionUser', 'hello @bob johnson test'));
assert('hello <span>@edward</span> test' === preg_replace_callback($pattern, 'mentionUser', 'hello @edward test'));
assert('hello @sally smith test' === preg_replace_callback($pattern, 'mentionUser', 'hello @sally smith test'));
Комментарии:
1. С помощью этого можно обновить упоминание, если пользователь изменит свое имя, пожалуйста?
2. Как только вы найдете @-упоминание, вы должны пометить его чем-то вроде
data
атрибута идентификатора пользователя, например,<a data-user-id="1234">user</a>
поскольку вы это уже знаете. При рендеринге страницы вам нужно будет решить, какая логика работает для вашего бизнес-примера. Например, если я изменю свое отображаемое имя на этом сайте сегодня, должны ли измениться и мои упоминания за более чем 10 лет? Пока ссылка все еще находит меня, лично меня устраивает, что мое имя для упоминания остается старым. Для меня @-упоминание — это момент времени и исторический, на который не повлияют будущие изменения.
Ответ №2:
Попробуйте это регулярное выражение:
/@[a-zA-Z0-9] ( *[a-zA-Z0-9] )*/g
Сначала он найдет знак at, а затем попытается найти одну или несколько букв или цифр. Она попытается найти ноль или более внутренних пробелов и ноль или более букв и цифр, следующих за этим.
Я предполагаю, что имя пользователя содержит только A-Za-z0-9 и пробел.
Комментарии:
1. Хммм, когда я пытаюсь это сделать, ответы не отображаются
2. @Lunyx Вам следует указать больше контекста, поскольку «ответы не отображаются» не дает мне никакого представления о том, что происходит в вашем коде.