使用PHP在字符串中抓取以@开头的单词[关闭]

When a user posts a comment, I want to grab every word that starts with a @ symbol.

ex. string is 'Check this out @user1. It's a photo of @user2 and @user3.'

When I'm on the PHP side, I want to grab user1, user2, user3 so I can then notify those users that they have been tagged in this comment.

I tried playing with strpos, but closest I got was if the string started with @ using the logic below.

if (0 === strpos($string, '@')){ echo 'yes' }

but that wasn't what I needed.

You can simply use this function:

function get_tagged_users($comment) {
    $matches = array();
    if (preg_match_all('/@(\w+)\b/', $comment, $matches)) {
        return $matches[1];
    }
    return array();
}

It will return an array of usernames (without "@") and an empty array if no matches found or if an error occurred while doing regex.

Note: It uses regular definition of word boundaries and words. Lorem @ipsum-ed dolor will return just ipsum.

So if you need to include hypen (-) in usernames, just change regex with /@([-\w]+)\b/

Here's a regex method of doing this:

$matches = [];
preg_match_all( "/@([-\w]+)\b/",
                "Check this out @user1. It's a photo of @user2 and @user3",
                $matches);

print_r($matches);

Output:

Array
(
    [0] => Array
        (
            [0] => user1
            [1] => user2
            [2] => user3
        )

)

The regular expression matches @ followed by one or more alphanumeric characters or an underscore (\w) up to a word boundary (\b). The matched words are in $matches (as you may have guessed).

A "regex-free" and "explode-free" solution

$str = 'Check this out @user1. It\'s a photo of @user2 and @user3.';

$offset = 0;
$users = array();

$str .= ' ';
while($offset = strpos($str, '@', $offset + 1)){
    $users[] = rtrim(substr($str, $offset + 1, strpos($str, ' ', $offset)- $offset), '?.,!:;');
}

print_r($users);

However this assumes that your usernames do not contain white space and punctuation characters as well as that a proper white space is present after punctuation.

EDIT:

I created a quick benchmark script to test which answer was the fastest. Contrary to my belief regex appears to be faster than bit-searching manually. You can see the results yourself here