douliao7930 2018-03-29 02:43
浏览 38
已采纳

在字符串中查找主题标签和标记用户

I am working on a project and am trying to add the ability to detect hashtags and tagged users.

The problem is I don't know how to make it stop reading when it reaches symbols or emojis (Except underscores) and not let the length go over 20 characters

For hashtags

#HelloWorld -> helloworld, #Hello_W0rld -> hello_w0rld, #Hello(World -> hello,

Also for tagged users (Which only allows A-Z a-z 0-9 and _

@HelloWorld -> helloworld, @Hello_W0rl.d -> hello_w0rl

My attempted code is (basically same for users or hashtags)

$words = explode(" ", $body);

        foreach($words as $word){
            if(substr($word, 0, 1) == "@"){
                $tagged_user = DB::query('SELECT id FROM users WHERE username=:username', array(':username' => ltrim($word, '@')))[0];
                $users .= $tagged_user,",";
            }
        }

        $users = rtrim($users, ',');

Also would it know not to save #% as a blank space

Edit: I updated it to this, is this correct?

$postid = "test_id";
        $matches = [];
        preg_replace_callback("/#([a-z_0-9]+)/i", function($res) use(&$matches) {
            $matches[] = strtolower($res[1]);
        }, $body);

        $matches2 = [];

        $tagholder = array_fill(0, count($matches), "?");
        $tagholderString = implode(", ", $tagholder);

        foreach($matches as $tagstring){
            if(DB::query('SELECT * FROM tags WHERE tag=:tag', array(':tag' => $tagstring))){
                $tag = DB::query('SELECT * FROM tags WHERE tag=:tag', array(':tag' => $tagstring))[0];
                DB::query ( "INSERT INTO post_tags VALUES(:tagid, :postid)", array (':tagid' => $tag['id'], ':postid' => $postid) );
            }else{
                $id = hash(sha256, $tagstring);
                DB::query ( "INSERT INTO tags VALUES(:id, :tag, :mode)", array (':id' => $id, ':tag' => $tagstring, ':mode' => 0) );
                DB::query ( "INSERT INTO post_tags VALUES(:tagid, :postid)", array (':tagid' => $id, ':postid' => $postid) );
            }
        }

        preg_replace_callback("/@([a-z_0-9]+)/i", function($res) use(&$matches2) {
            $matches2[] = strtolower($res[1]);
        }, $body);

        $userholder = array_fill(0, count($matches2), "?");
        $userholderString = implode(", ", $userholder);
        $user_query = DB::query("SELECT * FROM users WHERE username IN (".$userholderString.")", $matches2);

        $users_result = "";
        foreach($user_query as $result){
            $users_result .= $result['id'].",";
        }
        $users_result = rtrim($users_result, ',');

        //User string result
        $users_result;
  • 写回答

2条回答 默认 最新

  • dongluo8439 2018-03-29 02:56
    关注

    You can use preg_replace_callback() to pass each result into strtolower(). You need to patterns, one for each of your requirements. For hashtags:

    /#([a-z_0-9]+)/i
    

    Demo

    And for tags:

    /@([a-z_0-9]+)/i
    

    Demo

    With each of those you're asking for a starting @ or #, then one or more occurrences of either a letter, a number or an underscore, case-insensitive.

    The resulting code looks like this:

    $matches = [];
    $string = "#HelloWorld -> helloworld, #Hello_W0rld -> hello_w0rld, #Hello(World -> hello,";
    
    preg_replace_callback("/#([a-z_0-9]+)/i", function($res) use(&$matches) {
        $matches[] = strtolower($res[1]);
    }, $string);
    
    var_dump($matches);
    
    $matches2 = [];
    $string2 = "@HelloWorld -> helloworld, @Hello_W0rl.d -> hello_w0rl,";
    
    preg_replace_callback("/@([a-z_0-9]+)/i", function($res) use(&$matches2) {
        $matches2[] = strtolower($res[1]);
    }, $string2);
    
    var_dump($matches2);
    

    Demo

    Result:

    array (size=3)
    0 => string 'helloworld' (length=10)
    1 => string 'hello_w0rld' (length=11)
    2 => string 'hello' (length=5)

    array (size=2)
    0 => string 'helloworld' (length=10)
    1 => string 'hello_w0rl' (length=10)


    As a side note, you shouldn't be doing a query for each tag found. This will rapidly grow out of control and may severely hamper your database performance. Since you have all the tags in an array, do just one query with a WHERE IN clause, something like this:

    $placeholders = array_fill(0, count($matches), "?"); // get a ? for each match
    $placeholdersString = implode(", ", $placeholders); // make it a string
    DB::query("SELECT id FROM users WHERE username IN (".$placeholderString.")", $matches); // bind each value
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 MATLAB怎么通过柱坐标变换画开口是圆形的旋转抛物面?
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题
  • ¥15 Visual Studio问题
  • ¥20 求一个html代码,有偿