技术开发 频道

Web程序员必须掌握的五个正则表达式

匹配一个URL

匹配一个URL很像匹配一个email地址,除了你需要做更多的控制,同时必须容忍这个表达式在某些极端的情况下面会出现的判断错误。我经常在项目中使用这个表达式,比如在一个网站留言栏里,如果出现一个URL,我会自动把它转化为链接。象判断email的表达式一样,这个正则表达式是一个庞然大物,不过相信我,它很容易理解。

这个表达式将涉及到一个正则表达式里面的概念:正则表达式修饰符(Pattern modifiers),我在这个表达式里面使用了两个修饰符-- ‘x’ 和‘i’ 修饰符。正则表达式修饰符是跟在表达式最后,它的作用是改变解析引擎处理表达式的方法。

具体到现在的例子,‘x’ 修饰符告诉解析引擎忽略空格,除非出现在转义符(’\’)后面或者在一个字符分类([…])里面,它同时还通知解析引擎在字符分类以外任何地方跟在’#’字符后面的文字都视为注释文字(也就是在解析的时候忽略它们)。‘i’修饰符通知解析引擎对于字符串分析时不区分字母的大小写(case insensitive)。在这种比较复杂的表达式中,使用正则表达式修饰符可以极大的简化表达式,比如可以让你不用对匹配条件都指定大写字母以及小写字母。我现在用的这个正则表达式来源于Jeffrey Friedl 在他的著作Mastering Regular Expressions中写的一个表达式。
{ \b # Match the leading part (proto://hostname, or just hostname) ( # http://, or https:// leading part (https?)://[-\w]+(\.\w[-\w]*)+ | # or, try to find a hostname with more specific sub-expression (?i: [a-z0-9] (?:[-a-z0-9]*[a-z0-9])? \. )+ # sub domains # Now ending .com, etc. For these, require lowercase (?-i: com\b | edu\b | biz\b | gov\b | in(?:t|fo)\b # .int or .info | mil\b | net\b | org\b | [a-z][a-z]\.[a-z][a-z]\b # two-letter country code ) ) # Allow an optional port number ( : \d+ )? # The rest of the URL is optional, and begins with / ( / # The rest are heuristics for what seems to work well [^.!,?;"\'<>()[]{}sx7F-\xFF]* ( [.!,?]+ [^.!,?;”\’<>()\[\]{\}s\x7F-\xFF]+ )* )? }ix
这个表达式里面的注释解释得比较清晰,因此我认为我们不需要完整的分析整个表达式。我只想补充一下它可能会判断错误的一些地方 - 首先,这个表达式可能会匹配到一些无效的URL – 因为这个表达式假设任何两个字母的组合是一个有效的优异域名后缀(TLD),比如.cn、.en,但是我们知道有些组合可能还不存在。另一个问题是:它也不认识那些最近加到IANA列表里面的TLD,比如:.travel、 .name和.museum,不过这个问题你可以通过自己加上这些判断来解决 -- 首先从IANA下载最新的TLD列表,然后把新增加的这些补充到表达式中间对应的那块区域后面。

除了这些可能的例外,基本上这个正则表达式的匹配结果在99.9%以上的情况下是正确的。下面这个PHP函数能够分析一段文本,把它发现的所有URL转换成链接。在这个例子里面我假设你已经用上面的正则表达式正确地设置了变量$url_regex的值,所以在这里我就省略不重复了。
function auto_link( $text ) { $url_regex = ... return preg_replace( $url_regex, '<a href="$0"^gt;$0=</a>', $text ); }
以上就是我要介绍的所有内容。如果你觉得我遗漏了应该介绍的表达式或者有任何改进建议,请留下留言让我知道。

相关文章:《程序员必须掌握的基础正则表达式》
0
相关文章