Replace @mentions with anchor tags in a string
Asked Answered
A

7

7

Trying to replace all occurrences of an @mention with an anchor tag, so far I have:

$comment = preg_replace('/@([^@ ])? /', '<a href="/$1">@$1</a> ', $comment);

Take the following sample string:

"@name kdfjd fkjd as@name @ lkjlkj @name"

Everything matches okay so far, but I want to ignore that single "@" symbol. I've tried using "+" and "{2,}" after the "[^@ ]" which I thought would enforce a minimum amount of matches, but it's not working.

Adventurer answered 30/4, 2012 at 12:59 Comment(4)
Just figured it out: preg_replace('/@([^@ ]+)/', '<a href="/$1">@$1</a> ', $comment);Adventurer
do not use spaces in the expressions. lead to problems. instead use \sLandel
@Vipin That advice is not accurate. There are times when spaces are perfectly adequate in regular expressions. To say that spaces should never be used is not thoughtful advice.Anuradhapura
For efforts to replace \@mentions with text including dynamically retrieved content, see: Replace @mentions in text with clickable text including related ids fetched from a database tableAnuradhapura
J
10

Replace the question mark (?) quantifier ("optional") and add in a + ("one or more") after your character class:

@([^@ ]+)
Jaquith answered 30/4, 2012 at 13:2 Comment(0)
P
8

The regex

(^|\s)(@\w+)

Might be what you are after.

It basically means, the start of the line, or a space, then an @ symbol followed by 1 or more word characters.

E.g.

preg_match_all('/(^|\s)(@\w+)/', '@name1 kdfjd fkjd as@name2 @ lkjlkj @name3', $result);
var_dump($result[2]);

Gives you

Array
    (
        [0] => @name1
        [1] => @name3
    )
Pardew answered 30/4, 2012 at 13:8 Comment(0)
F
7

I like Petah's answer but I adjusted it slightly

preg_replace('/(^|\s)@([\w.]+)/', '$1<a href="/users/$2">@$2</a>', $text);

The main differences are:

  • the @ symbol is not included. That's for display only, should not be in the URL
  • allows . character (note: \w includes underscore)
  • in the replacement, I added $1 at the beginning to preserve the whitespace
Flexuous answered 30/9, 2015 at 2:44 Comment(0)
I
3

Replacing ? with + will work but not as you expect.

Your expression does not match @name at the end of string.

$comment = preg_replace('#@(\w+)#', '<a href="/$1">$0</a> ', $comment);

This should do what you want. \w+ stands for letter (a-zA-Z0-9)

Irritable answered 30/4, 2012 at 13:16 Comment(1)
work but not as expected, he wants no space and no @ symbol. but it removes allLandel
A
1

I recommend using a lookbehind before matching the @ then one or more characters which are not a space or @.

The "one or more" quantifier (+) prevents the matching of mentions that mention no one.

Using a lookbehind is a good idea because it not only prevents the matching of email addresses and other such unwanted substrings, it asks the regex engine to primarily search @s then check the preceding character. This should improve pattern performance since the number of spaces should consistently outnumber the number of mentions in comments.

If the input text is multiline or may contain newlines, then adding an m pattern modifier will tell ^ to match all line starts. If newlines and tabs are possible, is will be more reliable to use (?<=^|\s)@([^@\s]+).

Code: (Demo)

$comment = "@name kdfjd @@ fkjd as@name @ lkjlkj @name";

var_export(
    preg_replace(
        '/(?<=^| )@([^@ ]+)/',
        '<a href="/$1">$0</a>',
        $comment
    )
);

Output: (single-quotes are from var_export())

'<a href="/name">@name</a> kdfjd @@ fkjd as@name @ lkjlkj <a href="/name">@name</a>'
Anuradhapura answered 10/12, 2020 at 21:8 Comment(0)
F
0

Try:

'/@(\w+)/i'

Fulbert answered 30/4, 2012 at 13:3 Comment(6)
ERROR: unable to parse :PLandel
@VIPINJAIN: Looks syntactically correct to me. Semantically, not so much -- \b refers to the boundary between word chars and no-word chars, and @ not being a word char, it wouldn't match unless whatever preceded it was a word.Supernaturalism
he only want to remove the @ and space not other characters like hyphen etc. check your code it skips many special charactesLandel
Skipping characters that shouldn't be skipped, while bad, still means it parses and runs. Which pretty much by definition means it's not a parse error. If you're gonna call something broken, at least be correct about why.Supernaturalism
This answer is missing its educational explanation.Anuradhapura
\w is already case-insensitive. The pattern modifier has no purpose.Anuradhapura
C
-1

Try using this code in PHP to extract Mentions and Hashtags with unicode, dots and underscores support

<?php
preg_match_all('/(^|\s)([@|#][\d\p{L}\._]+)/iu', $text, $result);
Cytology answered 29/3 at 13:37 Comment(1)
At no point does the question mention hashtags. Your pattern erroneously matches pipes. A dot in a character class doesn't need to be escaped. The case insensitive flag is pointless.Anuradhapura

© 2022 - 2024 — McMap. All rights reserved.