1

I am trying to write function which will linkfy (convert as hyperlinks) email and URLs in the given text, but facing issue while replacing email since it will have domain in it. can some please correct my code where it should replace domain name in email?

Code Sample

     function linkifyMyString($noteText)) {

        $emailPattern = '/(\S+@\S+\.\S+)/';
        $urlPattern = '@(http)?(s)?(://)?(([a-zA-Z])([-\w]+\.)+([^\s\.]+[^\s]*)+[^,.\s])@';

        if(preg_match($emailPattern, $noteText, $email)) {
            // change email to mailto 
            $replace = "<a href='mailto:'.$email[0].'>".$email[0]."</a>";
            $noteText = preg_replace($emailPattern, $replace, $noteText);
        }
        if(preg_match($urlPattern, $noteText, $url)) {

        // change URLs to hyperlinks
            $noteText = preg_replace($urlPattern, '<a href="http$2://$4" target="_blank" title="$0">$0</a>', $noteText);
        }


        return $noteText;
}


$str = "contact me at test.me@gmail.com visit us http://google.com ,http://gmail.com";
function ($str);
somu.web
  • 379
  • 1
  • 5
  • 14

2 Answers2

1

How about this code

 1  #!/usr/bin/php
 2  <?php
 3  function linkifyMyEmail($noteText) 
 4  {
 5          $emailPattern = '/(\S+@\S+\.\S+)/';
 6          if(preg_match($emailPattern, $noteText, $email)) {
 7              // change email to mailto 
 8              $replace = '<a href="mailto:' . $email[0] . '">' . $email[0] . '</a>';
 9              $noteText = preg_replace($emailPattern, $replace, $noteText);
10          }
11          return $noteText;
12  }
13  function linkifyMyUrl($noteText)      
14  {
15          $urlPattern = '@(http://\S+)@';
16          if(preg_match($urlPattern, $noteText, $url)) {
17          // change URLs to hyperlinks
18              $replacement = '<a href="$1" target="_blank" title="$1">$1</a>';
19              $noteText = preg_replace($urlPattern,$replacement,$noteText);
20          }
21          return $noteText;
22  }
23  
24  
25  $str = "contact me at test.me@gmail.com visit us http://google.com ,http://gmail.com";
26  printf("Original string is %s\n",$str);
27  printf("string after email convertion %s\n",linkifyMyEmail($str));
28  printf("string after url convertion %s\n",linkifyMyUrl($str));
29  printf("Combining both functions %s\n",linkifyMyUrl(linkifyMyEmail($str)));
30  ?>

And output

[root@vznfsclient ~]# ./Test.php 
Original string is contact me at test.me@gmail.com visit us http://google.com ,http://gmail.com
string after email convertion contact me at <a href="mailto:test.me@gmail.com">test.me@gmail.com</a> visit us http://google.com ,http://gmail.com
string after url convertion contact me at test.me@gmail.com visit us <a href="http://google.com" target="_blank" title="http://google.com">http://google.com</a> ,<a href="http://gmail.com" target="_blank" title="http://gmail.com">http://gmail.com</a>
Combining both functions contact me at <a href="mailto:test.me@gmail.com">test.me@gmail.com</a> visit us <a href="http://google.com" target="_blank" title="http://google.com">http://google.com</a> ,<a href="http://gmail.com" target="_blank" title="http://gmail.com">http://gmail.com</a>
Dmitry Zayats
  • 474
  • 2
  • 6
  • Sorry I missed to specify it should work for "https:" also – somu.web Nov 24 '16 at 09:40
  • 1
    so what's the problem? You just change `$urlPattern = '@(http://\S+)@';` to `$urlPattern = '@(https*://\S+)@';` This should catch http and https. * after character means zero or more occurrences of the preceding character. – Dmitry Zayats Nov 24 '16 at 09:50
1

I think using your patterns in an alternation based regex and replacing inside a preg_replace_callback is more elegant and efficient, as you only use 1 regex pass and can customize your replacement logic easily when needed:

function replace_callback($m){
    if (empty($m[3])) { // email
        return "<a href='mailto:".$m[0]."'>" . $m[0] . "</a>";
    }
    else { // url
        return "<a href='".$m[1]."://".$m[3]."' target='_blank' title='".$m[0]."'>".$m[0]."</a>";
    }
}

function linkifyMyString($noteText) {
    $emailPattern = '\S+@\S+\.\S+';
    $urlPattern = '(https?)?(://)?([a-zA-Z](?:[-\w]+\.)+(?:[^\s.]+\S*)+[^,.\s])';
    return preg_replace_callback('~' . $emailPattern . '|' . $urlPattern . '~', 'replace_callback', $noteText);
}
$str = "www.google.com contact me at test.me@gmail.com visit us http://google.com ,http://gmail.com";
echo linkifyMyString($str);

See this PHP demo

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • preg_replace_callback has doesn't support in PHP 5.2, getting error [24-Nov-2016 19:30:00] PHP Parse error: syntax error, unexpected T_FUNCTION in – somu.web Nov 24 '16 at 10:34
  • It is not a big deal, replace the callback anonymous function with a separate function. I replaced the code in the answer and optimized the pattern a bit more. – Wiktor Stribiżew Nov 24 '16 at 10:38
  • thanks for the solutions , do know how the callback can be called if it public static function replace_callback()? – somu.web Nov 24 '16 at 10:50
  • Something like `array(new MyClass(), 'myStaticCallback')`. See http://stackoverflow.com/a/28954220/3832970. – Wiktor Stribiżew Nov 24 '16 at 10:51
  • 1
    thank you so much , array(self, 'replace_callback') this worked for me it is same class – somu.web Nov 24 '16 at 10:55
  • found one more problem when we give www.google.com it is replacing as mailto and it shouldn't convert url without http, https and www – somu.web Nov 24 '16 at 11:20
  • I see, the problem is that I checked Group 1 for a match with `if (empty($m[1]))`, but Group 1 is optional. We must check for Group 3 match that is obligatory. Try with `if (empty($m[3]))`. [See **this demo**](https://ideone.com/JQkoZ7). Or, if you mean that `www.google.com` should not be linkified, check if group 1 matches later, see [**this demo**](https://ideone.com/8kpES3). – Wiktor Stribiżew Nov 24 '16 at 11:23
  • Or, if you mean that `www.google.com` should not be linkified, check if group 1 matches later, see [**this demo**](https://ideone.com/8kpES3). – Wiktor Stribiżew Nov 24 '16 at 11:25
  • https://ideone.com/8kpES3 this one worked , but it is not making www.google.com linkified – somu.web Nov 24 '16 at 12:05
  • hello, I am having one more problem with email ID pattern , it should allow double quotes in email ID, any help ? Eg: test.test"n@gmail.com – somu.web Dec 06 '16 at 07:41
  • The `\S` matches `"`, so that pattern "allows" (=matches) double quotes. See [the regex demo](https://regex101.com/r/AVbTqy/2). If there is any issue it is not the regex. – Wiktor Stribiżew Dec 06 '16 at 07:43
  • Sorry my mistake it should not allow double quotes ("). Thanks in advance – somu.web Dec 06 '16 at 09:13
  • Then just replace `\S` with `[^\s"]`: `'[^\s"]+@[^\s"]+\.[^\s"]+'` – Wiktor Stribiżew Dec 06 '16 at 09:17
  • If I add this regex it is converting only n@gmail.com as hyperlinks, it should ignore complete email ID which has double quotes in it. thank you – somu.web Dec 06 '16 at 09:28
  • That is very difficult without knowing the actual requirements, exact context where the "good" strings are. You may try to only match these emails if they are preceded with whitespace/start of string: [`(?<!\S)[^\s"]+@[^\s"]+\.[^\s"]+\b`](https://regex101.com/r/aIyWpA/1). – Wiktor Stribiżew Dec 06 '16 at 09:37
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/129885/discussion-between-somu-web-and-wiktor-stribizew). – somu.web Dec 06 '16 at 09:45
  • Hello Wiktor, _"That is very difficult without knowing the actual requirements, exact context where the "good" strings are"_ requirement is same as mention in question , I am trying to linkify the emailIDs , but if there is double quote in emailID I should not linkify it good string are like stest@abc.com, test.me@gmail.com testme@tgs.co.in – somu.web Dec 06 '16 at 10:03
  • You are passing HTML code as input, right? Then why process tags at all? Replace `'~' . $emailPattern . '|' . $urlPattern . '~'` with `'~<[^<]*?>(*SKIP)(*F)|(?:' . $emailPattern . '|' . $urlPattern . ')~'` – Wiktor Stribiżew Dec 06 '16 at 10:09
  • I made some changes in the above functions, this is my current code `public static function linkifyString($noteText) { $patterns = array( '@(https?://([-\w\.]+)+(:\d+)?(/([-\w/_\.]*(\?\S+)?)?)?(?:\#\S+)?)@', '/(?<!\S)[^\s"]+@[^\s"]+\.[^\s"]+/i' );$replacements = array( '$1', '$1' ); return preg_replace($patterns, $replacements, $noteText); }` – somu.web Dec 06 '16 at 10:13