正则表达式 Regular Expression
2016-04-05 17:06
155 查看
重新整理记录一下正则规则
最初这个概念是由Unix中的工具软件如sed和grep普及开的,通常简写为regex
几乎所有操作系统以及编程语言中都有正则表达式的应用
DFA
NFA
POSIX NFA
一. DFA引擎
速度:最快
特点:以文本为主导
主要使用者:awk、egrep、flex、lex、MySQL、Procmail
二. NFA引擎
速度:次之
特点:以表达式为主导,更容易操纵,一般程序员更偏爱NFA
只要使用者:GNU Emacs、Java、ergp、less、.NET、PCRE
三. POSIX NFA
意义:为了防止继续出现不同引擎的变体而产生的统一引擎
速度:最慢
使用者:mawk、GNU Emacs(使用时显式指定)
TIPS:
零宽度断言用于匹配那些:在X之前或之后的需求
0:始终代表整个表达式
1:((A)(B(C)))
2:(A)
3:(B(C))
4:(C)
捕获的子序列可以通过上面说的Back references在表达式中使用
引用转义构造
引用其它应该被解释为非转义构造的字符(转义字符想要正常使用)
另外,在Java中字符串中的反斜线被视为Unicode转义(写法\uxxxx)或其它字符转义,因此需要使用两个反斜线来代表原意
Pattern类
正则表达式的编译表示形式
指定为字符串的正则表达式必须首先被编译为此类的实例:
Pattern只创建正则对象,而具体功能的实现则由Matcher类提供,典型的调用顺序是:
Matcher类
通过解释某个固定的Pattern从而对固定character sequence执行匹配操作的引擎
Matcher对象一经建立,其Pattern和String都已经确定了
匹配器可以执行3种不同的匹配操作:
matches
将整个输入序列与该模式进行匹配
lookingAt
将输入序列从头开始与该模式匹配
find
扫描输入序列以查找与该模式匹配的下一个子序列
当由以上3个中任意一个匹配方法匹配成功后,就可做很多事情了,如:
m.group();//获取刚刚匹配的输入子序列
m.start();//获取刚刚匹配的输入子序列的开始索引
m.end();//同上,结束索引
完整的学习正则表达式和Java中的正则,我推荐两个地址:
正则表达式30分钟入门教程
JavaSE8的API中的java.util.regex.Pattern类
正则表达式所有东西还是不少的,较为复杂,而且平常使用的只是一小部分,没有必要全学完
可以学会常用的,不常用的用到时去上面两个地方查询
一、定义
Regular Expression - 正规的/有规律的表达式,是计算机科学的一个概念。使用一个字符串来描述、匹配一系列符合某个句法规则的字符串最初这个概念是由Unix中的工具软件如sed和grep普及开的,通常简写为regex
几乎所有操作系统以及编程语言中都有正则表达式的应用
二、引擎
正则引擎主要分为两大类:DFA
NFA
POSIX NFA
一. DFA引擎
速度:最快
特点:以文本为主导
主要使用者:awk、egrep、flex、lex、MySQL、Procmail
二. NFA引擎
速度:次之
特点:以表达式为主导,更容易操纵,一般程序员更偏爱NFA
只要使用者:GNU Emacs、Java、ergp、less、.NET、PCRE
三. POSIX NFA
意义:为了防止继续出现不同引擎的变体而产生的统一引擎
速度:最慢
使用者:mawk、GNU Emacs(使用时显式指定)
三、表达式的构造
表达式的基本思路:对字符串中的字符一个一个的进行匹配构造 | 匹配 |
---|
Characters - 字符 | |
---|---|
x | 字符x就带表某个字符x |
\\ | backslash 反斜杠 |
\0n | octal 八进制数n |
\xhh | hexadecimal 十六进制数hh |
\uhhhh | hexadecimal 十六进制数hhhh |
\t | tab 制表符(‘\u0009’) |
\n | newline 新行(‘\u000A’) |
\r | carriage return 回车(‘\u000D’) |
Character classes - 字符类型 | |
---|---|
[abc] | a,b, or c |
[^abc] | exclusive OR 任意character except a,c, or c |
[a-zA-Z] | a through z or A through Z |
[a-d[m-p]] | 并集,相当于[a-dm-p] |
[a-z&&[bcd]] | 交集,相当于[bcd] |
[a-z&&[^bc]] | 交集,相当于[ad-z] |
Predefined character classes - 预定义的字符类型 | |
---|---|
. | 任意character |
\d | A digit:[0-9] |
\D | A non-digit:[^0-9] |
\s | whitespace:[ \t\n\x0B\f\r],注意中括号的第一个字符是空格(ASCII32)不是\t |
\S | non-whitespace:[^\s] |
\w | A word:[a-zA-Z_0-9] |
\W | A non-word:[^\w] |
Boundary matchers - 边界匹配器 | |
---|---|
^ | The beginning of a line |
$ | The end of a line |
\b | A word boundary |
\B | A non-word boundary |
Greedy quantifiers - 贪婪量词 | |
---|---|
X? | X出现一次或not at all |
X* | X出现0次或多次 |
X+ | X出现一次或多次 |
X{n} | X固定出现n次 |
X{n,} | X至少出现n次 |
X{n,m} | X出现n到m次 |
Reluctant quantifiers - 勉强量词 | 由Greedy加”?”构成 |
---|---|
X?? | X出现一次或not at all |
X*? | X出现0次或多次 |
X+? | X出现一次或多次 |
X{n}? | X固定出现n次 |
X{n,}? | X至少出现n次 |
X{n,m}? | X出现n到m次 |
Possessive quantifiers - 独占量词 | 由Greedy加”+”构成 |
---|---|
X?+ | X出现一次或not at all |
X*+ | X出现0次或多次 |
X++ | X出现一次或多次 |
X{n}+ | X固定出现n次 |
X{n,}+ | X至少出现n次 |
X{n,m}+ | X出现n到m次 |
Logical operators - 逻辑操作符 | |
---|---|
XY | X后面跟Y |
X | Y |
(X) | X,作为一个捕获组capturing group |
Back references - 引用捕获组 | |
---|---|
\n | 代表捕获组中的第n个,第0个默认代表整个表达式 |
Special constructs - 特殊构造 | 包括非捕获组 |
---|---|
(?:X) | X作为非捕获组 |
(?=X) | X通过零宽度正向预测先行断言,匹配X前面的位置 |
(?!X) | X通过零宽度负预测先行断言,匹配后面跟的不是exp的位置 |
(?<=X) | X通过零宽度正回顾后发断言,匹配X后面的位置 |
(? | X通过零宽度负回顾后发断言,匹配前面不是X的位置 |
(?>X) | X作为独立组,非捕获 |
零宽度断言用于匹配那些:在X之前或之后的需求
四、一些点
1. Groups and capturing 组和捕获
捕获组的编号通过从左至右数左括号来编号,如表达式((A)(B(C)))中,0:始终代表整个表达式
1:((A)(B(C)))
2:(A)
3:(B(C))
4:(C)
捕获的子序列可以通过上面说的Back references在表达式中使用
2. Backslash 反斜线
\Backslash反斜线用于:引用转义构造
引用其它应该被解释为非转义构造的字符(转义字符想要正常使用)
另外,在Java中字符串中的反斜线被视为Unicode转义(写法\uxxxx)或其它字符转义,因此需要使用两个反斜线来代表原意
五、Java中
使用到的各种情况,功能直接或间接都是由java.util.regex包中的两个类Pattern和Matcher的方法来完成的Pattern类
正则表达式的编译表示形式
指定为字符串的正则表达式必须首先被编译为此类的实例:
Pattern p = Pattern.compile(regex);
Pattern只创建正则对象,而具体功能的实现则由Matcher类提供,典型的调用顺序是:
Pattern p = Pattern.compile("a*b"); Matcher m = p.matcher("aaaaaab"); boolean b = m.matches();
Matcher类
通过解释某个固定的Pattern从而对固定character sequence执行匹配操作的引擎
Matcher对象一经建立,其Pattern和String都已经确定了
匹配器可以执行3种不同的匹配操作:
matches
将整个输入序列与该模式进行匹配
lookingAt
将输入序列从头开始与该模式匹配
find
扫描输入序列以查找与该模式匹配的下一个子序列
当由以上3个中任意一个匹配方法匹配成功后,就可做很多事情了,如:
m.group();//获取刚刚匹配的输入子序列
m.start();//获取刚刚匹配的输入子序列的开始索引
m.end();//同上,结束索引
1. 匹配
/** * 1. 匹配 * 方法:使用String的matches() * 规则:第一位必须是1,第二位可以是3/5/8,后面是9位数字 */ String str1 = "13812312319"; String regex1 = "1[358]\\d{9}"; System.out.println(str1.matches(regex1));//true
2. 分割
/** * 2. 分割 * 方法:使用String的split() * 目标: * 2.1 任意个空格的分割 * 2.2 以.分割:需要注意取消.在正则中代表任意字符的含义 * 2.3 重复的字符来分割,需要使用分组,因为要求第2个字符跟第1个相同 */ String str21 = "asdf 909 sdfd sadf sdf"; String regex21 = "\u0020+";//空格就是\u0020(十进制32),也可以直接敲个 (前面是个空格),或者使用\\s String [] strs21 = str21.split(regex21); String str22 = "asdf.909.sdfd.sadf.sdf"; String regex22 = "\\.";//首先\.代表想正常使用点(而不是正则字符),又因为在Java的String中,所以再加\ String [] strs22 = str22.split(regex22); String str23 = "asdfssss909aaaasdfdbbbbbsadfttttsdf"; String regex23 = "([a-z])\\1+";//首先,第一个字符是任意小写英文;接着,第二个字符和第一个一样;最后,第二个字符出现至少一次 String [] strs23 = str23.split(regex23);
3. 替换
/** * 3. 替换 * 方法:使用String的replaceAll() * 目标: * 3.1 简单替换 * 3.2 使用被替换的内容替换,将重复的变为1个:需使用组,可以在方法第二个参数中使用美元符号$选取组 * 3.3 手机号码中4位用*号代替 */ String str31 = "asdf 909 sdfd sadf sdf"; String regex31 = "\u0020+"; str31 = str31.replaceAll(regex31, "1");//asdf19091sdfd1sadf1sdf String str32 = "asdf 909 sdfd sadf sdf"; String regex32 = "(\u0020)+"; str32 = str32.replaceAll(regex32, "$1");//asdf 909 sdfd sadf sdf String str33 = "13812312319"; String regex33 = "(.{3}).{4}(.{4})";//将需要保留的内容编组保留,以便之后还原,然后整体替换 str33 = str33.replaceAll(regex33, "$1****$2");
4. 获取
/** * 4. 获取 * 方法:创建一个匹配给定输入(String)和给定模式(Pattern)的匹配器(Matcher) * 目标: * 4.1 获取3个字母组成的单词 */ String str41 = "asdf, sdd*adf%$$sdsf"; String regex41 = "[a-z]{3}"; Pattern p = Pattern.compile(regex41);//创建正则模式对象 Matcher m = p.matcher(str41);//创建根据固定字符串和模式的匹配器 while(m.find()){//查找一个匹配的子序列 System.out.println(m.group());//返回之前匹配的输入子序列 }
完整的学习正则表达式和Java中的正则,我推荐两个地址:
正则表达式30分钟入门教程
JavaSE8的API中的java.util.regex.Pattern类
正则表达式所有东西还是不少的,较为复杂,而且平常使用的只是一小部分,没有必要全学完
可以学会常用的,不常用的用到时去上面两个地方查询
相关文章推荐
- 搜索—Problem_1001-Can you solve this equation?
- 微信公众号内支付(三)
- Java 线程池的常用方法分析
- leetcode 284. Peeking Iterator
- CodeForces 368B:Sereja and Suffixes【水】
- 《Linux内核设计与实现》第三章读书笔记
- 动态代理的应用
- haproxy简述
- JAVA基础----java中E,T,?的区别?【转】
- Linux服务器如何查看CPU占用率、内存占用、带宽占用
- python字典和集合,frozenset和哈希值
- 安装pcre-8.30报错
- CCF Z字形扫描
- Linux软连接和硬链接
- 程序员面试宝典16章操作系统整理笔记及补充(个人理解整理版)
- Eclipse使用maven构建web项目
- iOS地理位置解析
- Android小程序-Walker注册页面(二)
- if __name__ == '__main__'在python中的应用
- 添加约束