从@开始,从字符串中获取所有部分

I need get all matches in string, when word begins with @ and then contains only alnym 0-9a-z characters. for example from this string @ww@ee x@@vx @ss @aa assadd @sfsd I need get these pieces:

@ss @aa @sfsd

I am trying:

    $str = "@ww@ee  x@@vx @ss @aa assadd @sfsd";
    preg_match_all("#(^|\s)\@([0-9a-z]+)(\s+|$)#ui", $str, $matches);
    var_dump( $matches );

But this gives only @ss @sfsd and skips @aa.

What would be right pattern for this?

You can use the following regex

'~\B(?<!@)@([0-9a-z]+)(?:\s|$)~iu'

See the regex demo and here is an IDEONE demo:

$re = '~\B(?<!@)@([0-9a-z]+)(?:\s|$)~ui'; 
$str = "@ww@ee  x@@vx @ss @aa assadd @sfsd"; 
preg_match_all($re, $str, $matches);
print_r($matches);

The regex explanation:

  • \B - match the non-word boundary location (that is, everywhere but between ^ and \w, \w and $, \W and \w, \w and \W))
  • (?<!@) - fail the match if there is a @ before the current location
  • @ - a @ symbol (does not have to be escaped)
  • ([0-9a-z]+) - Group 1 (since the (...) are not escaped, they capture a subpattern and store it in a special memory slot)
  • (?:\s|$) - a non-capturing group (only meant to group alternatives) matching a whitespace (\s) or $.

The ~ui modifiers allow proper handling of Unicode strings (u) and make the pattern case insensitive (i).

Note that \B is forcing a non-word character to appear before @. But you do not want to match if another @ precedes the @wwww-like string. Thus, we have to use the negative lookbehind (?<!@) that restricts the matches even further.