我所知道的正则表达式

转载 2012年03月21日 09:28:32

我所知道的正则表达式(1)- 基础知识

2011年12月16日不争没有评论

本文作为温故系列第一篇,主要帮助我回忆正则表达式的基础知识。

正则表达式是处理文本时的有力工具,能够按照一定的模式或规则去匹配具有一定格式的文本,并可以完成分组、替换等复杂功能。作为一程序员,正则作为必备武器,能给我们处理文带来极大的便利。经常用到的正则的场景如:javascript验证输入格式(密码、电话、email等)、网页爬虫从网页中的解析出需要的内容,替换相同模式的文本内容等。

正则中预定义了一些元字符,用来表示字符、个数、重复次数、逻辑关系等,以下是大致介绍:

字符匹配

. 匹配任意一个字符
^ 行开头
$ 行结束
\ 转义符
\d 一个数字,相当于[0-9]
\s 一个空白字符,相当于[ \t\n\x0B\f\r]
\w 一个单词中的字符:字母、数字、下划线,相当于[a-zA-Z_0-9]
\b 单词的边界(单词的开头或结尾)
[] []里面的任意一个字符

数量匹配,用来匹配字符出现的次数

x* 0个或者任意个x,
x? 0个或这1个x
x+ 至少1个x
x{n} n个x
x{n,} 至少n个x
x{n,m} 至少n个x,至多m个x

注:此为贪婪模式,就是匹配最多的结果。例如有个字符串abcdefg#aaa, [a-z]+的第一次匹配结果为abcdefg,不会是a或者ab等

[]的使用举例

[0-9] 一个数字
[^0-9] 一个非数字字符
[a-z] a-z中的任意一个字母(所有小写字母)
[A-Z] A-Z中的任意一个字母(所有大写字母)
[a-zA-Z] 所有字母的一个
[a-zA-Z0-9] 所有字母和数字中的一个
[a-ce-z] a-c和e-z中的一个,不含d
[a-d[m-p]] a-  d或者m-p中的一个,这个不是所有解释器都支持

注:在[]中的^不是表示行开头,而是标识反义,意为“除xxx之外的所有”

逻辑关系

XY X后面是Y
X|Y X或者Y

分组

在一个正则表达式中,将局部用()包含成子表达式,目的是对子表达式进行重复匹配等操作,每个()就是一个组。在匹配的过程中,会将匹配每个子表达式字符按顺序保存在临时变量中,最多可保存9个分组,可以使用1到9来引用。
例如有这样文本,要求匹配出网站名称和链接:
<a href=”http://www.google.com”>谷歌</a><a href=”http://www.baidu.com”>百度</a>

就可以使用分组,正则为:<a href=”([^\"]+)”>([^<]+)</a> ,每个括号为一组,共2个分组。
看下面的Java的测试用例:

1
2
3
4
5
6
7
8
package org.buzheng.test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class Test {
    public static void main(String[] args) throws Exception {
        String value = "<a href="\"http://www.google.com\""></a><a href="\"http://www.baidu.com\""></a>";
        Pattern pattern = Pattern.compile("

最终输出:
谷歌 – http://www.google.com
百度 – http://www.baidu.com

分组替换

分组可以很方便的完成替换,例如在apache的urlrewrite模块中,经常用到如下的正则:
RewriteRule ^/article/([0-9]+)$ /article.php?id=$1 [L]
就是通过分组1获取到id,从而通过$1赋值到后面的url中去

不捕获分组(2011-12-16添加)

(?:group-regex) 按分组(group-regex)来匹配,但不捕获该分组
(?<name>group-regex) 命名分组为name, 可以通过此名字捕获该分组


我所知道的正则表达式(2)- 贪婪模式与懒惰模式

2011年12月25日不争没有评论

前段时间对自己以前了解的正则表达式的基础知识做了一个总结,有了基础知识已经能够能应付大多数情况,像字符串匹配、正则替换、校验等;但是再使用的过程中你可能发现一个问题,就是当使用重复元字符匹配数量时,总是会尽可能长的去匹配,而有时这恰恰不是你想要的。看下面的例子:

<a href=”http://www.google.com”>谷歌</a><a href=”http://www.baidu.com”>百度</a>

你希望匹配出每个链接的html内容。如果你用 <a (.*)</a>会首先匹配到整个字符串,而不是你希望的<a href=”http://www.google.com”>谷歌</a>和<a href=”http://www.baidu.com”>百度</a>。

为什么会出现这种情况呢?这就是正则表达式的贪婪模式。当出现重复数量的时候,会尽可能的多匹配。上述的正则表达式中 . 表示任意字符,* 代表可以重复出现任意个,根据正则表达式的贪婪个性,不匹配到最后才怪呢。就像人一样,有贪婪就有懒惰,一个?就可以让正则立刻改变本性,这时的正则就表现懒惰模式的本性了。

修改后的正则表达式为:<a (.*?)</a>,这时就可以匹配出每个连接的html了。

测试用例为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package org.buzheng.test;
 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class Test {
    public static void main(String[] args) throws Exception {
        String value = "<a href=\"http://www.google.com\">谷歌</a><a href=\"http://www.baidu.com\">百度</a>";
 
        System.out.println("贪婪模式:");
        Pattern pattern = Pattern.compile("<a (.*)</a>");
        Matcher matcher = pattern.matcher(value);
        while (matcher.find()) {
            System.out.println(matcher.group(0));
        }
 
        System.out.println("贪婪模式:");
        pattern = Pattern.compile("<a (.*?)</a>");
        matcher = pattern.matcher(value);
        while (matcher.find()) {
            System.out.println(matcher.group(0));
        }
    }
}

最后总结一下数量元字符懒惰模式的常用写法(其实就是多了一个?):

x*? 0个或者任意个x, 最少匹配
x?? 0个或这1个x, 最少匹配
x+? 至少1个x, 最少匹配
x{n,}? 至少n个x, 最少匹配
x{n,m}? 至少n个x,至多m个x, 最少匹配


我所知道的正则表达式(3)- 零宽断言

2011年12月31日不争没有评论

前段时间总结了正则表达式的基础知识以及贪婪模式和懒惰模式,今天再总结一下零宽断言。

正则表达式里面比较高级的应用就属于零宽断言了。那么什么是零宽断言呢?拆分法从字面上分析一下,零宽,即宽带为0,意味者不会返回匹配的字符,以为匹配的是当前字符的位置。断言,就是预言、假设,意味着从此处假设存在什么情况。那么零宽断言的意思就是假定从此位置开始满足某种情况。

根据断言字符串位于当前位置的前后关系,分为正向和反向断言,根据断言肯定和否定的语气,又有正向否定断言和反向否定断言。肯定即断言存在该字符串、否定即相反的意思:存在的不是该字符串,总之概念比较绕口,下表介绍的时候顺便给出英文:

(?=X) 正向断言,假定该位置后跟的是X
zero-width positive lookahead
(?!X) 正向否定断言,假设该位置后跟的不是X
zero-width negative lookahead
(?<=X) 反向断言,假设该位置前跟的是X
zero-width positive lookbehind
(?<!X) 反向否定断言,假设该位置前跟的不是X
zero-width negative lookbehind

举例:
(?=X) 正向断言

[^\s]+?(?=ing) 来匹配 having doing listing,会匹配出 hav, do, list,注意:并不会匹配出ing,因为ing是零宽断言的部分。

(?!X) 正向否定断言
这个可参考以前的文章:一个匹配数字和字母密码的正则表达式

(?<=X) 反向断言
(?<=hell)[a-z]+ 来匹配test hellen hellas helloween,会匹配出 en, as, oween

(?<!X) 反向否定断言
[a-z]+(?<!hell)en 来匹配testen hellen hellas helloween,会匹配出testen和helloween

注:所有的案例都在UE下进行测试。


一个匹配数字和字母密码的正则表达式

2011年12月14日不争没有评论

一个用户注册功能的密码有如下要求:由数字和字母组成,并且要同时含有数字和字母,且长度要在8-16位之间。

如何分析需求?拆分!这就是软件设计的一般思路了。于是乎,拆分需求如下:
1,不能全部是数字
2,不能全部是字母
3,必须是数字或字母
只要能同时满足上面3个要求就可以了,写出来如下:

1
^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$

分开来注释一下:
^ 匹配一行的开头位置
(?![0-9]+$) 预测该位置后面不全是数字
(?![a-zA-Z]+$) 预测该位置后面不全是字母
[0-9A-Za-z] {8,16} 由8-16位数字或这字母组成
$ 匹配行结尾位置

注:(?!xxxx) 是正则表达式的负向零宽断言一种形式,标识预该位置后不是xxxx字符。

测试用例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Test {
    public static void main(String[] args) throws Exception {
        String regex = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$";        
 
        String value = "aaa";  // 长度不够
        System.out.println(value.matches(regex));
 
        value = "1111aaaa1111aaaaa";  // 太长
        System.out.println(value.matches(regex));
 
        value = "111111111"; // 纯数字
        System.out.println(value.matches(regex));
 
        value = "aaaaaaaaa"; // 纯字母
        System.out.println(value.matches(regex));
 
        value = "####@@@@#"; // 特殊字符
        System.out.println(value.matches(regex));
 
        value = "1111aaaa";  // 数字字母组合
        System.out.println(value.matches(regex));
 
        value = "aaaa1111"; // 数字字母组合
        System.out.println(value.matches(regex));
 
        value = "aa1111aa";    // 数字字母组合
        System.out.println(value.matches(regex));
 
        value = "11aaaa11";    // 数字字母组合
        System.out.println(value.matches(regex));
 
        value = "aa11aa11"; // 数字字母组合
        System.out.println(value.matches(regex));
    }
}


轻松理解正则表达式

无论是Java、Shell、Python、Perl都用正则表达式,说明它肯定是个好东西,那它到底是一个什么样东东呢?本文将通极易理解的语言对其进行描述,让你彻底理解正则表达式。...
  • yanquan345
  • yanquan345
  • 2014年02月22日 18:04
  • 1674

知道这20个正则表达式,能让你少写1000行代码

正则正则表达式,一个十分古老而又强大的文本处理工具,仅仅用一段非常简短的表达式语句,便能够快速实现一个非常复杂的业务逻辑。熟练地掌握正则表达式的话,能够使你的开发效率得到极大的提升. 正则表达式经常被...
  • IThelei
  • IThelei
  • 2017年02月07日 19:41
  • 479

用于查找文本的正则表达式

在记事本中,或文本编辑器中使用正则替换内容 通过使用正则表达式,可以在 Microsoft Expression Web 中执行繁复的查找和替换操作。如果您不知道所要查找的确切文本或代码,或者要查...
  • lihuang319
  • lihuang319
  • 2016年09月26日 15:15
  • 3148

必须知道的20个正则表达式

正则表达式,一个十分古老而又强大的文本处理工具,仅仅用一段非常简短的表达式语句,便能够快速实现一个非常复杂的业务逻辑。熟练地掌握正则表达式的话,能够使你的开发效率得到极大的提升。下面是@技匠整理的,在...
  • yabg_zhi_xiang
  • yabg_zhi_xiang
  • 2016年06月14日 11:38
  • 154

你总该知道的那么几个正则表达式

你总该知道的那么几个正则表达式虽然对正则的了解不是很深,只知道一些简单的语法规则,但是还是在这里稍微总结一下,那些我们该知道的正则表达式我们该知道那么几个符号...
  • lady_zhou
  • lady_zhou
  • 2017年12月28日 10:37
  • 70

十个应该知道的正则表达式例子

正则表达式是一个编程的艺术,很难调试,学习和理解,但强大的功能,仍吸引不少开发者编写正则表达式。让我们探索一下下面10个实际应用中的正则表达式。 1. 用户名正则表达式模式 ^[a-z0-9_...
  • u010399332
  • u010399332
  • 2014年03月04日 15:41
  • 299

你应该知道的10种java正则表达式

原文: http://www.mkyong.com/regular-expressions/10-java-regular-expression-examples-you-should-know/ ...
  • long316
  • long316
  • 2013年10月18日 13:42
  • 509

java-正则表达式判断移动联通电信手机号

package com.linbilin.phone;      import java.util.regex.Matcher;   import java.util.regex.Pattern...
  • younger_z
  • younger_z
  • 2017年05月07日 10:02
  • 1075

正则表达式中的"^"这个符号的一些思考

在学习正则表达式的时候,一些常见的规则我们都不难理解,但是有 一个正则表达式中的特殊字符让我一直有点搞不懂,就是”^”这个字符,文档上给出了解释是匹配输入的开始,如果多行标示被设置成了true,同时会...
  • sufubo
  • sufubo
  • 2016年03月27日 11:03
  • 17803

正则表达式之?、(?:pattern)、(?!pattern)、(?=pattern)理解及应用

今天朋友问我一个问题,是这样子的,通过正则表达式匹配html标签input包含hidden的字符串,具体如下: "" 匹配下来,应该输出: "" 读了这个问题之后,觉得挺简单的,直...
  • sunhuaer123
  • sunhuaer123
  • 2013年11月15日 19:09
  • 59534
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:我所知道的正则表达式
举报原因:
原因补充:

(最多只允许输入30个字)