2

I am implimenting a timeline system on my website where users can mention others users in their timeline using @username like twitter.

I want to convert @username to link and point it to their profile

My string :

$timeline="@fred-ii 's posts on @stackoverflow are intresting."; 

I am using the following code to replace @username with url :

echo preg_replace("/@([^\s]+)/i","<a href='http://example.com/$1'>@$1</a>",$timeline);

it works, the problem is that it matchs spaces also

this string

"@fred-ii 's posts on@stackoverflow";

There is no space between on and @stackoverflow ,I want to exclude it,

so i updated my regex

/\s+@([^\s]+)/

it worked but it didnot match the first part of my string (username @fred-ii ) .I think regex engine is looking for space|s at the start of string.

What do I need to change in my pattern to match all @usernames ?

$timeline="@fred-ii 's posts on @stackoverflow are intresting."; 
1
  • So you want to match the space in the username, but don't have a space in the link? Commented Nov 21, 2015 at 15:05

2 Answers 2

2

You can do this with lookbehind negative assertion:

/(?<!\w)@([^\s]+)/

The (?<!\w) tells the Regex engine to match @([^\s]+) only if it's not preceded by a word \w. It will work in the example you gave, perhaps you will have to tweak it as you go.

Example code:

$pattern = "/(?<!\w)@([^\s]+)/";
$subject = "@fred-ii 's posts on @stackoverflow are interesting. @fred-ii 's posts on@stackoverflow";

preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER );

foreach($matches as $item)
{
    echo $item[1] . "<br/>";
}

Produces this output:

fred-ii
stackoverflow
fred-ii

See it in action.

Sign up to request clarification or add additional context in comments.

Comments

0

You can use this lookbehind assertion:

/(?<=\s|^)@\S+/

(?<=\s|^) makes sure there is whitespace or line start before @.

Code:

php> $s = "@fred-ii 's posts on@stackoverflow";

php> echo preg_replace('/(?<=\s|^)@\S+/', "<a href='http://example.com/$0'>$0</a>", $s);
<a href='http://example.com/fred-ii'>@fred-ii</a> 's posts on@stackoverflow

5 Comments

Anubhava your answer is korrect, it gives the korrect output. but what if I don't use lookbehind forexample the pattern /(\s+|^)@([^\s]+)/ also works, is it correct to use it or always with lookbehind. please guide me.
Yes you can also use: /(?:\s|^)@([^\s]+)/ with captured group. Lookbehind gives you an option of not using any captured group at all using: preg_replace('/(?<=\s|^)@\S+/', "<a href='http://example.com/$0'>$0</a>", $s);
Thank you so much for the explaination Anubhava , I learned alot about LookBehind from your answer and comment. I really appriciate it.
Anubhava Do you know how to match a string in Shell based wildcard expresion? sorry for adding an unrelated comment, I'ma remove it soon.
Try: s="@fred-ii 's posts on@stackoverflow"; sed -r 's~(^|[[:blank:]])(@[^[:blank:]]+)~\1<a href="http://example.com/\2">\2</a>~' <<< "$s"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.