【问题标题】:preg_match_all replaces first ocurrence only @user phppreg_match_all 仅替换第一次出现@user php
【发布时间】:2020-05-14 17:10:57
【问题描述】:

我创建了这个函数来检查提到的@users

function user_links($string,$table_users,$pdo) {
    preg_match_all('/@(\w+)/',$string,$matches);
           //
        $sql="
      SELECT id_user,user 
      FROM $table_sers 
      WHERE user= :user LIMIT 1";
        $sql = $pdo->prepare($sql); 
        $sql->bindParam(':user', $match,PDO::PARAM_STR, 20); 

    foreach ($matches[1] as $match) {

        $sql->execute();

        $res = $sql->fetch(PDO::FETCH_ASSOC);

        if($sql->rowCount() > 0){
            $id_user=$res['id_user'];
            $user=$res['user'];

            $from = "/@(" . $match . ")(?!\w)/";
            $to = "<a href='user.phhp?id=$id_user'>@".$match."</a>";
            $string = preg_replace($from, $to, $string);
        }

        return $string;
    }
}

我正在尝试将提到的用户与下一个 string 联系起来,但它只替换了第一次出现...

@cat,@dog and @turtle is in the db

主字符串

 $string="Hi Im @cat and not @cat2, yes you are @dog, @squirrel and @turtle ";

   echo user_links($string,$table_users,$pdo);

它检索到的内容:

//Hi Im <a>@cat</a> and not @cat2, yes you are @dog, @squirrel and @turtle 

@dog 也没有,@turtled 被替换...尽管它们在数据库中..

做错了什么?

【问题讨论】:

  • 你需要将return $string移动到foreach右括号}之后
  • 是的,我试过了。它也不起作用。谢谢
  • 如果您只想匹配整个单词,请使用\b 而不是(?!\w)
  • 在每个循环结束时(以前的返回位置)尝试echo $string.PHP_EOL;
  • @Barmar 谢谢。伟大的洞察力。我已经编辑了帖子。以及关于我的问题的任何线索。我还是找不到办法。

标签: php preg-replace preg-match-all


【解决方案1】:

首先,您可以动态创建查询以查找所有 ID,因此您无需在循环中进行字符串替换。

其次,您可以使用preg_replace_callback() 动态生成替换字符串。将用户名到ID的所有映射放在一个关联数组中,并在回调函数中使用该数组。

<?php
function user_links($string,$table_users,$pdo) {
    preg_match_all('/@(\w+)/',$string,$matches);

    $in_string = implode(',', array_fill(0, count($matches[1]), '?'));
    $sql="
      SELECT id_user,user 
      FROM $table_sers 
      WHERE user in ($in_string)";
    $stmt = $pdo->prepare($sql);
    $sql->execute($matches[1]);

    $mapping = [];
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        $mapping[$row['user']] = $row['id_user'];
    }

    $string = preg_replace_callback('/@(\w+)/', function($matches) use($mapping) {
            if (isset($mapping[$matches[1]])) {
                return "<a href='scriptname.php?id={$mapping[$matches[1]]}'>{$matches[0]}</a>";
            } else {
                return $matches[0];
            }
        }, $string);
    return $string;
}

【讨论】:

  • 很棒的答案。我认为它有效....我有一个小细节。我正在使用一个非常旧的 php 服务器4.0.3 这个preg_replace_callback() 检索错误syntax error, unexpected T_FUNCTION in 。我知道我需要升级,但同时我使用这个服务器版本,有没有可能为这种类型的 php 版本找到合适的解决方案?谢谢。
  • 旧版本需要使用create_function()函数。您可以在preg_replace_callback() 文档中查看示例。
  • 它还必须包含global $mapping,因为那时use() 并不存在。
  • 我在我的在线服务器中禁用了全局变量。
  • 你说的是register_globals吗?这与函数内部的 global 声明无关。
猜你喜欢
  • 1970-01-01
  • 2016-12-15
  • 2014-01-28
  • 1970-01-01
  • 2023-01-08
  • 2011-08-25
  • 1970-01-01
相关资源
最近更新 更多