近段涉及到了数据的解析,自然离不开对Regular Expressions(正则表达式)的温习;在jdk 官方源码中看到了对《Mastering Regular Expressions, 2nd Edition》的推荐;由Jeffrey E.F. Friedl大师主刀,O'Reilly于2002年再版。
对O'Reilly的书向有好感,像当年误入java的歧途,没看Java编程思想之类的,倒看了O'Reilly的一本影印版《java in a nutshell》,颇留记忆。
正则表达式的“祖先”可以一直上溯至对人类神经系统如何工作的早期研究。
Warren McCulloch 和Walter Pitts 这两位神经生理学家研究出一种数学方式来描述这些神经网络。
1956 年, 一位叫Stephen Kleene 的数学家在McCulloch 和Pitts 早期工作的基础上,发表了一篇标题为“神经网事件的表示法”的论文,引入了正则表达式的概念。
正则表达式就是用来描述他称为“正则集的代数”的表达式,因此采用“正则表达式”这个术语。
随后,发现可以将这一工作应用于使用Ken Thompson 的计算搜索算法的一些早期研究,Ken Thompson 是Unix 的主要发明人。
正则表达式的第一个实用应用程序就是Unix 中的qed 编辑器。
目前,正则表达式已经在很多软件中得到广泛的应用,包括*nix(Linux, Unix等),HP等操作系统;PHP,Perl,Python,C#,Java等开发环境,以及很多的应用软件中,For Example:网络上的搜索引擎,数据库的全文检索etc...本笔记是是自我学习过程的一个整理,例子或来源于书本,或自己枚举。
好了,废话一箩筐,切入正题。
1.正则表达式的介绍1.1、行开始和结束^begin line。
匹配行开头,如^cat匹配以cat开头的$end line。
匹配行结束,如cat$匹配以cat结束的;^cat$仅仅匹配该行有cat1.2、匹配给定的字符序列[...],表示in。
里面写入欲匹配的几个字符,如<sep[ea]r[ea]te>,匹配seperate,separete,separate";<H[123456]>匹配<H1>, <H2>, <H3>, etc.[a-z]代表从a到z 中的任意字符,[0-9]、[A-Z]分别代表0-9,A-Z中的任意数字或大写字母;“-”代表连续的从开始字符到结束;那么[0123456789abcdefABCDEF]也可以写为[0-9a-fA-F];对于这些频繁使用的字符,各语言分别做了相同的预定义。
1.3、匹配非给定的字符(非...)[^]匹配,表示not。
^和行开头的标记完全一样,但写的位置不一样,则表述的意思可能完全相反,用^表示否定的意思,更多是写在[]里面,如:q[^u]匹配q后面紧跟非u的字符,如Iraqi,qasida,zaqqum,Iraq;没错,"Iraq"这个单词也会被匹配,尽管q后面什么也没有,也可能有个空格、或回车符等。
否定字符的意思(翻译出来绕口):means "match a character that's not listed" and not "don't match what is listed."1.4、匹配任何字符.匹配,表示any。
任何字符,如07.04匹配:07_04,07-04,07 04,07.04 etc;如想要精确匹配07/04,07-04,or 07.04;需要写07[-./]04;没错当.在[]里面包含的时候,仅仅表示“.”字符而已,如果不在[]里面,需要转义\\. 如匹配形如x.y的小数:是[0-9]\\.[0-9],而非[0-9].[0-9]1.5、匹配几个给定的字符序列中的一个|匹配,表示or。
譬如gr[ea]y,也可以这样写:grey|gray 或gr(a|e)y;表的意思完全一样,即只能匹配gray或grey这两个单词。
再举个例子:假如我们读取一封邮件如:From: elvis@ (The King)Subject: be seein' ya aroundDate: Thu, 31 Oct 96 11:04:13Hi, ......... .................. .................. ......... ......... ......... .........yours smith我们打算只读取邮件的From: Subject: Date:(发件人、主题、发送日期)三行内容,那么我们可以用这个表达式来完成:"^(From|Subject|Date):"。
^表示行开头,匹配From或Subject或Date,后面紧跟:的内容;是的,当我们从指定的几个字符序列当中匹配其中的一个时候,需要借助()来对其进行分组,当然()的用途不仅体现在这里,后面还会赘述。
|的匹配是就近匹配原则,所以这样的写法就错误了:^From|Subject|Date: ,这个表达式描述的意思是,只要^From 或者Subject 或者Date:。
1.6、匹配单词边界与java中的转义字符\<、\>分别匹配单词的开头或结尾,如查找cat这个单词:\<cat\>。
\<cat或cat\>查找以cat开头或结尾的单词。
注:单词边界的匹配符并非所有版本的表达式语言都支持,至少在java中就不是这样。
在java中定义了“\b”匹配单词边界,“\B”匹配非单词边界,而没有定义匹配单词开头或结尾的边界符。
根据Java语法的约定,Java 源代码的字符串中的反斜线被解释为Unicode 转义或其他字符转义;目前被预定义的有:\b \t \n \f \r \" \' \\。
分别表示退格符、制表符、换行符、分页符、回车符、双引号、单引号、反斜线。
所以在java字符串中,除了这几个字符,其他任何必须用单斜线的写法都是错误。
因此必须在字符串字面值中使用两个反斜线,表示正则表达式受到保护,不被Java 字节码编译器解释;它们是为将来扩展正则表达式语言保留的,呵呵。
例如,当解释为正则表达式时,字符串字面值"\b" 与单个退格字符匹配,而"\\b" 与单词边界匹配。
字符串"\(hello\)" 是非法的,将导致编译时错误;要与字符串(hello) 匹配,必须使用字符串字面值"\\(hello\\)"。
小结:字符名称含义. dot 任何字符[?] character 给定的字符序列[^?] negated character 非给定的字符序列^ caret 行开头$ dollar 行结尾\< backslash less-than 单词开始边界*不是所有表达语言都支持的\> backslash greater-than 单词结束边界*不是所有表达语言都支持的| or; bar 或,必须匹配给定中的一个字符序列(?) parentheses 用于|的分界分组,或者作为捕获组1.7、数量词(匹配次数)X? X,一次或一次也没有X* X,零次或多次X+ X,一次或多次X{n} X,恰好n 次X{n,} X,至少n 次X{n,m} X,至少n 次,但是不超过m 次举例,我们想匹配<HR >或者<HR SIZE = 14 >,则可以写为<HR +(SIZE = 14)? >;想匹配<H1>..<H6>,则<H[1-6]+>。
注:X{1,}等于X+1.8、子表达式想对于一个完整的表达式而言,中间用()起来的部分被称为子表达式,如:^(Subject|Date):,Subject|Date就是一个子表达式,而[]起来的部分不能成为子表达式,如H[1-6]+,1-6不能成为子表达式。
几个例子:如匹配金额,如:$5、$44、$5.49等,可以这样写:\$[0-9]+(\.[0-9][0-9])?,分解成这样三个部分:\$ 和 ...+ 和...?,标识匹配$符(加斜线表示匹配美元符,而不是行结束标记符),至少一个数字,可包含含有小数点的两位小数。
如匹配时间,如"9:17 am" 、"12:30 pm",可以这样写:[0-9]?[0-9]:[0-9][0-9] (am|pm)。
它会匹配9:17 am 或者12:30 pm,但也匹配99:99 pm。
显然是不正确的,小时可有1位或2位,2位时候,第1位只能是1,第2位只能是0或1或2,那么小时部分可以写:(1[012]|[1-9])。
分钟部分,第1位是0-5,第2位是0-9;于是正确的写法是:(1[012]|[1-9]):[0-5][0-9] (am|pm)。
当我们采用2位的24小时制的时候,小时部分可以写为:0?[0-9]|1[0-9]|2[0-3]。
1.9、反向引用表达式在匹配时,表达式引擎会将小括号"( )" 包含的表达式所匹配到的字符串记录下来。
"小括号包含的表达式所匹配到的字符串" 不仅是在匹配结束后才可以使用,在匹配过程中也可以使用。
表达式后边的部分,可以引用前面"括号内的子匹配已经匹配到的字符串"。
引用方法是"\" 加上一个数字。
重复搜索前面某个分组匹配的文本,例如,\1代表分组1匹配的文本。
如:(\b[a-z]+\b) +\1可以用来匹配重复的单词,像go go, kitty kitty。
首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母(\b[a-z]+\b),然后是1个或几个空白符,最后是前面匹配的那个单词(\1)。
"\1" 引用第1对括号内匹配到的字符串,"\2" 引用第2对括号内匹配到的字符串……以此类推,如果一对括号内包含另一对括号,则外层的括号先排序号。
换句话说,哪一对的左括号"(" 在前,那这一对就先排序号。
额滴神啊,第一章终于学习完了,笔记主要对举的例子做了详细翻译,文字描述部分没有多赘述。
第一章还只是个入门介绍;第二章难度会提高很多了。
To be continued....2.扩展正则表达式的应用在这一章,主要通过几个例子的应用,来介绍如何应用正则表达式来匹配文本和查找文本。