diff --git a/links.inc b/links.inc
index 3e35791..cdfa3f3 100644
--- a/links.inc
+++ b/links.inc
@@ -291,7 +291,7 @@ function links_parse_url($url, $accept_bare=TRUE, $accept_relative=TRUE, $accept
   // Userid or local_part for email address
   $p_user   = "([a-zA-Z0-9_\-.%$]+)";
   // Password for URLs of the form "scheme://username:password@server/path"
-  $p_passwd = "([a-zA-Z0-9%_~#?&=.,;-]+)";
+  $p_passwd = "([a-zA-Z0-9%_~#!?&=.,;-]+)";
   // Combined userid and password authentication spec (see above)
   $p_auth   = "(?:(".$p_user."(?::".$p_passwd.")?)@)";
   // Combined specification of authentication credentials, hostname, and port
@@ -300,7 +300,7 @@ function links_parse_url($url, $accept_bare=TRUE, $accept_relative=TRUE, $accept
 //  $p_query  = "(?:\?([a-zA-Z0-9{}@:%_~&=.,/;-]+))";
   $p_query  = "(?:\?([^#]*))";
   // Fragment indicator (after "#")
-  $p_frag   = "(?:#([a-zA-Z0-9@:%_?~&=.,/;-]*))";
+  $p_frag   = "(?:#([a-zA-Z0-9@:%_?~&=!.,/;-]*))";
   // The path catches the leading slash, if present, separately
   // so that we can later distinguish between relative and absolute
 //  $p_path   = "(/?)([a-zA-Z0-9@:%_~&=.,/;-]*)";
@@ -321,7 +321,8 @@ function links_parse_url($url, $accept_bare=TRUE, $accept_relative=TRUE, $accept
   }
 
   // Now try to find a match
-  $pattern = "!".$p_inet.$p_local."$!i";
+  $delim = chr(127);
+  $pattern = $delim.$p_inet.$p_local."$".$delim."i";
   $result['debug'][] = "Matching for regular URL using pattern: ".$pattern;
   $matches = array();
   preg_match($pattern, $url_n, $matches);
