我在评论网application上工作,我想解析用户提及(@user)作为链接。以下是我到目前为止的情况:
$text = "@user is not @user1 but @user3 is @user4";
$pattern = "/\@(\w+)/";
preg_match_all($pattern,$text,$matches);
if($matches){
$sql = "SELECT *
FROM users
WHERE username IN ('" .implode("','",$matches[1]). "')
ORDER BY LENGTH(username) DESC";
$users = $this->getQuery($sql);
foreach($users as $i=>$u){
$text = str_replace("@{$u['username']}",
"<a href='#' class='ct-userLink' rel='{$u['user_id']}'>@{$u['username']}</a> ", $text);
}
$echo $text;
}
问题是用户链接正在重叠:
<a rel="11327" class="ct-userLink" href="#">
<a rel="21327" class="ct-userLink" href="#">@user</a>1
</a>
如何避免链接重叠?
由于选择了答案,这就是我的新foreach循环的样子:
foreach($users as $i=>$u){
$text = preg_replace("/@".$u['username']."\b/",
"<a href='#' title='{$u['user_id']}'>@{$u['username']}</a> ", $text);
}
答案 0 :(得分:1)
问题似乎是某些用户名可以包含其他用户名。因此,您可以使用user1
正确替换<a>user1</a>
。然后,user
匹配并替换为<a><a>user</a>1</a>
。我的建议是将你的字符串替换更改为带有字边界的正则表达式,\ b,这是在用户名之后所必需的。
答案 1 :(得分:0)
你可以选择一个自定义的str替换功能,它在第一次替换时就会停止..比如......
function str_replace_once($needle , $replace , $haystack){
$pos = strpos($haystack, $needle);
if ($pos === false) {
// Nothing found
return $haystack;
}
return substr_replace($haystack, $replace, $pos, strlen($needle));
}
并使用它:
foreach($users as $i=>$u){
$text = str_replace_once("@{$u['username']}",
"<a href='#' class='ct-userLink' rel='{$u['user_id']}'>@{$u['username']}</a> ", $text);
}
答案 2 :(得分:0)
Twitter小部件有JavaScript代码来执行此操作。我在WordPress plugin中将它移植到PHP。这是相关部分:
function format_tweet($tweet) {
// add @reply links
$tweet_text = preg_replace("/\B[@@]([a-zA-Z0-9_]{1,20})/",
"@<a class='atreply' href='http://twitter.com/$1'>$1</a>",
$tweet);
// make other links clickable
$matches = array();
$link_info = preg_match_all("/\b(((https*\:\/\/)|www\.)[^\"\']+?)(([!?,.\)]+)?(\s|$))/",
$tweet_text, $matches, PREG_SET_ORDER);
if ($link_info) {
foreach ($matches as $match) {
$http = preg_match("/w/", $match[2]) ? 'http://' : '';
$tweet_text = str_replace($match[0],
"<a href='" . $http . $match[1] . "'>" . $match[1] . "</a>" . $match[4],
$tweet_text);
}
}
return $tweet_text;
}
答案 3 :(得分:0)
而不是解析'@user'解析'@user'(最后有空格)或'@user'甚至避免错误解析电子邮件地址(例如:mailaddress@user.com)'@user :'也应该被允许。如果用户名没有空格,这只会起作用......
答案 4 :(得分:0)
您不应该一次替换某个用户提及但一次全部替换。您可以使用preg_split
来执行此操作:
// split text at mention while retaining user name
$parts = preg_split("/@(\w+)/", $text, -1, PREG_SPLIT_DELIM_CAPTURE);
$n = count($parts);
// $n is always an odd number; 1 means no match found
if ($n > 1) {
// collect user names
$users = array();
for ($i=1; $i<$n; $i+=2) {
$users[$parts[$i]] = '';
}
// get corresponding user information
$sql = "SELECT *
FROM users
WHERE username IN ('" .implode("','", array_keys($users)). "')";
$users = array();
foreach ($this->getQuery($sql) as $user) {
$users[$user['username']] = $user;
}
// replace mentions
for ($i=1; $i<$n; $i+=2) {
$u = $users[$parts[$i]];
$parts[$i] = "<a href='#' class='ct-userLink' rel='{$u['user_id']}'>@{$u['username']}</a>";
}
// put everything back together
$text = implode('', $parts);
}
答案 5 :(得分:0)
我喜欢解析'@user'的dnl解决方案,但可能不适合你。
无论如何,您是否尝试使用strip_tags函数删除锚标签?这样你就可以得到没有链接的字符串了,你可以解析它再次构建链接。