问题描述
我希望能够点击每个 @.... 并转到他们的特定页面,以便我从数据库中获取文本中每个匹配项的 ID,以便链接到匹配项的页面。我确实从 foreach 循环中获得了一组 id,但是当我在 foreach 循环中使用 preg_replace 时,我为多个值插入了相同的 id。我被卡住了,并尝试了许多不同的变化,但还没有运气。
$text = "I went to the dog park yesterday and saw @dog4 playing with @dog8 and @dog3 drinking water.";
public function getLinks($text) {
preg_match_all("/@([\w]+)/",$text,$matches);
if ($matches) {
$result = array_values($matches[1]);
}
$sql = "SELECT dogId FROM dogs WHERE dogName = :dogName";
foreach ($result as $dogName) {
$stmt = $this->con->prepare($sql);
$stmt->execute(array(":dogName" => $dogName));
$data = $stmt->fetch(PDO::FETCH_ASSOC);
$i = 0;
if (!empty($data)) {
foreach ($data as $dogId) {
$i++;
// It's working here. I'm getting an array of dogIds
echo '<pre>'; print_r($data); echo '</pre>';
Array
(
[dogId] => 4
)
Array
(
[dogId] => 8
)
Array
(
[dogId] => 3
)
if ($i == count($data)) {
$pattern = "/@([\w]+)/";
$dogPage = "<span onclick='openPage(\"dogs.PHP?id=$dogId\")' role='link' tabindex='0'>$0</span>";
$dogLink = preg_replace($pattern,$dogPage,$text);
// It's not working here. I only get the last array value(3) inserted in $dogId for every match.
echo '<pre>'; print_r($dogPage); echo '</pre>';
"<span onclick='openPage(\"dogs.PHP?id=3\")' role='link' tabindex='0'>@dog4</span>"
"<span onclick='openPage(\"dogs.PHP?id=3\")' role='link' tabindex='0'>@dog8</span>"
"<span onclick='openPage(\"dogs.PHP?id=3\")' role='link' tabindex='0'>@dog3</span>"
}
}
}
} return $dogLink
}
我得到的结果文本是
I went to the dog park yesterday and saw @dog4(id=3) playing with @dog8(id=3) and @dog3(id=3) drinking water.
但我希望实现的是
I went to the dog park yesterday and saw @dog4(id=4) playing with @dog8(id=8) and @dog3(id=3) drinking water.
先谢谢你!
解决方法
首先扫描所有@mentions 的输入文本,并构建一个没有前导“@”的值的平面数组(\K
表示忘记任何先前匹配的字符——在本例中为 @
)。从 dogs
表中提取生成列表中的所有行,并将它们转换为以 dogName
作为键和 dogId
作为值的查找数组。
$count = preg_match_all('/@\K\w+/',$text,$mentions);
if ($count) {
$in = str_repeat('?,',$count - 1) . '?';
$stmt = $db->prepare("SELECT dogName,dogId FROM dogs WHERE dogName IN ($in)");
$stmt->execute($mentions[0]);
$lookup = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
}
生成$mentions
的演示:https://3v4l.org/O9v37
PDO 引用:https://stackoverflow.com/a/14767651/2943403 & https://phpdelusions.net/pdo/fetch_modes#FETCH_KEY_PAIR
然后您可以使用 /@(\w+)/
作为 preg_replace_callback()
的第一个参数再次读取 @mentions 的输入文本。在回调的自定义函数范围内,使用 isset()
快速检查匹配的提及项是否作为查找中的键存在——如果是,则替换,如果不是,则不要更改文本。
$text = "I went to the dog park yesterday and saw @dog4 playing with @dog8 and @dog3 drinking water -- poor @dog33.";
$lookup = [
'dog4' => 4,'dog8' => 8,'dog3' => 3,];
echo preg_replace_callback(
'/@(\w+)/',function ($m) use($lookup) {
return isset($lookup[$m[1]])
? "<span onclick='openPage(\"dogs.php?id={$lookup[$m[1]]}\")' role='link' tabindex='0'>{$m[0]}</span>"
: $m[0];
},$text
);
输出:
I went to the dog park yesterday and saw <span onclick='openPage("dogs.php?id=4")' role='link' tabindex='0'>@dog4</span> playing with <span onclick='openPage("dogs.php?id=8")' role='link' tabindex='0'>@dog8</span> and <span onclick='openPage("dogs.php?id=3")' role='link' tabindex='0'>@dog3</span> drinking water -- poor @dog33.