Skip navigation.

王志军个人空间

工作、生活、健康

Posts tagged with "正则表达式"

JAVA 正则表达式实现

URL: http://www.javasalon.net/java/src/pages/3/1120_1012475928.htm

偶尔搜到的东东,不记得是那位的Bolg了。很不错的文章。。。。
§1黑暗岁月
有一个String,如何查询其中是否有y和f字符?最黑暗的办法就是:
程序1:我知道if、for语句和charAt()啊。
class Test{
public static void main(String args[]) {
String str="For my money, the important thing "+
"about the meeting was bridge-building";
char x='y';
char y='f';
boolean result=false;
for(int i=0;i<str.length();i++){
char z=str.charAt(i); //System.out.println(z);
if(x==z||y==z) {
result=true;
break;
}
else result=false;
}
System.out.println(result);
}
}
好像很直观,但这种方式难以应付复杂的工作。如查询一段文字中,是否有is?是否有thing或ting等。这是一个讨厌的工作。
§2 Java的java.util.regex包
按照面向对象的思路,把希望查询的字符串如is、thing或ting封装成一个对象,以这个对象作为模板去匹配一段文字,就更加自然了。作为模板的那个东西就是下面要讨论的正则表达式。先不考虑那么复杂,看一个例子:
程序2:不懂。先看看可以吧?
import java.util.regex.*;
class Regex1{
public static void main(String args[]) {
String str="For my money, the important thing "+
"about the meeting was bridge-building";
String regEx="a|f"; //表示a或f
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(str);
boolean result=m.find();
System.out.println(result);
}
}
如果str匹配regEx,那么result为true,否则为flase。如果想在查找时忽略大小写,则可以写成:
Pattern p=Pattern.compile(regEx,Pattern.CASE_INSENSITIVE);
虽然暂时不知道Pattern(模板、模式)和Matcher(匹配器)的细节,程序的感觉就比较爽,如果先查询is、后来又要查询thing或ting,我们只需要修改一下模板Pattern,而不是考虑if语句和for语句,或者通过charAt()。
1、写一个特殊的字符串??正则表达式如a|f。
2、将正则表达式编译成一个模板:p
3、用模板p去匹配字符串str。
思路清楚了,现在看Java是如何处理的(Java程序员直到JDK1.4才能使用这些类。
§3 Pattern类与查找
①public final class java.util.regex.Pattern是正则表达式编译后的表达法。下面的语句将创建一个Pattern对象并赋值给句柄p:Pattern p=Pattern.compile(regEx);
有趣的是,Pattern类是final类,而且它的构造器是private。也许有人告诉你一些设计模式的东西,或者你自己查有关资料。这里的结论是:Pattern类不能被继承,我们不能通过new创建Pattern类的对象。
因此在Pattern类中,提供了2个重载的静态方法,其返回值是Pattern对象(的引用)。如:
public static Pattern compile(String regex) {
return new Pattern(regex, 0);
}
当然,我们可以声明Pattern类的句柄,如Pattern p=null;
②p.matcher(str)表示以用模板p去生成一个字符串str的匹配器,它的返回值是一个Matcher类的引用,为什么要这个东西呢?按照自然的想法,返回一个boolean值不行吗?
我们可以简单的使用如下方法:
boolean result=Pattern.compile(regEx).matcher(str).find();
呵呵,其实是三个语句合并的无句柄方式。无句柄常常不是好方式。后面再学习Matcher类吧。先看看regEx??这个怪咚咚。
§4 正则表达式之限定符
正则表达式(Regular Expression)是一种生成字符串的字符串。晕吧。比如说,String regEx="me+";这里字符串me+ 能够生成的字符串是:me、mee、meee、meeeeeeeeee等等,一个正则表达式可能生成无穷的字符串,所以我们不可能(有必要吗?)输出正则表达式产生的所有东西。
反过来考虑,对于字符串:me、mee、meee、meeeeeeeeee等等,我们能否有一种语言去描述它们呢?显然,正则表达式语言是这种语言,它是一些字符串的模式??简洁而深刻的描述。
我们使用正则表达式,用于字符串查找、匹配、指定字符串替换、字符串分割等等目的。

生成字符串的字符串??正则表达式,真有些复杂,因为我们希望由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)描述任意的字符串,而且要准确。
先搞几个正则表达式例子:
程序3:我们总用这个程序测试正则表达式。
import java.util.regex.*;
class Regex1{
public static void main(String args[]) {
String str="For my money, the important thing ";
String regEx="ab*";
boolean result=Pattern.compile(regEx).matcher(str).find();
System.out.println(result);
}
}//ture
①"ab*"??能匹配a、ab、abb、abbb……。所以,*表示前面字符可以有零次或多次。如果仅仅考虑查找,直接用"a"也一样。但想想替换的情况。 问题regEx="abb*"结果如何?
②"ab+"??能匹配ab、abb、abbb……。等价于"abb*"。问题regEx="or+"结果如何?
③"or?"??能匹配o和or。? 表示前面字符可以有零次或一次。
这些限定符*、+、?方便地表示了其前面字符(子串)出现的次数(我们用{}来描述):
x* 零次或多次 ≡{0,}
x+ 一次或多次 ≡{1,}
x? 零次或一次 ≡{0,1}
x{n} n次(n>0)
x{n,m} 最少n次至最多m次(0<n<m)
x{n,} 最少n次,

现在我们知道了连续字符串的查找、匹配。下面的是一些练习题:
①查找粗体字符串(不要求精确或要求精确匹配),写出其正则表达式:
str regEX(不要求精确) regEX(要求精确) 试一试
abcffd b或bcff或bcf*或bc*或bc+ bcff或bcf{2} bc{3}
gooooogle o{1,}、o+ o{5}
banana (an)+ (an){2}a、a(na) {2}



②正则表达式匹配字符串,输出是什么?
§5替换(删除)、Matcher类
现在我们可能厌烦了true/false,我们看看替换。如把book,google替换成bak(这个文件后缀名,在EditPlus中还行)、look或goooogle。
程序4:字符串的替换。
import java.util.regex.*;
class Regex1{
public static void main(String args[]) {
String regEx="a+";//表示一个或多个a
String str="abbbaaa an banana hhaana";
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(str);
String s=m.replaceAll("⊙⊙"); // ("") 删除
System.out.println(s);
}
}
这个程序与前面的程序的区别,在于使用了m.replaceAll(String)方法。看来Matcher类还有点用处。
① public final class Matcher 是一个匹配器。可以把他看成一个人,一手拿着模子(Pattern类的对象),一手拿着一个字符序列(CharSequence),通过解释该模子而对字符序列进行匹配操作(match operations)。常常我们这样编程:“喂,模子p,你和字符串str一起创建一个匹配器对象”。即 Matcher m=p.matcher(str);
② m可以进行一些操作,如public String replaceAll(String replacement),它以replacement替换所有匹配的字符串。
§6正则表达式之特殊字符
我们熟悉这样一个字符串"\n" 如:System.out.print(s+"\nbbb");这是Java中常用的转移字符之一。其实转移字符就是一种正则表达式,它使用了特殊字符 \ 。

下面是正则表达式中常用的特殊字符:
匹配次数符号 * + ? {n}、{n,}、{n,m}
“或”符号 | 程序2已经使用过了
句点符号 . 句点符号匹配所有字符(一个),包括空格、Tab字符甚至换行符。
方括号 [ ] 仅仅匹配方括号其中的字符)
圆括号 () 分组,圆括号中的字符视为一个整体。
连字符 - 表示一个范围。
“否”符号 ^ 表示不希望被匹配的字符(排除)
我们一下子学不了太多的东西,这不是正则表达式的全部内容和用法。但已经够我们忙活的了。我们用程序4 验证。(⊙⊙表示替换的字符)
① regEx为下列字符串时,能够表示什么?
regEx 匹配 测试用str
(a|b){2} aa、ab、bb、ba aabbfooaabfooabfoob
a[abc]b aab、abb、acb 3dfacb5ooyfo6abbfooaab
. all string 3dfac
a. aa、ax……等等 3dfacgg
d[^j]a daa、d9a等等,除dja 3dfacggdjad5a
[d-g][ac]c dac、ecc、gac等 3dfacggggccad5c
[d-g].{2}c d⊙⊙c…… 3dfacggggccad5c
g{1,10} g、ggg…… 3dfacggggccad5c
[a|c][^a] 3dfacggggccad5c

② 下列字符串如何用regEx表示?
测试用str 匹配 regEx
aabbfoaoabfooafobob a⊙⊙b a..b
aabbfoaaobfooafbob a⊙b、除aab a[^a]b、
gooooooogle oooo……变成oo o{2,20}
一本书中的“tan”、“ten”、“tin”和“ton” t.n、t[aeio]n
abcaccbcbaacabccaa 删除ac、ca (ca)|(ac)
abccbcbaabca 再删除ab、ba 结果ccbcca(如何与上面的合并)



注:
1、String str="一本书中的tan、ten、tin和ton";
输出: 一本书中的⊙⊙、⊙⊙、⊙⊙和⊙⊙
2、String str=" abcaccbcbaacabccaa "; 输出:ccbcca
程序5:if、for语句和charAt(),886。
import java.util.regex.*;
class Regex1{
public static void main(String args[]) {
String str="abcaccbcbaacabccaa";
String regEx="(ac)|(ca)";
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(str);
String s=m.replaceAll("");//⊙⊙
regEx="(ab)|(ba)";
p=Pattern.compile(regEx);
s=p.matcher(s).replaceAll("");

System.out.print(s+"\n");
}
}

§7 开始
好像我们知道了一些正则表达式与 Java的知识,事实上,我们才刚刚开始。这里列出我们知道的东西,也说一点我们不知道的东西。
① Java 在JDK1.4引入了(java.util.regex包)以支持正则表达式,包中有两个类,分别是Pattern和Matcher。它们都有很多的方法,我们还不知道。String类中的split、matches方法等等也使用到了正则表达式。StringTokenizer是否没有用处了?
② 正则表达式是一门语言。有许多正则表达式语法、选项和特殊字符,在Pattern.java源文件中大家可以查看。可能比想象中的要复杂。系统学习正则表达式的历史、语法、全部特殊字符(相当于Java中的关键字的地位),组合逻辑是下一步的事情。
③ 正则表达式是文本处理的重要技术,在Perl、PHP、Python、JavaScript、Java、C#中被广泛支持。被列为“保证你现在和未来不失业的十种关键技术”,呵呵,信不信由你


相关链接:
http://dev.csdn.net/develop/article/83/83039.shtm
http://www.regular-expressions.info/java.html ****
http://java.sun.com/docs/books/tutorial/essential/regex/ ***
http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html
http://irw.ncit.edu.tw/peterju/webslide/re/ **
http://soft.yesky.com/lesson/211/2350711.shtml **
http://www.regexlab.com/zh/regref.htm
http://www.cs.princeton.edu/introcs/72regular/
http://jspwiki.org/wiki/JavaRegularExpressions#section-JavaRegularExpressions-BackslashesEscapesAndQuoting
http://java.sun.com/developer/technicalArticles/releases/1.4regex/
http://hi.baidu.com/bestwisheslhl/blog/item/6e27e21f2fda52f5e1fe0bd9.html ***
http://hi.baidu.com/personnel/blog/item/6ac534a8ac7ef2b1ca130c23.html ***

Java正则表达式详解

,

正规表达式教程

正则表达式
一、简介

正则表达式这个名词,相信很多人都听说过,这个名词最早起源于1956 年, 一位叫 Stephen Kleene 的美国数学家在 McCulloch 和 Pitts 早期工作的基础上,发表了一篇标题为“神经网事件的表示法”的论文,引入了正则表达式的概念。正则表达式就是用来描述他称为“正则集的代数”的表达式,因此采用“正则表达式”这个术语。

随后,发现可以将这一工作应用于使用Ken Thompson 的计算搜索算法的一些早期研究,Ken Thompson是Unix 的主要发明人。正则表达式的第一个实用应用程序就是 Unix 中的qed 编辑器。

Q: 正则表达式,能够为我们做什么呢?

A: 基于文本的编辑器和搜索工具中的一个重要部分。正则表达式可以让用户通过使用一系列的特殊字符构建匹配模式,然后把匹配模式与数据文件、程序输入以及WEB页面的表单输入等目标对象进行比较,根据比较对象中是否包含匹配模式,执行相应的程序。

下面我们就一步一步的结合它的语法,来介绍正则表达式的使用。

二、初次接触正则表达式

我们先来了解正则表达式的一些基本概念。正则表达式作为一种表示语言,其定义了自己的一套描述方式,来描述各种各样的字符类。下面摘取msdn中的一段定义。(ms-help: //MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpconcharacterclasses.htm)

字符转义表
字符类
含义

.
与除 \n 以外的任何字符匹配。如果通过 Singleline 选项(请参阅正则表达式选项)进行了修改,则句点字符与任何字符匹配。

[aeiou]
与指定字符集中包含的任何单个字符匹配。

[^aeiou]
与不在指定字符集中的任何单个字符匹配。

[0-9a-fA-F]
使用连字号 (–) 允许指定连续字符范围。

\p{name}
与 name 指定的命名字符类中的任何字符匹配。支持的名称为 Unicode 组和块范围。例如 Ll£?Nd£?Z£?IsGreek£?IsBoxDrawing。

\P{name}
与在 {name} 中指定的组和块范围中未包含的文本匹配。

\w
与任何单词字符匹配。等效于 Unicode 字符类别
[\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}]。如果通过 ECMAScript 选项指定了符合 ECMAScript 的行为,则 \w 等同于 [a-zA-Z_0-9]。

\W
与任何非单词字符匹配。等效于 Unicode 类别 [^\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}]。如果通过 ECMAScript 选项指定了符合 ECMAScript 的行为,则 \W 等同于 [^a-zA-Z_0-9]。

\s
与任何空白字符匹配。等效于 Unicode 字符类别 [\f\n\r\t\v\x85\p{Z}]。如果通过 ECMAScript 选项指定了符合 ECMAScript 的行为,则 \s 等同于 [ \f\n\r\t\v]。

\S
与任何非空白字符匹配。等效于 Unicode 字符类别 [^\f\n\r\t\v\x85\p{Z}]。如果通过 ECMAScript 选项指定了符合 ECMAScript 的行为,则 \S 等同于 [^ \f\n\r\t\v]。

\d
与任何十进制数字匹配。与 Unicode 的 \p{Nd} 和非 Unicode 的 [0-9] 以及 ECMAScript 行为一样。

\D
与任何非数字匹配。与 Unicode 的 \P{Nd} 和非 Unicode 的 [^0-9] 以及 ECMAScript 行为一样。


上表列举了,正则表达式中最最基本的语法定义,了解这些,我们已经可以定义一些简单的规则了,例如:

1. 匹配所有的字符

当然是什么都不用写(@_@)

2. 匹配所有的英文字符

a) \w

b) [a-zA-Z_0-9]

3. 匹配十进制数字

a) \d

b) [0-9]

看上面的例子,是不是觉得很简单呢,不过,到目前为止,这样写出来的规则,还有一个很大的缺陷,就是没有声明匹配字符的个数?

Q: 我希望要匹配的字符为5个英文字母

A: ???

光了解上面的知识是,无法解决这个的L。那正则表达式中是如何解决这个问题的呢,我们来看下面这个表:

(ms-help://MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpconquantifiers.htm)

限定符表
限定符
说明

*
指定零个或更多个匹配;例如 \w* 或 (abc)*。与 {0,} 相同。

+
指定一个或多个匹配;例如 \w+ 或 (abc)+。与 {1,} 相同。

?
指定零个或一个匹配;例如 \w? 或 (abc)?。与 {0,1} 相同。

{n}
指定恰好 n 个匹配;例如 (pizza){2}。

{n,}
指定至少 n 个匹配;例如 (abc){2,}。

{n,m}
指定至少 n 个但不多于 m 个匹配。

*?
指定尽可能少地使用重复的第一个匹配 (lazy *)。

+?
指定尽可能少地使用重复但至少使用一次 (lazy +)。

??
指定使用零次重复(如有可能)或一次重复 (lazy ?)。

{n}?
等效于 {n} (lazy {n})。

{n,}?
指定尽可能少地使用重复,但至少使用 n 次 (lazy {n,})。

{n,m}?
指定介于 n 次和 m 次之间、尽可能少地使用重复 (lazy {n,m})。


上表中列出了,正则表达式的限定方式,配合这些字符的使用,我们就可以很方便的编写更为强劲的正则表达式了。

例如:

1. 匹配零个或多个所有的字符

*

2. 匹配一个或多个所有字符

+

3. 匹配零个或多个所有的英文字符

\w*

4. 匹配一个或多个所有的英文字符

[a-zA-Z0-9]+

5. 匹配3个十进制数字

\d{3}

6. 匹配最少3个十进制数字

\d{3,}

7. 匹配3个到6个十进制数字

\d{3,6}

现在我们可以解答上面问题了:

Q: 我希望要匹配的字符为5个英文字母

A: \w{5}

很高兴,我们已解决了上面的问题,不过,新的问题总是在不断的出现。我如何限制匹配字符出现在哪里呢?

Q: 我希望匹配以doc开头的字符串

A: ???

为了解决这个问题,我们先来看看这个表:

(ms-help://MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpconatomiczero-widthassertions.htm)

原子零宽度断言
断言
说明

^
指定匹配必须出现在字符串的开头或行的开头。有关更多信息,请参阅正则表达式选项中的 Multiline 选项。

$
指定匹配必须出现在以下位置:字符串结尾、字符串结尾的 \n 之前或行的结尾。有关更多信息,请参阅正则表达式选项中的 Multiline 选项。

\A
指定匹配必须出现在字符串的开头(忽略 Multiline 选项)。

\Z
指定匹配必须出现在字符串的结尾或字符串结尾的 \n 之前(忽略 Multiline 选项)。

\z
指定匹配必须出现在字符串的结尾(忽略 Multiline 选项)。

\G
指定匹配必须出现在当前搜索开始的位置(此位置通常是上一次搜索结束位置之后的第一个字符)。例如,请考虑一个由分离的字符组组成的串联字符串,其中每一组的长度都为 n 个字符。在每个字符组中搜索匹配时,如果正则表达式在 0、n、2n、3n 等字符位置找到匹配,则该正则表达式成功。仅当匹配出现在定位组边界上时才会成功。

\b
指定匹配必须出现在 \w(字母数字)和 \W(非字母数字)字符之间的边界上。匹配必须出现在单词边界上,即出现在由空格分隔的单词中第一个或最后一个字符上。

\B
指定匹配不得出现在 \b 边界上。


相信大家都注意到了,在这个表中第一个断言字符就是我们需要的@_@.

例如,^ 指定当前位置在行或字符串的开头。因此,正则表达式 ^FTP 只会返回那些在行的开头出现的字符串“FTP”的匹配项。

看来上面碰到的问题,又可以解决了,让我们一起来解决上面的问题:

Q: 我希望匹配以doc开头的字符串

A: ^doc

以上我们初步了解了什么是正则表达式,已经了解其最基本的语法,当作热身@_@,接下来,才正式进入主题,我们会从第二篇开始深入探讨正则表达式的使用。
在前一篇文章中,介绍了一些初步的正则表达式的基本概念,相信很多人对正则表达式的基本知识有所了解,接下来,我们结合一些实际的编程示例来掩饰说明正则表达式的作用。

首先,我们先看几个实际的例子:

1. 验证输入字符是否全部为英文字符

java script:

var ex = "^\\w+$";

var re = new RegExp(ex,"i");

return re.test(str);

vb script

Dim regEx,flag,ex

ex = "^\w+$"

Set regEx = New RegExp

regEx.IgnoreCase = True

regEx.Global = True

regEx.Pattern = ex

flag = regEx.Test( str )

C#

System.String ex = @"^\w+$";

System.Text.RegularExpressions.Regex reg = new Regex( ex ); bool flag = reg.IsMatch( str );

2. 验证邮件格式

C#

System.String ex = @"^\w+@\w+\.\w+$";

System.Text.RegularExpressions.Regex reg = new Regex( ex );

bool flag = reg.IsMatch( str );

3. 更改日期的格式(用 dd-mm-yy 的日期形式代替 mm/dd/yy 的日期形式)

C#

String MDYToDMY(String input)

{

return Regex.Replace(input,

"\\b(?<month>\\d{1,2})/(?<day>\\d{1,2})/(?<year>\\d{2,4})\\b",

"${day}-${month}-${year}");

}

4. 从 URL 提取协议和端口号

C#

String Extension(String url)

{

Regex r = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/",

RegexOptions.Compiled);

return r.Match(url).Result("${proto}${port}");

}

这里的例子可能是我们在网页开发中,通常会碰到的一些正则表达式,尤其在第一个例子中,给出了使用java script,vb script,C#等不同语言的实现方式,大家不难看出,对于不同的语言来说,正则表达式没有区别,只是正则表达式的实现类不同而已。而如何发挥正则表达式的公用,也要看实现类的支持。

(摘自msdn: Microsoft .NET 框架 SDK 提供大量的正则表达式工具,使您能够高效地创建、比较和修改字符串,以及迅速地分析大量文本和数据以搜索、移除和替换文本模式。ms-help: //MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpconregularexpressionslanguageelements.htm)

下面我们逐个来分析这些例子:

1-2,这两个例子很简单,只是简单的验证字符串是否符合正则表达式规定的格式,其中使用的语法,在第一篇文章中都已经介绍过了,这里做一下简单的描述。

第1个例子的表达式: ^\w+$

^ -- 表示限定匹配开始于字符串的开始

\w – 表示匹配英文字符

+ -- 表示匹配字符出现1次或多次

$ -- 表示匹配字符到字符串结尾处结束

验证形如asgasdfs的字符串

第2个例子的表达式: ^\w+@\w+.\w+$

^ -- 表示限定匹配开始于字符串的开始

\w – 表示匹配英文字符

+ -- 表示匹配字符出现1次或多次

@ -- 匹配普通字符@

\. – 匹配普通字符.(注意.为特殊字符,因此要加上\转译)

$ -- 表示匹配字符到字符串结尾处结束

验证形如dragontt@sina.com的邮件格式


第3 个例子中,使用了替换,因此,我们还是先来看看正则表达式中替换的定义:

(ms-help://MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpconsubstitutions.htm)

替换
字符
含义

$123
替换由组号 123(十进制)匹配的最后一个子字符串。

${name}
替换由 (?<name> ) 组匹配的最后一个子字符串。

$$
替换单个“$”字符。

$&
替换完全匹配本身的一个副本。

$`
替换匹配前的输入字符串的所有文本。

$'
替换匹配后的输入字符串的所有文本。

$+
替换最后捕获的组。

$_
替换整个输入字符串。


分组构造
(ms-help://MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpcongroupingconstructs.htm)

分组构造
定义

( )
捕获匹配的子字符串(或非捕获组;有关更多信息,请参阅正则表达式选项中的 ExplicitCapture 选项。)使用 () 的捕获根据左括号的顺序从 1 开始自动编号。捕获元素编号为零的第一个捕获是由整个正则表达式模式匹配的文本。

(?<name> )
将匹配的子字符串捕获到一个组名称或编号名称中。用于 name 的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如 (?'name')。

(?<name1-name2> )
平衡组定义。删除先前定义的 name2 组的定义并在 name1 组中存储先前定义的 name2 组和当前组之间的间隔。如果未定义 name2 组,则匹配将回溯。由于删除 name2 的最后一个定义会显示 name2 的先前定义,因此该构造允许将 name2 组的捕获堆栈用作计数器以跟踪嵌套构造(如括号)。在此构造中,name1 是可选的。可以使用单引号替代尖括号,例如 (?'name1-name2')。

(?: )
非捕获组。

(?imnsx-imnsx: )
应用或禁用子表达式中指定的选项。例如,(?i-s: ) 将打开不区分大小写并禁用单行模式。有关更多信息,请参阅正则表达式选项。

(?= )
零宽度正预测先行断言。仅当子表达式在此位置的右侧匹配时才继续匹配。例如,\w+(?=\d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。

(?! )
零宽度负预测先行断言。仅当子表达式不在此位置的右侧匹配时才继续匹配。例如,\b(?!un)\w+\b 与不以 un 开头的单词匹配。

(?<= )
零宽度正回顾后发断言。仅当子表达式在此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。

(?<! )
零宽度负回顾后发断言。仅当子表达式不在此位置的左侧匹配时才继续匹配。

(?> )
非回溯子表达式(也称为贪婪子表达式)。该子表达式仅完全匹配一次,然后就不会逐段参与回溯了。(也就是说,该子表达式仅与可由该子表达式单独匹配的字符串匹配。)


我们还是先简单的了解一下这两个概念:

分组构造:

最基本的构造方式就是(),在左右括号中括起来的部分,就是一个分组;

更进一步的分组就是形如:(?<name> )的分组方式,这种方式与第一种方式的不同点,就是对分组的部分进行了命名,这样就可以通过该组的命名来获取信息;

(还有形如(?= )等等的分组构造,我们这篇的例子中也没有使用到,下次我们在来介绍)

替换:

上面提到了两种基本的构造分组方式()以及(?<name> ),通过这两种分组方式,我们可以得到形如$1,${name}的匹配结果。


这样说,可能概念上还是有些模糊,我们还是结合上面的例子来说:

第三个例子的正则表达式为:\\b(?<month>\\d{1,2})/(?<day>\\d{1,2})/(?<year>\\d{2,4})\\b

(解释一下,为什么这里都是\\一起用:这里是C#的例子,在C#语言中\是转译字符,要想字符串中的\不转译,就需要使用\\或者在整个字符串的开始加上@标记,即上面等价与

@”\b(?<month>\d{1,2})/(?<day>\d{1,2})/(?<year>\d{2,4}\b”)

\b -- 是一种特殊情况。在正则表达式中,除了在 [] 字符类中表示退格符以外,\b 表示字边界(在 \w 和 \W 字符之间)。在替换模式中,\b 始终表示退格符

(?<month>\d{1,2}) – 构造一个名为month的分组,这个分组匹配一个长度为1-2的数字

/ -- 匹配普通的/字符

(?<day>\d{1,2}) --构造一个名为day的分组,这个分组匹配一个长度为1-2的数字

/ -- 匹配普通的/字符

(?<year>\d{2,4}\b”) --构造一个名为year的分组,这个分组匹配一个长度为2-4的数字


这里还不能够看出这些分组的作用,我们接着看这一句

${day}-${month}-${year}

${day} – 获得上面构造的名为day的分组匹配后的信息

- -- 普通的-字符

${month} --获得上面构造的名为month的分组匹配后的信息

- -- 普通的-字符

${year} --获得上面构造的名为year的分组匹配后的信息


举例来说:

将形如04/02/2003的日期使用例3种的方法替换

(?<month>\d{1,2}) 分组将匹配到04由${month}得到这个匹配值

(?<day>\d{1,2}) 分组将匹配到02由${day}得到这个匹配值

(?<year>\d{1,2}) 分组将匹配到2003由${year}得到这个匹配值

了解了这个例子后,我们在来看第4个例子就很简单了。


第4个例子的正则

^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/

^ -- 表示限定匹配开始于字符串的开始

(?<proto>\w+) – 构造一个名为proto的分组,匹配一个或多个字母

: -- 普通的:字符

// -- 匹配两个/字符

[^/] – 表示这里不允许是/字符

+? – 表示指定尽可能少地使用重复但至少使用一次匹配

(?<port>:\d+) – 构造一个名为port的分组,匹配形如:2134(冒号+一个或多个数字)

? – 表示匹配字符出现0次或1次

/ -- 匹配/字符


最后通过${proto}${port}来获取两个分组构造的匹配内容

(有关Regex对象的用法,参考

ms-help://MS.VSCC/MS.MSDNVS.2052/cpref/html/frlrfSystemTextRegularExpressionsRegexMembersTopic.htm)


好了,本次介绍的几个例子,也讲得差不多了,希望大家有所收获,下次,在就一些特殊的要求,进一步探讨正则表达式的实现。
前面的文章中,介绍了正则表达式的基本语法,以及一些简单的例子。但这些并不是我们会遇到的全部问题,有些时候我们不得不编写一些较为复杂的正则表达式来解决我们的实际问题。

这里,我先提几个问题,然后,我们逐个运用正则表达式的知识来解决。

1. 符合两种条件之一,都成立,例如:是纯数字或者纯字符

123(true),hello(true),234.test23(false)

2. 要得到不以数字开头的字符组合

如:How2234do>you234do,希望得到How和you而不是do,do

3. 得到以数字开头的字符组合

上例中,得到do和do

4. 要得到不以数字结尾的字符组合

还是上面的情况,要得到的是Ho,do,yo,do

5. 得到以数字结尾的字符组合

同上例,得到Ho,do,yo,do

6. 不允许字符中ab同时出现

例:nihaoma(true),above(false),agoodboy(true)


下面我们开始着手解决这些问题:

第一个:符合两种条件之一,都成立

这种要求可能代表着一种普遍的要求,我们先来看看这个表

替换构造
替换构造
定义

|
与由|(垂直条)字符分隔的术语中的任何一个术语匹配;例如 cat|dog|tiger。使用最左侧的成功匹配。

(?(expression)yes|no)
如果表达式在此位置匹配,则与“yes”部分匹配;否则,与“no”部分匹配。“no”部分可省略。表达式可以是任何有效的表达式,但它将变为零宽度断言,因此该语法等效于 (?(?=expression)yes|no)。请注意,如果表达式是命名组的名称或捕获组编号,则替换构造将解释为捕获测试(在本表的下一行对此进行了描述)。若要避免在这些情况下产生混淆,则可以显式拼出内部 (?=expression)。

(?(name)yes|no)
如果命名捕获字符串有匹配,则与“yes”部分匹配;否则,与“no”部分匹配。“no”部分可省略。如果给定的名称不与此表达式中使用的捕获组的名称或编号对应,则替换构造将解释为表达式测试(在本表的上一行进行了描述)。


(ms-help://MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpconalternationconstructs.htm)

在这个表中,我们看到,正则中为了解决这一类问题,定义了|来表示或者的关系,就好像常见的或运算符一样,现在我们来看看如何利用|来解决我们的问题。

1. 先为可选择的表达式撰写表达式:

a) 纯数字 – [0-9]*

b) 纯字母 – [a-zA-Z]*

2. 将可选条件用|连接起来就是我们所需的

^[0-9]*$|^[a-zA-Z]*$

(这里我特别对两个条件加上了^和$限定符,这在验证字符串是否完全符合要求时,是十分必要的,如果不加这两个限定符,有兴趣的朋友可以自己试一下效果。


后面四个问题,其实是一类的,所以我们把它们放在一起处理。接下来我们来解决第二到第四个问题:

首先,我们回顾一下上次介绍的分组构造:

(?= )
零宽度正预测先行断言。仅当子表达式在此位置的右侧匹配时才继续匹配。例如,\w+(?=\d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。

(?! )
零宽度负预测先行断言。仅当子表达式不在此位置的右侧匹配时才继续匹配。例如,\b(?!un)\w+\b 与不以 un 开头的单词匹配。

(?<= )
零宽度正回顾后发断言。仅当子表达式在此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。

(?<! )
零宽度负回顾后发断言。仅当子表达式不在此位置的左侧匹配时才继续匹配。


可以看到,这个表的这四种规则,正好可以解决我们的问题。

@_@先解决我们的问题再说:

第二例:要得到不以数字开头的字符组合

(?<!\d)[a-zA-Z]{2,}

(?<!\d) -- 限定字符的开头不为数字才匹配

[a-zA-Z]{2,} – 描述匹配2个以上的字母

(注:这是取巧的做法,因为,按照我们的逻辑How2234do>you234do中的两个do的o字母也是符合的,不过,这不是我们想要的,当然还有其他的解决办法,可以根据实际的情况来处理,这里是为了讲解这个方法@_@)

第三例:得到以数字开头的字符组合

(?<=\d)[a-zA-Z]+

(?<=\d) – 限定为数字开头的字符才匹配

[a-zA-Z]+ -- 描述匹配1个或多个字母

第四例:要得到不以数字结尾的字符组合

[a-zA-Z]+(?!\d)

[a-zA-Z]+ -- 描述匹配1个或多个字母

(?!\d) – 限定不为数字结尾的字母才匹配

第五例:得到以数字结尾的字符组合

[a-zA-Z]+(?=\d)

[a-zA-Z]+ -- 描述匹配1个或多个字母

(?=\d) – 限定为数字结尾的字母才匹配


第六例:不允许字符中ab同时出现

^(?!.*?ab).*$

(?!.*?ab) – 限定不允许出现ab相连的字符

.* -- 任意字符

正则表达式系统教程

URL: http://www.pconline.com.cn/pcedu/empolder/wz/php/0501/533294.html

正则表达式(regular expression)



 关键字:正则表达式,Regular Expression
  原著:笑容
 创作于:2004年05月03日
最后更新:2004年05月04日 21:12
引用地址:正则表达式(regular expression)
版权声明:使用创作公用版权协议



前言

  正则表达式是烦琐的,但是强大的,学会之后的应用会让你除了提高效率外,会给你带来绝对的成就感。只要认真去阅读这些资料,加上应用的时候进行一定的参考,掌握正则表达式不是问题。

索引

  1._引子
  2._正则表达式的历史
  3._正则表达式定义

   3.1_普通字符
   3.2_非打印字符
   3.3_特殊字符
   3.4_限定符
   3.5_定位符
   3.6_选择
   3.7_后向引用

  4._各种操作符的运算优先级
  5._全部符号解释
  6._部分例子
  7._正则表达式匹配规则

   7.1_基本模式匹配
   7.2_字符簇
   7.3_确定重复出现
1. 引子
  目前,正则表达式已经在很多软件中得到广泛的应用,包括*nix(Linux, Unix等),HP等操作系统,PHP,C#,Java等开发环境,以及很多的应用软件中,都可以看到正则表达式的影子。

  正则表达式的使用,可以通过简单的办法来实现强大的功能。为了简单有效而又不失强大,造成了正则表达式代码的难度较大,学习起来也不是很容易,所以需要付出一些努力才行,入门之后参照一定的参考,使用起来还是比较简单有效的。

  例子: ^.+@.+\\..+$

  这样的代码曾经多次把我自己给吓退过。可能很多人也是被这样的代码给吓跑的吧。继续阅读本文将让你也可以自由应用这样的代码。

  注意:这里的第7部分跟前面的内容看起来似乎有些重复,目的是把前面表格里的部分重新描述了一次,目的是让这些内容更容易理解。

2. 正则表达式的历史

  正则表达式的“祖先”可以一直上溯至对人类神经系统如何工作的早期研究。Warren McCulloch 和 Walter Pitts 这两位神经生理学家研究出一种数学方式来描述这些神经网络。

  1956 年, 一位叫 Stephen Kleene 的数学家在 McCulloch 和 Pitts 早期工作的基础上,发表了一篇标题为“神经网事件的表示法”的论文,引入了正则表达式的概念。正则表达式就是用来描述他称为“正则集的代数”的表达式,因此采用“正则表达式”这个术语。

  随后,发现可以将这一工作应用于使用 Ken Thompson 的计算搜索算法的一些早期研究,Ken Thompson 是 Unix 的主要发明人。正则表达式的第一个实用应用程序就是 Unix 中的 qed 编辑器。

  如他们所说,剩下的就是众所周知的历史了。从那时起直至现在正则表达式都是基于文本的编辑器和搜索工具中的一个重要部分。

3. 正则表达式定义

  正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。

  列目录时, dir *.txt或ls *.txt中的*.txt就不是一个正则表达式,因为这里*与正则式的*的含义是不同的。

  正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。

  3.1 普通字符

  由所有那些未显式指定为元字符的打印和非打印字符组成。这包括所有的大写和小写字母字符,所有数字,所有标点符号以及一些符号。

  3.2 非打印字符

字符 含义
\cx 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。

 
  3.3 特殊字符

  所谓特殊字符,就是一些有特殊含义的字符,如上面说的"*.txt"中的*,简单的说就是表示任何字符串的意思。如果要查找文件名中有*的文件,则需要对*进行转义,即在其前加一个\。ls \*.txt。正则表达式有以下特殊字符。

特别字符 说明
$ 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符本身,请使用 \$。
( ) 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 \( 和 \)。
* 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
+ 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+。
. 匹配除换行符 \n之外的任何单字符。要匹配 .,请使用 \。
[ 标记一个中括号表达式的开始。要匹配 [,请使用 \[。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。
\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\\' 匹配 "\",而 '\(' 则匹配 "("。
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 \^。
{ 标记限定符表达式的开始。要匹配 {,请使用 \{。
| 指明两项之间的一个选择。要匹配 |,请使用 \|。
 

  构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与操作符将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。
 

  3.4 限定符

  限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有*或+或?或{n}或{n,}或{n,m}共6种。

  *、+和?限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配。

  正则表达式的限定符有:

字符 描述
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。


  3.5 定位符

  用来描述字符串或单词的边界,^和$分别指字符串的开始与结束,\b描述单词的前或后边界,\B表示非单词边界。不能对定位符使用限定符。

  3.6 选择

  用圆括号将所有选择项括起来,相邻的选择项之间用|分隔。但用圆括号会有一个副作用,是相关的匹配会被缓存,此时可用?:放在第一个选项前来消除这种副作用。

  其中?:是非捕获元之一,还有两个非捕获元是?=和?!,这两个还有更多的含义,前者为正向预查,在任何开始匹配圆括号内的正则表达式模式的位置来匹配搜索字符串,后者为负向预查,在任何开始不匹配该正则表达式模式的位置来匹配搜索字符串。

  3.7 后向引用

  对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左至右所遇到的内容存储。存储子匹配的缓冲区编号从 1 开始,连续编号直至最大 99 个子表达式。每个缓冲区都可以使用 '\n' 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。

  可以使用非捕获元字符 '?:', '?=', or '?!' 来忽略对相关匹配的保存。

4. 各种操作符的运算优先级

  相同优先级的从左到右进行运算,不同优先级的运算先高后低。各种操作符的优先级从高到低如下:

操作符 描述
\ 转义符
(), (?:), (?=), [] 圆括号和方括号
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $, \anymetacharacter 位置和顺序
| “或”操作


5. 全部符号解释

字符 描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。
^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。
. 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
(pattern) 匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。
(?:pattern) 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。
(?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern) 负向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始
x|y 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。
[xyz] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
[^xyz] 负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\cx 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\d 匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。
\w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
\W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。
\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,'\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。.
\num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。
\n 标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
\nm 标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。
\nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。
\un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。
 
6. 部分例子

正则表达式 说明
/\b([a-z]+) \1\b/gi 一个单词连续出现的位置
/(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/ 将一个URL解析为协议、域、端口及相对路径
/^(?:Chapter|Section) [1-9][0-9]{0,1}$/ 定位章节的位置
/[-a-z]/ A至z共26个字母再加一个-号。
/ter\b/ 可匹配chapter,而不能terminal
/\Bapt/ 可匹配chapter,而不能aptitude
/Windows(?=95 |98 |NT )/ 可匹配Windows95或Windows98或WindowsNT,当找到一个匹配后,从Windows后面开始进行下一次的检索匹配。
 

7. 正则表达式匹配规则

  7.1 基本模式匹配

  一切从最基本的开始。模式,是正规表达式最基本的元素,它们是一组描述字符串特征的字符。模式可以很简单,由普通的字符串组成,也可以非常复杂,往往用特殊的字符表示一个范围内的字符、重复出现,或表示上下文。例如:

  ^once

  这个模式包含一个特殊的字符^,表示该模式只匹配那些以once开头的字符串。例如该模式与字符串"once upon a time"匹配,与"There once was a man from NewYork"不匹配。正如如^符号表示开头一样,$符号用来匹配那些以给定模式结尾的字符串。

  bucket$

  这个模式与"Who kept all of this cash in a bucket"匹配,与"buckets"不匹配。字符^和$同时使用时,表示精确匹配(字符串与模式一样)。例如:

  ^bucket$

  只匹配字符串"bucket"。如果一个模式不包括^和$,那么它与任何包含该模式的字符串匹配。例如:模式

  once

  与字符串

  There once was a man from NewYork
  Who kept all of his cash in a bucket.

  是匹配的。

  在该模式中的字母(o-n-c-e)是字面的字符,也就是说,他们表示该字母本身,数字也是一样的。其他一些稍微复杂的字符,如标点符号和白字符(空格、制表符等),要用到转义序列。所有的转义序列都用反斜杠(\)打头。制表符的转义序列是:\t。所以如果我们要检测一个字符串是否以制表符开头,可以用这个模式:

  ^\t

  类似的,用\n表示“新行”,\r表示回车。其他的特殊符号,可以用在前面加上反斜杠,如反斜杠本身用\\表示,句号.用\.表示,以此类推。

  7.2 字符簇

  在INTERNET的程序中,正规表达式通常用来验证用户的输入。当用户提交一个FORM以后,要判断输入的电话号码、地址、EMAIL地址、信用卡号码等是否有效,用普通的基于字面的字符是不够的。

  所以要用一种更自由的描述我们要的模式的办法,它就是字符簇。要建立一个表示所有元音字符的字符簇,就把所有的元音字符放在一个方括号里:

  [AaEeIiOoUu]

  这个模式与任何元音字符匹配,但只能表示一个字符。用连字号可以表示一个字符的范围,如:

  [a-z] //匹配所有的小写字母
  [A-Z] //匹配所有的大写字母
  [a-zA-Z] //匹配所有的字母
  [0-9] //匹配所有的数字
  [0-9\.\-] //匹配所有的数字,句号和减号
  [ \f\r\t\n] //匹配所有的白字符

  同样的,这些也只表示一个字符,这是一个非常重要的。如果要匹配一个由一个小写字母和一位数字组成的字符串,比如"z2"、"t6"或"g7",但不是"ab2"、"r2d3" 或"b52"的话,用这个模式:

  ^[a-z][0-9]$

  尽管[a-z]代表26个字母的范围,但在这里它只能与第一个字符是小写字母的字符串匹配。

  前面曾经提到^表示字符串的开头,但它还有另外一个含义。当在一组方括号里使用^是,它表示“非”或“排除”的意思,常常用来剔除某个字符。还用前面的例子,我们要求第一个字符不能是数字:

  ^[^0-9][0-9]$

  这个模式与"&5"、"g7"及"-2"是匹配的,但与"12"、"66"是不匹配的。下面是几个排除特定字符的例子:

  [^a-z] //除了小写字母以外的所有字符
  [^\\\/\^] //除了(\)(/)(^)之外的所有字符
  [^\"\'] //除了双引号(")和单引号(')之外的所有字符

  特殊字符"." (点,句号)在正规表达式中用来表示除了“新行”之外的所有字符。所以模式"^.5$"与任何两个字符的、以数字5结尾和以其他非“新行”字符开头的字符串匹配。模式"."可以匹配任何字符串,除了空串和只包括一个“新行”的字符串。

  PHP的正规表达式有一些内置的通用字符簇,列表如下:

  字符簇含义

  [[:alpha:]] 任何字母
  [[:digit:]] 任何数字
  [[:alnum:]] 任何字母和数字
  [[:space:]] 任何白字符
  [[:upper:]] 任何大写字母
  [[:lower:]] 任何小写字母
  [[:punct:]] 任何标点符号
  [[:xdigit:]] 任何16进制的数字,相当于[0-9a-fA-F]

  7.3 确定重复出现

  到现在为止,你已经知道如何去匹配一个字母或数字,但更多的情况下,可能要匹配一个单词或一组数字。一个单词有若干个字母组成,一组数字有若干个单数组成。跟在字符或字符簇后面的花括号({})用来确定前面的内容的重复出现的次数。

  字符簇 含义
  ^[a-zA-Z_]$ 所有的字母和下划线
  ^[[:alpha:]]{3}$ 所有的3个字母的单词
  ^a$ 字母a
  ^a{4}$ aaaa
  ^a{2,4}$ aa,aaa或aaaa
  ^a{1,3}$ a,aa或aaa
  ^a{2,}$ 包含多于两个a的字符串
  ^a{2,} 如:aardvark和aaab,但apple不行
  a{2,} 如:baad和aaa,但Nantucket不行
  \t{2} 两个制表符
  .{2} 所有的两个字符

  这些例子描述了花括号的三种不同的用法。一个数字,{x}的意思是“前面的字符或字符簇只出现x次”;一个数字加逗号,{x,}的意思是“前面的内容出现x或更多的次数”;两个用逗号分隔的数字,{x,y}表示“前面的内容至少出现x次,但不超过y次”。我们可以把模式扩展到更多的单词或数字:

  ^[a-zA-Z0-9_]{1,}$ //所有包含一个以上的字母、数字或下划线的字符串
  ^[0-9]{1,}$ //所有的正数
  ^\-{0,1}[0-9]{1,}$ //所有的整数
  ^\-{0,1}[0-9]{0,}\.{0,1}[0-9]{0,}$ //所有的小数

  最后一个例子不太好理解,是吗?这么看吧:与所有以一个可选的负号(\-{0,1})开头(^)、跟着0个或更多的数字([0-9]{0,})、和一个可选的小数点(\.{0,1})再跟上0个或多个数字([0-9]{0,}),并且没有其他任何东西($)。下面你将知道能够使用的更为简单的方法。

  特殊字符"?"与{0,1}是相等的,它们都代表着:“0个或1个前面的内容”或“前面的内容是可选的”。所以刚才的例子可以简化为:

  ^\-?[0-9]{0,}\.?[0-9]{0,}$

  特殊字符"*"与{0,}是相等的,它们都代表着“0个或多个前面的内容”。最后,字符"+"与 {1,}是相等的,表示“1个或多个前面的内容”,所以上面的4个例子可以写成:

  ^[a-zA-Z0-9_]+$ //所有包含一个以上的字母、数字或下划线的字符串
  ^[0-9]+$ //所有的正数
  ^\-?[0-9]+$ //所有的整数
  ^\-?[0-9]*\.?[0-9]*$ //所有的小数

  当然这并不能从技术上降低正规表达式的复杂性,但可以使它们更容易阅读。


相关链接:
JScript 和 VBScript 正则表达式
http://bbs.chinaunix.net/viewthread.php?tid=149723&highlight=%D5%FD%D4%F2%B1%ED%B4%EF%CA%BD%D3%EF%B7%A8
http://bbs.chinaunix.net/viewthread.php?tid=61847&highlight=%D5%FD%D4%F2%B1%ED%B4%EF%CA%BD%BD%E9%C9%DC
http://waitu.cnblogs.com/archive/2006/01/17/318821.html 正则表达式效校验工具

正则表达式介绍

URL: http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/jscript7/html/jsreconintroductiontoregularexpressions.asp

这十三个小节介绍正则表达式的概念,并说明如何在 JScript 中创建和使用它们。

尽管每个主题都自成一体,但我们还是建议您按顺序细读这些主题,以便最好地理解本材料。许多主题依赖于对前面的主题所介绍的功能或概念的理解。
本节内容

正则表达式
通过与大多数读者已经熟悉的一些概念进行比较,说明正则表达式的概念。
正则表达式的用途
通过实例说明正则表达式如何扩展常规搜索条件。
正则表达式语法
说明构成正则表达式的字符、构成元字符的字符以及元字符的行为。
生成正则表达式
描述正则表达式的组件以及组件和分隔符之间的关系。
优先级顺序
说明如何计算正则表达式以及正则表达式的序列和语法对结果有何影响。
普通字符
区分普通字符与元字符,并说明如何将多个单字符正则表达式组合在一起,以创建更大的表达式。
特殊字符
说明转义符的概念以及如何创建与元字符匹配的正则表达式。
不可打印字符
列出用于表示正则表达式中非打印字符的转义序列。
字符匹配
说明正则表达式如何使用句点、转义符和中括号创建返回特定结果的序列。
限定符
说明当无法指定多少字符构成一个匹配时如何创建正则表达式。
定位点
说明如何将正则表达式固定到行首或行尾,以及如何创建在单词内、在单词的开头或者在单词的结尾出现的正则表达式。
替换和分组
说明替换如何使用“| ”字符以允许在两个或更多替换选项之间进行选择,以及分组如何与替换配合工作以进一步精练结果。
反向引用
说明如何创建可以访问存储匹配模式的组成部分的正则表达式,而不必重新创建构成这一匹配模式的正则表达式。

相关章节

.NET Framework 正则表达式
阐明正则表达式的模式匹配表示法如何使开发人员能够快速分析大量的文本,以查找特定字符模式;提取、编辑、替换或删除文本子字符串;或将提取的字符串添加到集合中,以便生成报告。
正则表达式示例
提供指向代码示例的一组链接,这些示例说明正则表达式在常见的应用程序中的用法。


正则表达式

除非您以前使用过正则表达式,否则您可能不熟悉此术语。但是,毫无疑问,您已经使用过不涉及脚本的某些正则表达式概念。

例如,您很可能使用 ? 和 * 通配符来查找硬盘上的文件。通配符匹配文件名中的单个字符,而 * 通配符匹配零个或多个字符。像 data?.dat 这样的模式将查找下列文件:

data1.dat

data2.dat

datax.dat

dataN.dat

使用 * 字符代替 ? 字符扩大了找到的文件的数量。data*.dat 匹配下列所有文件:

data.dat

data1.dat

data2.dat

data12.dat

datax.dat

dataXYZ.dat

尽管这种搜索方法很有用,但它还是有限的。和 * 通配符的能力引入了正则表达式所依赖的概念,但正则表达式功能更强大,而且更加灵活。


正则表达式的用途

典型的搜索和替换操作要求您提供与预期的搜索结果匹配的确切文本。虽然这种技术对于对静态文本执行简单搜索和替换任务可能已经足够了,但它缺乏灵活性,若采用这种方法搜索动态文本,即使不是不可能,至少也会变得很困难。

通过使用正则表达式,可以:

* 测试字符串内的模式。

例如,可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。
* 替换文本。

可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
* 基于模式匹配从字符串中提取子字符串。

可以查找文档内或输入域内特定的文本。

例如,您可能需要搜索整个 Web 站点,删除过时的材料,以及替换某些 HTML 格式标记。在这种情况下,可以使用正则表达式来确定在每个文件中是否出现该材料或该 HTML 格式标记。此过程将受影响的文件列表缩小到包含需要删除或更改的材料的那些文件。然后可以使用正则表达式来删除过时的材料。最后,可以使用正则表达式来搜索和替换标记。

正则表达式在 JScript 或 C 等语言中也很有用,这些语言的字符串处理能力还不为人们所知。


正则表达式语法

正则表达式是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为“元字符”)。模式描述在搜索文本时要匹配的一个或多个字符串。

下面是正则表达式的一些示例:
表达式 匹配
/^\s*$/ 匹配空行。
/\d{2}-\d{5}/ 验证由两位数字、一个连字符再加 5 位数字组成的 ID 号。
/<\s*(\S+)(\s[^>]*)?>[\s\S]*<\s*\/\1\s*>/ 匹配 HTML 标记。

下表包含了元字符的完整列表以及它们在正则表达式上下文中的行为:
字符 说明
\ 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,“n”匹配字符“n”。“\n”匹配换行符。序列“\\”匹配“\”,“\(”匹配“(”。
^ 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与“\n”或“\r”之后的位置匹配。
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与“\n”或“\r”之前的位置匹配。
* 零次或多次匹配前面的字符或子表达式。例如,zo* 匹配“z”和“zoo”。* 等效于 {0,}。
+ 一次或多次匹配前面的字符或子表达式。例如,“zo+”与“zo”和“zoo”匹配,但与“z”不匹配。+ 等效于 {1,}。
? 零次或一次匹配前面的字符或子表达式。例如,“do(es)?”匹配“do”或“does”中的“do”。? 等效于 {0,1}。
{n} n 是非负整数。正好匹配 n 次。例如,“o{2}”与“Bob”中的“o”不匹配,但与“food”中的两个“o”匹配。
{n,} n 是非负整数。至少匹配 n 次。例如,“o{2,}”不匹配“Bob”中的“o”,而匹配“foooood”中的所有 o。'o{1,}' 等效于 'o+'。'o{0,}' 等效于 'o*'。
{n,m} m 和 n 是非负整数,其中 n <= m。至少匹配 n 次,至多匹配 m 次。例如,“o{1,3}”匹配“fooooood”中的头三个 o。'o{0,1}' 等效于 'o?'。注意:您不能将空格插入逗号和数字之间。
? 当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是“非贪心的”。“非贪心的”模式匹配搜索到的、尽可能短的字符串,而默认的“贪心的”模式匹配搜索到的、尽可能长的字符串。例如,在字符串“oooo”中,“o+?”只匹配单个“o”,而“o+”匹配所有“o”。
. 匹配除“\n”之外的任何单个字符。若要匹配包括“\n”在内的任意字符,请使用诸如“[\s\S]”之类的模式。
(pattern) 匹配 pattern 并捕获该匹配的子表达式。可以使用 $0...$9 属性从结果“匹配”集合中检索捕获的匹配。若要匹配括号字符 ( ),请使用“\(”或者“\)”。
(?:pattern) 匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用“或”字符 (|) 组合模式部件的情况很有用。例如,与“industry|industries”相比,“industr(?:y| ies)”是一个更加经济的表达式。
(?=pattern) 执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,“Windows (?=95| 98| NT| 2000)”与“Windows 2000”中的“Windows”匹配,但不与“Windows 3.1”中的“Windows”匹配。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
(?!pattern) 执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,“Windows (?!95| 98| NT| 2000)”与“Windows 3.1”中的“Windows”匹配,但不与“Windows 2000”中的“Windows”匹配。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
x| y 与 x 或 y 匹配。例如,“z| food”与“z”或“food”匹配。“(z| f)ood”与“zood”或“food”匹配。
[xyz] 字符集。匹配包含的任一字符。例如,“[abc]”匹配“plain”中的“a”。
[^xyz] 反向字符集。匹配未包含的任何字符。例如,“[^abc]”匹配“plain”中的“p”。
[a-z] 字符范围。匹配指定范围内的任何字符。例如,“[a-z]”匹配“a”到“z”范围内的任何小写字母。
[^a-z] 反向范围字符。匹配不在指定的范围内的任何字符。例如,“[^a-z]”匹配任何不在“a”到“z”范围内的任何字符。
\b 匹配一个字边界,即字与空格间的位置。例如,“er\b”匹配“never”中的“er”,但不匹配“verb”中的“er”。
\B 非字边界匹配。“er\B”匹配“verb”中的“er”,但不匹配“never”中的“er”。
\cx 匹配由 x 指示的控制字符。例如,\cM 匹配一个 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是“c”字符本身。
\d 数字字符匹配。等效于 [0-9]。
\D 非数字字符匹配。等效于 [^0-9]。
\f 换页符匹配。等效于 \x0c 和 \cL。
\n 换行符匹配。等效于 \x0a 和 \cJ。
\r 匹配一个回车符。等效于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 制表符匹配。与 \x09 和 \cI 等效。
\v 垂直制表符匹配。与 \x0b 和 \cK 等效。
\w 匹配任何字类字符,包括下划线。与“[A-Za-z0-9_]”等效。
\W 任何非字字符匹配。与“[^A-Za-z0-9_]”等效。
\xn 匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,“\x41”匹配“A”。“\x041”与“\x04”&“1”等效。允许在正则表达式中使用 ASCII 代码。
\num 匹配 num,此处的 num 是一个正整数。到捕获匹配的反向引用。例如,“(.)\1”匹配两个连续的相同字符。
\n 标识一个八进制转义码或反向引用。如果 \n 前面至少有 n 个捕获子表达式,那么 n 是反向引用。否则,如果 n 是八进制数 (0-7),那么 n 是八进制转义码。
\nm 标识一个八进制转义码或反向引用。如果 \nm 前面至少有 nm 个捕获子表达式,那么 nm 是反向引用。如果 \nm 前面至少有 n 个捕获,那么 n 是反向引用,后面跟 m。如果前面的条件均不存在,那么当 n 和 m 是八进制数 (0-7) 时,\nm 匹配八进制转义码 nm。
\nml 当 n 是八进制数 (0-3),m 和 l 是八进制数 (0-7) 时,匹配八进制转义码 nml。
\un 匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (©)。


生成正则表达式

正则表达式的结构与算术表达式的结构类似。即,各种元字符和运算符可以将小的表达式组合起来,创建大的表达式。

通过在一对分隔符之间放置表达式模式的各种组件,就可以构建正则表达式。对于 JScript,分隔符是正斜杠 (/) 字符。例如:

/expression/

在上面的示例中,正则表达式模式 (expression) 存储在 RegExp 对象的 Pattern 属性中。

正则表达式的组件可以是单个字符、字符集、字符的范围、在几个字符之间选择或者所有这些组件的任何组合。


优先级顺序

正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。

下表从最高到最低说明了各种正则表达式运算符的优先级顺序:
运算符 说明
\ 转义符
(), (?:), (?=), [] 括号和中括号
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $, \anymetacharacter, anycharacter 定位点和序列
| 替换

字符的优先级比替换运算符高,替换运算符允许“m|food”与“m”或“food”匹配。若要匹配“mood”或“food”,请使用括号创建子表达式,从而产生“(m|f)ood”。


普通字符

普通字符包括没有显式指定为元字符的所有可打印和不可打印字符。这包括所有大写和小写字母、所有数字、所有标点符号和一些其他符号。

正则表达式的最简单形式是在搜索字符串中匹配其本身的单个普通字符。例如,单字符模式,如 A,不论出现在搜索字符串中的何处,它总是匹配字母 A。下面是一些单字符正则表达式模式的示例:

/a/
/7/
/M/

可以将许多单字符组合起来以形成大的表达式。例如,以下正则表达式组合了单字符表达式:a、7 和 M。

/a7M/

请注意,没有串联运算符。只须在一个字符后面键入另一个字符。


特殊字符

许多元字符要求在试图匹配它们时特别对待。若要匹配这些特殊字符,必须首先使字符“转义”,即,将反斜杠字符 (\) 放在它们前面。下表列出了特殊字符以及它们的含义:
特殊字符 注释
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,那么 $ 还匹配 \n 或 \r 前面的位置。若要匹配 $ 字符本身,请使用 \$。
( ) 标记子表达式的开始和结束。可以捕获子表达式以供以后使用。若要匹配这两个字符,请使用 \( 和 \)。
* 零次或多次匹配前面的字符或子表达式。若要匹配 * 字符,请使用 \*。
+ 一次或多次匹配前面的字符或子表达式。若要匹配 + 字符,请使用 \+。
. 匹配除换行符 \n 之外的任何单个字符。若要匹配 .,请使用 \。
[ ] 标记中括号表达式的开始。若要匹配这些字符,请使用 \[ 和 \]。
? 零次或一次匹配前面的字符或子表达式,或指示“非贪心”限定符。若要匹配 ? 字符,请使用 \?。
\ 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,字符 n 匹配字符 n。\n 匹配换行符。序列 \\ 匹配 \,序列 \( 匹配 (。
/ 表示文本正则表达式的开始或结束。若要匹配 / 字符,请使用 \/。
^ 匹配输入字符串开始处的位置,但在中括号表达式中使用的情况除外,在那种情况下它对字符集求反。若要匹配 ^ 字符本身,请使用 \^。
{ } 标记限定符表达式的开始。若要匹配这些字符,请使用 \{ 和 \}。
| 指出在两个项之间进行选择。若要匹配 | ,请使用 \|


不可打印字符

非打印字符也可以是正则表达式的组成部分。下表列出了表示非打印字符的转义序列:
字符 含义
\cx 匹配由 x 指示的控制字符。例如,\cM 匹配一个 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是“c”字符本身。
\f 换页符匹配。等效于 \x0c 和 \cL。
\n 换行符匹配。等效于 \x0a 和 \cJ。
\r 匹配一个回车符。等效于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 制表符匹配。与 \x09 和 \cI 等效。
\v 垂直制表符匹配。与 \x0b 和 \cK 等效。


字符匹配

句点 (.) 匹配字符串中的各种打印或非打印字符,只有一个字符例外。这个例外就是换行符 (\n)。下面的正则表达式匹配 aac、abc、acc、adc 等等,以及 a1c、a2c、a-c 和 a#c:

/a.c/

若要匹配包含文件名的字符串,而句点 (.) 是输入字符串的组成部分,请在正则表达式中的句点前面加反斜扛 (\) 字符。举例来说明,下面的正则表达式匹配 filename.ext:

/filename\.ext/

这些表达式只让您匹配“任何”单个字符。可能需要匹配列表中的特定字符组。例如,可能需要查找用数字表示的章节标题(Chapter 1、Chapter 2 等等)。
中括号表达式

若要创建匹配字符组的一个列表,请在方括号([ 和 ])内放置一个或更多单个字符。当字符括在中括号内时,该列表称为“中括号表达式”。与在任何别的位置一样,普通字符在中括号内表示其本身,即,它在输入文本中匹配一次其本身。大多数特殊字符在中括号表达式内出现时失去它们的意义。不过也有一些例外,如:

* 如果 ] 字符不是第一项,它结束一个列表。若要匹配列表中的 ] 字符,请将它放在第一位,紧跟在开始 [ 后面。
* \ 字符继续作为转义符。若要匹配 \ 字符,请使用 \\。

括在中括号表达式中的字符只匹配处于正则表达式中该位置的单个字符。以下正则表达式匹配 Chapter 1、Chapter 2、Chapter 3、Chapter 4 和 Chapter 5:

/Chapter [12345]/

请注意,单词 Chapter 和后面的空格的位置相对于中括号内的字符是固定的。中括号表达式指定的只是匹配紧跟在单词 Chapter 和空格后面的单个字符位置的字符集。这是第九个字符位置。

若要使用范围代替字符本身来表示匹配字符组,请使用连字符 (-) 将范围中的开始字符和结束字符分开。单个字符的字符值确定范围内的相对顺序。下面的正则表达式包含范围表达式,该范围表达式等效于上面显示的中括号中的列表。

/Chapter [1-5]/

当以这种方式指定范围时,开始值和结束值两者都包括在范围内。注意,还有一点很重要,按 Unicode 排序顺序,开始值必须在结束值的前面。

若要在中括号表达式中包括连字符,请采用下列方法之一:

* 用反斜扛将它转义:

[\-]

* 将连字符放在中括号列表的开始或结尾。下面的表达式匹配所有小写字母和连字符:

[-a-z]
[a-z-]

* 创建一个范围,在该范围中,开始字符值小于连字符,而结束字符值等于或大于连字符。下面的两个正则表达式都满足这一要求:

[!--]
[!-~]

若要查找不在列表或范围内的所有字符,请将插入符号 (^) 放在列表的开头。如果插入字符出现在列表中的其他任何位置,则它匹配其本身。下面的正则表达式匹配编号大于 5 的章节标题:

/Chapter [^12345]/

在上面的示例中,表达式在第九个位置匹配 1、2、3、4 或 5 之外的任何数字字符。这样,例如,Chapter 7 就是一个匹配项,Chapter 9 也是一个匹配项。

上面的表达式可以使用连字符 (-) 来表示:

/Chapter [^1-5]/

中括号表达式的典型用途是指定任何大写或小写字母或任何数字的匹配。下面的表达式指定这样的匹配:

/[A-Za-z0-9]/


限定符

如果您不能指定构成匹配的字符的数量,那么正则表达式支持限定符的概念。这些限定符使您能够指定,为使匹配为真,正则表达式的某个给定组件必须出现多少次。

下表说明各种限定符以及它们的含义:
字符 说明
* 零次或多次匹配前面的字符或子表达式。例如,zo* 匹配 z 和 zoo。* 等效于 {0,}。
+ 一次或多次匹配前面的字符或子表达式。例如,zo+ 匹配 zo 和 zoo,但不匹配 z。+ 等效于 {1,}。
? 零次或一次匹配前面的字符或子表达式。例如,do(es)? 匹配 do 或 does 中的 do。? 等效于 {0,1}。
{n} n 是非负整数。正好匹配 n 次。例如,o{2} 不匹配 Bob 中的 o,但匹配 food 中的两个 o。
{n,} n 是非负整数。至少匹配 n 次。例如,o{2,} 不匹配 Bob 中的 o,而匹配 foooood 中的所有 o。o{1,} 等效于 o+。o{0,} 等效于 o*。
{n,m} m 和 n 是非负整数,其中 n <= m。至少匹配 n 次,至多匹配 m 次。例如,o{1,3} 匹配 fooooood 中的头三个 o。o{0,1} 等效于 o?。注意:您不能将空格插入逗号和数字之间。

由于章节编号在大的输入文档中会很可能超过九,所以您需要一种方式来处理两位或三位章节编号。限定符给您这种能力。下面的正则表达式匹配编号为任何位数的章节标题:

/Chapter [1-9][0-9]*/

请注意,限定符出现在范围表达式之后。因此,它应用于整个范围表达式,在本例中,只指定从 0 到 9 的数字(包括 0 和 9)。

这里不使用 + 限定符,因为在第二个位置或后面的位置不一定需要有一个数字。也不使用?字符,因为它将章节编号限制到只有两位数。您需要至少匹配 Chapter 和空格字符后面的一个数字。

如果您知道章节编号被限制为只有 99 章,可以使用下面的表达式来至少指定一位但至多两位数字。

/Chapter [0-9]{1,2}/

上面的表达式的缺点是,大于 99 的章节编号仍只匹配开头两位数字。另一个缺点是 Chapter 0 也将匹配。只匹配两位数字的更好的表达式如下:

/Chapter [1-9][0-9]?/



/Chapter [1-9][0-9]{0,1}/

*、+ 和 ? 限定符都被称为“贪心的”,因为它们匹配尽可能多的文本。但是,有时您只需要最小的匹配。

例如,您可能搜索 HTML 文档,以查找括在 H1 标记内的章节标题。该文本在您的文档中如下:

<H1>Chapter 1 – Introduction to Regular Expressions</H1>

下面的表达式匹配从开始小于符号 (<) 到关闭 H1 标记的大于符号 (>) 之间的所有内容。

/<.*>/

如果您只需要匹配开始 H1 标记,下面的“非贪心”表达式只匹配 <H1>。

/<.*?>/

通过在 *、+ 或 ? 限定符之后放置 ?,该表达式从“贪心”表达式转换为“非贪心”表达式或者最小匹配。


定位点

本节前面的主题中的示例只涉及章节标题查找。字符串 Chapter 后面跟空格和数字的任何匹配项可能是实际章节标题,或者也可能是指向另一章的交叉引用。由于真正的章节标题总是出现在行的开始,所以设计一种方法只查找标题而不查找交叉引用可能很有用。

定位点提供该能力。定位点使您能够将正则表达式固定到行首或行尾。它们还使您能够创建这样的正则表达式,这些正则表达式出现在一个单词内、在一个单词的开头或者一个单词的结尾。下表包含正则表达式定位点以及它们的含义的列表:
字符 说明
^ 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与 \n 或 \r 之后的位置匹配。
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与 \n 或 \r 之前的位置匹配。
\b 匹配一个字边界,即字与空格间的位置。
\B 非字边界匹配。

不能将限定符与定位点一起使用。由于在紧靠换行或者字边界的前面或后面不能有一个以上位置,因此不允许诸如 ^* 之类的表达式。

若要匹配一行文本开始处的文本,请在正则表达式的开始使用 ^ 字符。不要将 ^ 的这种用法与中括号表达式内的用法混淆。

若要匹配一行文本的结束处的文本,请在正则表达式的结束处使用 $ 字符。

若要在搜索章节标题时使用定位点,下面的正则表达式匹配一个章节标题,该标题只包含两个尾随数字,并且出现在行首:

/^Chapter [1-9][0-9]{0,1}/

真正的章节标题不仅出现行的开始处,而且它还是该行中仅有的文本。它即出现在行首又出现在同一行的结尾。下面的表达式能确保指定的匹配只匹配章节而不匹配交叉引用。通过创建只匹配一行文本的开始和结尾的正则表达式,就可做到这一点。

/^Chapter [1-9][0-9]{0,1}$/

匹配字边界稍有不同,但向正则表达式添加了很重要的能力。字边界是单词和空格之间的位置。非字边界是任何其他位置。下面的表达式匹配单词 Chapter 的开头三个字符,因为这三个字符出现字边界后面:

/\bCha/

\b 字符的位置是非常重要的。如果它位于要匹配的字符串的开始,它在单词的开始处查找匹配项。如果它位于字符串的结尾,它在单词的结尾处查找匹配项。例如,下面的表达式匹配单词 Chapter 中的字符串 ter,因为它出现在字边界的前面:

/ter\b/

下面的表达式匹配 Chapter 中的字符串 apt,但不匹配 aptitude 中的字符串 apt:

/\Bapt/

字符串 apt 出现在单词 Chapter 中的非字边界处,但出现在单词 aptitude 中的字边界处。对于 \B 非字边界运算符,位置并不重要,因为匹配不关心究竟是单词的开头还是结尾。


替换和分组

替换使用 | 字符来允许在两个或多个替换选项之间进行选择。例如,可以扩展章节标题正则表达式,以返回比章标题范围更广的匹配项。但是,这并不象您可能认为的那样简单。替换匹配 | 字符两边的尽可能最大的表达式。您可能认为,下面的表达式匹配出现在行首和行尾、后面跟一个或两个数字的 Chapter 或 Section:

/^Chapter|Section [1-9][0-9]{0,1}$/

很遗憾,上面的正则表达式要么匹配行首的单词 Chapter,要么匹配行尾的单词 Section 及跟在其后的任何数字。如果输入字符串是 Chapter 22,那么上面的表达式只匹配单词 Chapter。如果输入字符串是 Section 22,那么该表达式匹配 Section 22。

若要使正则表达式更易于控制,可以使用括号来限制替换的范围,即,确保它只应用于两个单词 Chapter 和 Section。但是,括号也用于创建子表达式,并可能捕获它们以供以后使用,这一点在有关反向引用的那一节讲述。通过在上面的正则表达式的适当位置添加括号,就可以使该正则表达式匹配 Chapter 1 或 Section 3。

下面的正则表达式使用括号来组合 Chapter 和 Section,以便表达式正确地起作用:

/^(Chapter|Section) [1-9][0-9]{0,1}$/

虽然这些表达式正确发挥作用,但 Chapter| Section 两边的括号还会使得两个匹配单词中的任何一个被捕获以供将来使用。由于在上面的表达式中只有一组括号,因此,只有一个被捕获的“子匹配项”。可以通过使用 RegExp 对象的 $1-$9 属性来引用此子匹配项。

在上面的示例中,您只需要使用括号来组合单词 Chapter 和 Section 之间的选择。若要防止匹配被保存以备将来使用,请在括号内正则表达式模式之前放置 ?:。下面的修改提供相同的能力而不保存子匹配项:

/^(?:Chapter|Section) [1-9][0-9]{0,1}$/

除 ?: 元字符外,两个其他非捕获元字符创建被称为“预测先行”匹配的某些内容。正向预测先行使用 ?= 指定,它匹配处于括号中匹配正则表达式模式的起始点的搜索字符串。反向预测先行使用 ?! 指定,它匹配处于与正则表达式模式不匹配的字符串的起始点的搜索字符串。

例如,假设您有一个文档,该文档包含指向 Windows 3.1、Windows 95、Windows 98 和 Windows NT 的引用。再进一步假设,您需要更新该文档,将指向 Windows 95、Windows 98 和 Windows NT 的所有引用更改为 Windows 2000。下面的正则表达式(这是一个正向预测先行的示例)匹配 Windows 95、Windows 98 和 Windows NT:

/Windows(?=95 |98 |NT )/

找到一处匹配后,紧接着就在匹配的文本(不包括预测先行中的字符)之后搜索下一处匹配。例如,如果上面的表达式匹配 Windows 98,将在 Windows 之后而不是在 98 之后继续搜索。


反向引用

正则表达式的最重要功能之一是存储匹配的模式的一部分以供以后重新使用的能力。您可能想起,若在正则表达式模式或模式的一部分两侧加上括号,就会导致表达式的一部分被存储到临时缓冲区中。可以通过使用非捕获元字符 ?:、?= 或 ?! 来重写捕获。

每个捕获的子匹配项按照它们在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。可以使用 \n 来访问每个缓冲区,其中 n 是标识特定缓冲区的一位或两位十进制数字。

反向引用的最简单的、最有用的应用之一,是提供查找文本中两个相同的相邻单词的匹配项的能力。以下面的句子为例:

Is is the cost of of gasoline going up up?

上面的句子很显然有多个重复的单词。如果能设计一种方法定位该句子,而不必查找每个单词的重复出现,那该有多好。下面的正则表达式使用单个子表达式来实现这一点:

/\b([a-z]+) \1\b/gi

捕获的表达式,正如 [a-z]+ 指定的,包括一个或多个字母。正则表达式的第二部分是对以前捕获的子匹配项的引用,即,单词的第二个匹配项正好由括号表达式匹配。\1 指定第一个子匹配项。字边界元字符确保只检测整个单词。否则,诸如“is issued”或“this is”之类的词组将不能正确地被此表达式识别。

正则表达式后面的全局标记 (g) 指示,将该表达式应用到输入字符串中能够查找到的尽可能多的匹配。表达式的结尾处的不区分大小写 (i) 标记指定不区分大小写。多行标记指定换行符的两边可能出现潜在的匹配。

使用上面的正则表达式,下面的代码可以使用子匹配项信息,将文本字符串中的两个连续相同的单词的匹配项替换为同一单词的单个匹配项:

var ss = "Is is the cost of of gasoline going up up?.\n";
var re = /\b([a-z]+) \1\b/gim; //Create regular expression pattern.
var rv = ss.replace(re,"$1"); //Replace two occurrences with one.

在 replace 方法内使用 $1 引用第一个保存的子匹配项。如果您有多个子匹配项,您将通过使用 $2、$3 等依次引用它们。

反向引用还可以将通用资源指示符 (URI) 分解为其组件。假定您想将下面的 URI 分解为协议(ftp、http 等等)、域地址和页/路径:

http://msdn.microsoft.com:80/scripting/default.htm

下面的正则表达式提供该功能:

/(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/

第一个括号子表达式捕获 Web 地址的协议部分。该子表达式匹配在冒号和两个正斜杠前面的任何单词。第二个括号子表达式捕获地址的域地址部分。该子表达式匹配不包括 / 或 : 字符的任何字符序列。第三个括号子表达式捕获端口号(如果指定了的话)。该子表达式匹配冒号后面的零个或多个数字。最后,第四个括号子表达式捕获 Web 地址指定的路径和/或页信息。该子表达式匹配 # 或空格字符之外的一个或多个字符。

将正则表达式应用到上面的 URI,各子匹配项包含下面的内容:

* RegExp.$1 包含“http”
* RegExp.$2 包含“msdn.microsoft.com”
* RegExp.$3 包含“:80”
* RegExp.$4 包含“/scripting/default.htm”

正規運算式

URL: http://www.tldp.org/linuxfocus/ChineseBig5/July1998/article53.html

內容摘要: 正規運算式 (regular expression) 被應用於本文搜尋, 及文句修改的進階場合上。您可以在許多進階的編輯器、 語法分析程式、 以及程式語言中, 發現他們的蹤影。


介紹

許多進階的編輯器, 像是 vi 和 emacs, 工具程式 grep/egrep, 以及程式語言, 像是 awk、 perl 和 sed, 都可以發現正規運算式的蹤影。

正規表示式被應用於本文搜尋, 及文句修改的進階場合上。正規運算式就是某種樣式的制式描述, 透過該樣式, 可以比對到文章中的一段文字。

記得多年以前, 看到某人在使用正規運算式, 我當時大感神奇。通常要花費數小時的時間, 才能完成文章編輯以及搜尋的工作,居然可以在幾秒內就全部解決。 但是, 當我注視螢幕的運算式時,卻連一個字也看不懂, 它們看起來像是一些點、 斜線、 星號,以及其他字元, 所湊起來的奇怪組合。 雖然如此, 我仍舊下定決心,要去暸解它的工作原理, 很快地, 我發現它們其實是非常容易使用的,有一些基本的規則可循。

雖然正規運算式在 Unix 的世界中, 運用地相當廣泛, 但是還未出現過,所謂的「標準正規運算式」, 它的情況, 很像是有許多不同的方言存在一般。例如有二種 grep 程式: grep 與 egrep, 它們都有使用正規運算式,只是能力稍微不同而已。 而程式語言 Perl 的正規運算式, 功能可說是最完整的了。可喜的是, 他們都遵循相同的原則, 一旦您暸解基本觀念後,再去學習其他方言的細微差異處, 是很容易的。

本文將為各位介紹一些基本的觀念, 同時您也可以查看不同程式的操作說明文件,以便暸解其相異之處, 以及功能所在。
一個簡單的例子

譬如說, 您有一份公司員工的電話名單, 它看起來像是這樣:

Phone Name ID
...
...
3412 Bob 123
3834 Jonny 333
1248 Kate 634
1423 Tony 567
2567 Peter 435
3567 Alice 535
1548 Kerry 534
...

這是一個 500 人的公司, 他們把員工資料以一般的純文字檔案加以儲存。電話號碼中, 第一位數字為 1 的人, 表示他在 1 號大廈工作。那麼到底誰在 1 號大廈工作呢?

正規運算式可以回答這個問題:
grep '^1' phonelist.txt


egrep '^1' phonelist.txt


perl -ne 'print if (/^1/)' phonelist.txt

它的意思是說, 搜尋檔案的每一行, 看看是否有以 1 作該行開頭的。符號 "^" 表示要比對每一行的開頭, 它強制整個正規運算式,只比對匹配到, 以 1 作第一個字元的每一行。
語法規則
單一字元樣式

正規運算式的基本構件, 就是單一字元樣式, 它只比對匹配這個字元。前面的例子中, 1 就是個單一字元樣式, 她只比對匹配文章中, 1 這個字元。

另一個單一字元樣式的實例是:
egrep 'Kerry' phonelist.txt

這個比對樣式, 其實還是僅由單一字元樣式所組成 (字母 K,e ...)

數個字元可以聚集起來, 放在字元集合中, 這樣的集合,是由一對左、 右方括號, 以及在這對方括號之間的一串字元, 來做為表示。 整個字元集合, 其實也被視為單一字元樣式, 在進行樣式比對時,這些字元集合裡, 會有一個, 而且只有一個字元, 出現在所搜尋匹配的文句中。例如:

[abc] 是個單一字元樣式, 用來比對匹配文章裡
a、 b 或 c 當中之任一個字母
[ab0-9] 是個單一字元樣式, 用來比對匹配文章裡
a 或 b 或一個 ascii 字元集中,
範圍在 0 到 9 的數字
[a-zA-Z0-9\-] 用來比對匹配某個單一字元為
大寫或小寫字母、 阿拉伯數字或減號

讓我們試著執行:
egrep '^1[348]' phonelist.txt

這樣會搜尋到以 13 或 14 或 18 開頭的每一行。

如我們所看到的, 大部分的 ASCII 字元, 就是按照其字元原本的樣子來比對,但是有些 ASCII 字元, 卻有特殊的含意。 例如方括號,表示開始指定一個字元集合, 在字元集合中, "-" 的特殊含意就是「範圍」。 要取消特定字元的特殊含意, 您可以在該字元前面,加上反斜線字元。 在 [a-zA-Z0-9\-] 中的減號, 就是一個實例。也有某些正規運算式的「方言」, 在特定字元前面加上反斜線字元後,會有特殊含意, 此時, 你得將前面的反斜線字元拿掉, 才有原本正常的意思。

點字元 (.) 是一個重要的特殊字元, 除了換行字元外,它會比對匹配到任何一個字元。 例如:

grep '^.2' phonelist.txt



egrep '^.2' phonelist.txt

這樣會搜尋匹配到, 第一個字元為任何字元, 而且第二個字元為 2 的每一行。

如果使用 "[^" 而不是 "[" 來定義字元集合,則其所代表的含意, 與原來完全相反。 在 "[" 與 "^" 組合之後, "^" 的意義不再是代表每行的開頭,而是代表字元集合的反義。

[0-9] 是個單一字元樣式, 會比對匹配到文章裡
一個 ascii 字元集中, 範圍在 0 到 9 的數字
[^0-9] 會比對匹配到任何一個非阿拉伯數字的字元
[^abc] 會比對匹配到任何一個非 a、 b 或 c 的字元
. 點字元會比對匹配到任何一個非換行字元的字元
它的意義與 [^\n] 相同, 其中 \n 是換行字元

要比對匹配到「不是以 1 開頭的每一行文字」, 我們可以這樣寫:

grep '^[^1]' phonelist.txt



egrep '^[^1]' phonelist.txt

定位字元

在前面的部份, 我們已經知道 "^" 是用來比對匹配到文章的每一行開頭。定位字元是一種特別的正規運算式字元, 它被用來比對匹配到文章的某個位置,而不是文章的所有字元。

^ 會比對匹配文章裡的每一行開頭
$ 會比對匹配文章裡的每一行結尾

想要在公司的員工電話名單中, 尋找 ID 編號為 567 的人, 我們可以這樣做:

egrep '567$' phonelist.txt

這樣子會尋找到「以數字 567 結尾」的每一行。
倍數字元

倍數字元用來決定, 單一字元樣式在文章中必須出現幾次。

說明 grep egrep perl vi vim vile elvis emacs
零或多次 * * * * * * * *
一或多次 \{1,\} + + \+ \+ \+ +
零或一次 \? ? ? \= \? \= ?
n 到 m 次 \{n,m\} {n,m} \{n,m\} \{n,m\}

注意事項: 各類 VI 編輯程式要與上表的動作一致有 magic 設定選項可用.

舉一個電話名單的例子:

....
1248 Kate 634
....
1548 Kerry 534
....

要比對匹配以 1 開頭, 接著有一些阿拉伯數字, 然後至少有一個以上的間隔字元以及人名是以 K 開始的每一行我們可以這樣寫:

grep '^1[0-9]\{1,\} \{1,\}K' phonelist.txt
或使用 * 來重複比對匹配 [0-9] 與間隔字元:
grep '^1[0-9][0-9]* *K' phonelist.txt

egrep '^1[0-9]+ +K' phonelist.txt

perl -ne 'print if (/^1[0-9]+ +K/)' phonelist.txt

倍數字元會將前面的單一字元樣式出現的次數加倍. 所以 "23*4" 不表示說她會比對匹配 " 2 然後 3 任何字元 4" (這其實是 "23.*4" 的含義). 她會比對匹配 " 2 一次 然後 3 可能許多次以及 4 一次"

還有一個你也須要注意的重點就是這些倍數字元很貪心. 也就是說在比對樣式中第一個出現的倍數字元會盡可能地向 每行文字的右邊延伸所要匹配的字元.

運算式 ^1.*4
將會比對匹配到一整行
1548 Kerry 534
從開頭一直到最後面的 4.
但是她就是不會只匹配到 154.

這個特性對 grep 工具程式並沒有什麼影響但是對文字的編輯與代換卻非常重要.
括號字元有記憶能力

括號字元有記憶能力的機制並沒有改變運算式的比對方法但是 她卻能夠將包含在括號的樣式所匹配到的文字部分記憶起來,所以 在運算式的後面可以再參考到她.

這個被記憶的內容可以經由變數來取得. 第一組括號字元所記憶的內容 可以經由變數一來取得, 第二組括號字元所記憶的內容可以經由變數二來取得 依此類推.

程式名稱括號字元語法變數語法
grep\(\)\1
egrep()\1
perl()\1 or ${1}
vi,vim,vile,elvis\(\)\1
emacs\(\)\1

例如:

運算式 [a-z][a-z] 將會
比對匹配二個小寫字母.

現在我們可以使用變數來搜尋比對像是 'otto' 這類的文字:

egrep '([a-z])([a-z])\2\1'

變數 \1 的內容是字母 o
而變數 \2 的內容是字母 t.

這個運算式也能夠比對匹配到 anna 這個名字
但是 yxyx 就不可以了.

在尋找像是 otto 和 anna 這類名字時並不常用到括號字元的記憶能力 倒是文字的編輯與代換時會常用到她的記憶能力.
應用正規運算式的能力來編輯文字

想在編輯文字時借用正規運算式的能力你需要一個像是 vi, emacs 之類的編輯器 或者你也可以使用像是 perl 之類的程式語言.

在 emacs 編輯器中你可以使用 M-x 來下 query-replace-regexp 命令 或是將 query-replace-regexp 命令設定在一些功能鍵上. 亦或是你也可以 使用 replace-regexp 命令. 不過 query-replace-regexp 是採交談的方式, 而後者則否.

在 vi 編輯器中文字的代換則是使用 :%s/ / /gc 這樣的命令. 其中 百分比字元是指搜尋 '整個檔案' 的範圍然而你也可以取代成你想要的 範圍. 在 vim 編輯器中你可以按下 shift-v 鍵來標示一個區域然後你 可以只在標示的區域上使用代換文字的命令. 在這裡我並不對 vim 的 使用多作說明你可以參考該編輯器所附的自習指導文件. 而代換命令中 的 'gc' 是指採用交談的方式. 不使用交談的方式可以下 s/ / /g 這樣 的命令.

所謂交談的方式是指在每次比對匹配到時編輯器會提示詢問你 是否要執行代換文字的動作.

在 perl 程式語言中你可以使用

perl -pe 's/ / /g'

讓我們看一點例子. 例如現在我們公司的編號計劃已經做了改變 就是凡電話號碼是 1 開頭的人在第二位阿拉伯數字之後都會插入一 個 2 .

也就是說如果原先電話號碼是 1423 則應該變成 14223.

舊的名單:

Phone Name ID
...
3412 Bob 123
3834 Jonny 333
1248 Kate 634
1423 Tony 567
2567 Peter 435
3567 Alice 535
1548 Kerry 534
...

這裡是各種處理的方法:

vi: s/^\(1.\)/\12/g
emacs: ^\(1.\) replaced by \12
perl: perl -pe 's/^(1.)/${1}2/g' phonelist.txt

現在新的電話名單看起來像是這樣:

Phone Name ID
...
3412 Bob 123
3834 Jonny 333
12248 Kate 634
14223 Tony 567
2567 Peter 435
3567 Alice 535
15248 Kerry 534
...

Perl 程式語言可以處理超過 \1 到 \9 的記憶變數因此 \12 將會指到 第 12 個記憶變數此時這個變數的內容當然是空的. 要解決這個問題我們 可以使用 ${1} 的方式.

現在名單的排列方式有點不整齊. 要如何修正他?你可以這樣子試試看 如果在第五個位置是空白字元你就再插入一個空白字元:

vi: s/^\(....\) /\1 /g
emacs: '^\(....\) ' replaced by '\1 '
perl: perl -pe 's/^(....) /${1} /g' phonelist.txt

現在電話名單看起來像是這樣

Phone Name ID
...
3412 Bob 123
3834 Jonny 333
12248 Kate 634
14223 Tony 567
2567 Peter 435
3567 Alice 535
15248 Kerry 534
...

現在有同事以人工的方式編輯這個名單並且偶爾會在文字行的開頭插入一些空白字元. 我們要如何作才能夠將之除去?

Phone Name ID
...
3412 Bob 123
3834 Jonny 333
12248 Kate 634
14223 Tony 567
2567 Peter 435
3567 Alice 535
15248 Kerry 534
...

這個問題應該如此解決:

vi: s/^ *// (當我們不使用 + 時必須使用 2 個空白字元)
emacs: '^ +' replaced by the empty string
perl: perl -pe 's/^ +//' phonelist.txt

當你在撰寫程式時使用了 temp 與 temporary 二個變數. 現在你想要 將變數 temp 的變數名稱改為 counter. 如果你所作的只是代換 temp 這個字串則變數 temporary 會變成 counterorary 這當然不是你想要的 結果.

正規運算式可以解決這個問題. 你只要將 temp([^o]) 代換成 counter\1 即可. 也就是說, 只代換 temp 並且不含字母 o 的字串. (另一個解決方式 就是使用邊界字元但是我們並不在這類的定位字元樣式中討論她.)

我希望這篇文章能夠激發起你對正規運算式的興趣. 現在你可能必須去 看一下你所使用編輯器的操作說明與文件以便仔細暸解其正規運算式的功能.

還有許多特殊字元未能提到, 像是交替字元" | " 他具有 "或者" 的意思以及前面所說的邊界字元.

最後敬祝各位愉快, 並能夠用得充滿樂趣。

使用正规表达式编写更好的SQL

URL: http://www.pconline.com.cn/pcedu/empolder/db/oracle/0507/670149.html
URL: http://blog.yesky.com/blog/sunshineboy/archive/2005/11/23/1160068.aspx

Oracle Database 10g 中的正规表达式特性是一个用于处理文本数据的强大工具

  Oracle Database 10g 的一个新特性大大提高了您搜索和处理字符数据的能力。这个特性就是正规表达式,是一种用来描述文本模式的表示方法。很久以来它已在许多编程语言和大量 UNIX 实用工具中出现过了。

  Oracle 的正规表达式的实施是以各种 SQL 函数和一个 WHERE 子句操作符的形式出现的。如果您不熟悉正规表达式,那么这篇文章可以让您了解一下这种新的极其强大然而表面上有点神秘的功能。已经对正规表达式很熟悉的读者可以了解如何在 Oracle SQL 语言的环境中应用这种功能。

什么是正规表达式?

  正规表达式由一个或多个字符型文字和/或元字符组成。在最简单的格式下,正规表达式仅由字符文字组成,如正规表达式 cat。它被读作字母 c,接着是字母 a 和 t,这种模式匹配 cat、location 和 catalog 之类的字符串。元字符提供算法来确定 Oracle 如何处理组成一个正规表达式的字符。当您了解了各种元字符的含义时,您将体会到正规表达式用于查找和替换特定的文本数据是非常强大的。

  验证数据、识别重复关键字的出现、检测不必要的空格,或分析字符串只是正规表达式的许多应用中的一部分。您可以用它们来验证电话号码、邮政编码、电子邮件地址、社会安全号码、IP 地址、文件名和路径名等的格式。此外,您可以查找如 HTML 标记、数字、日期之类的模式,或任意文本数据中符合任意模式的任何事物,并用其它的模式来替换它们。


用 Oracle Database 10g 使用正规表达式

  您可以使用最新引进的 Oracle SQL REGEXP_LIKE 操作符和 REGEXP_INSTR、REGEXP_SUBSTR 以及 REGEXP_REPLACE 函数来发挥正规表达式的作用。您将体会到这个新的功能如何对 LIKE 操作符和 INSTR、SUBSTR 和 REPLACE 函数进行了补充。实际上,它们类似于已有的操作符,但现在增加了强大的模式匹配功能。被搜索的数据可以是简单的字符串或是存储在数据库字符列中的大量文本。正规表达式让您能够以一种您以前从未想过的方式来搜索、替换和验证数据,并提供高度的灵活性。

正规表达式的基本例子

  在使用这个新功能之前,您需要了解一些元字符的含义。句号 (.) 匹配一个正规表达式中的任意字符(除了换行符)。例如,正规表达式 a.b 匹配的字符串中首先包含字母 a,接着是其它任意单个字符(除了换行符),再接着是字母 b。字符串 axb、xaybx 和 abba 都与之匹配,因为在字符串中隐藏了这种模式。如果您想要精确地匹配以 a 开头和以 b 结尾的一条三个字母的字符串,则您必须对正规表达式进行定位。脱字符号 (^) 元字符指示一行的开始,而美元符号 ($) 指示一行的结尾(参见表1:附表见第4页)。因此, 正规表达式 ^a.b$ 匹配字符串 aab、abb 或 axb。将这种方式与 LIKE 操作符提供的类似的模式匹配 a_b 相比较,其中 (_) 是单字符通配符。

  默认情况下,一个正规表达式中的一个单独的字符或字符列表只匹配一次。为了指示在一个正规表达式中多次出现的一个字符,您可以使用一个量词,它也被称为重复操作符。.如果您想要得到从字母 a 开始并以字母 b 结束的匹配模式,则您的正规表达式看起来像这样:^a.*b$。* 元字符重复前面的元字符 (.) 指示的匹配零次、一次或更多次。LIKE 操作符的等价的模式是 a%b,其中用百分号 (%) 来指示任意字符出现零次、一次或多次。

  表 2 给出了重复操作符的完整列表。注意它包含了特殊的重复选项,它们实现了比现有的 LIKE 通配符更大的灵活性。如果您用圆括号括住一个表达式,这将有效地创建一个可以重复一定次数的子表达式。例如,正规表达式 b(an)*a 匹配 ba、bana、banana、yourbananasplit 等。

  Oracle 的正规表达式实施支持 POSIX (可移植操作系统接口)字符类,参见表 3 中列出的内容。这意味着您要查找的字符类型可以非常特别。假设您要编写一条仅查找非字母字符的 LIKE 条件 — 作为结果的 WHERE 子句可能不经意就会变得非常复杂。

  POSIX 字符类必须包含在一个由方括号 ([]) 指示的字符列表中。例如,正规表达式 [[:lower:]] 匹配一个小写字母字符,而 [[:lower:]]{5} 匹配五个连续的小写字母字符。

  除 POSIX 字符类之外,您可以将单独的字符放在一个字符列表中。例如,正规表达式 ^ab[cd]ef$ 匹配字符串 abcef 和 abdef。必须选择 c 或 d。

  除脱字符 (^) 和连字符 (-) 之外,字符列表中的大多数元字符被认为是文字。正规表达式看起来很复杂,这是因为一些元字符具有随上下文环境而定的多重含义。^ 就是这样一种元字符。如果您用它作为一个字符列表的第一个字符,它代表一个字符列表的非。因此,[^[:digit:]] 查找包含了任意非数字字符的模式,而 ^[[:digit:]] 查找以数字开始的匹配模式。连字符 (-) 指示一个范围,正规表达式 [a-m] 匹配字母 a 到字母 m 之间的任意字母。但如果它是一个字符行中的第一个字符(如在 [-afg] 中),则它就代表连字符。

  之前的一个例子介绍了使用圆括号来创建一个子表达式;它们允许您通过输入更替元字符来输入可更替的选项,这些元字符由竖线 (|) 分开。

  例如,正规表达式 t(a|e|i)n 允许字母 t 和 n 之间的三种可能的字符更替。匹配模式包括如 tan、ten、tin 和 Pakistan 之类的字,但不包括 teen、mountain 或 tune。作为另一种选择,正规表达式 t(a|e|i)n 也可以表示为一个字符列表 t[aei]n。表 4 汇总了这些元字符。虽然存在更多的元字符,但这个简明的概述足够用来理解这篇文章使用的正规表达式。

REGEXP_LIKE 操作符

  REGEXP_LIKE 操作符向您介绍在 Oracle 数据库中使用时的正规表达式功能。表 5 列出了 REGEXP_LIKE 的语法。

  下面的 SQL 查询的 WHERE 子句显示了 REGEXP_LIKE 操作符,它在 ZIP 列中搜索满足正规表达式 [^[:digit:]] 的模式。它将检索 ZIPCODE 表中的那些 ZIP 列值包含了任意非数字字符的行。

SELECT zip FROM zipcode WHERE REGEXP_LIKE(zip, '[^[:digit:]]')

ZIP
-----
ab123
123xy
007ab
abcxy


  这个正规表达式的例子仅由元字符组成,更具体来讲是被冒号和方括号分隔的 POSIX 字符类 digit。第二组方括号(如 [^[:digit:]] 中所示)包括了一个字符类列表。如前文所述,需要这样做是因为您只可以将 POSIX 字符类用于构建一个字符列表。

REGEXP_INSTR 函数

  这个函数返回一个模式的起始位置,因此它的功能非常类似于 INSTR 函数。新的 REGEXP_INSTR 函数的语法在表 6 中给出。这两个函数之间的主要区别是,REGEXP_INSTR 让您指定一种模式,而不是一个特定的搜索字符串;因而它提供了更多的功能。接下来的示例使用 REGEXP_INSTR 来返回字符串 Joe Smith, 10045 Berry Lane, San Joseph, CA 91234 中的五位邮政编码模式的起始位置。如果正规表达式被写为 [[:digit:]]{5},则您将得到门牌号的起始位置而不是邮政编码的,因为 10045 是第一次出现五个连续数字。因此,您必须将表达式定位到该行的末尾,正如 $ 元字符所示,该函数将显示邮政编码的起始位置,而不管门牌号的数字个数。

SELECT REGEXP_INSTR('Joe Smith, 10045 Berry Lane, San Joseph, CA 91234',
'[[:digit:]]{5}$') AS rx_instr FROM dual

RX_INSTR
----------
45



编写更复杂的模式

  让我们在前一个例子的邮政编码模式上展开,以便包含一个可选的四位数字模式。您的模式现在可能看起来像这样:[[:digit:]]{5}(-[[: digit:]]{4})?$。如果您的源字符串以 5 位邮政编码或 5 位 + 4 位邮政编码的格式结束,则您将能够显示该模式的起始位置。

SELECT REGEXP_INSTR('Joe Smith, 10045 Berry Lane, San Joseph, CA 91234-1234',
' [[:digit:]]{5}(-[[:digit:]]{4})?$') AS starts_at FROM dual

STARTS_AT
----------
44


  在这个示例中,括弧里的子表达式 (-[[:digit:]]{4}) 将按 ? 重复操作符的指示重复零次或一次。此外,企图用传统的 SQL 函数来实现相同的结果甚至对 SQL 专家也是一个挑战。为了更好地说明这个正规表达式示例的不同组成部分,表 7 包含了一个对单个文字和元字符的描述。

REGEXP_SUBSTR 函数

  类似于 SUBSTR 函数的 REGEXP_SUBSTR 函数用来提取一个字符串的一部分。表 8 显示了这个新函数的语法。在下面的示例中,匹配模式 [^,]* 的字符串将被返回。该正规表达式搜索其后紧跟着空格的一个逗号;然后按 [^,]* 的指示搜索零个或更多个不是逗号的字符,最后查找另一个逗号。这种模式看起来有点像一个用逗号分隔的值字符串。

SELECT REGEXP_SUBSTR('first field, second field , third field', ', [^,]*,') FROM dual

REGEXP_SUBSTR('FIR
------------------
, second field ,



REGEXP_REPLACE 函数

  让我们首先看一下传统的 REPLACE SQL 函数,它把一个字符串用另一个字符串来替换。假设您的数据在正文中有不必要的空格,您希望用单个空格来替换它们。利用 REPLACE 函数,您需要准确地列出您要替换多少个空格。然而,多余空格的数目在正文的各处可能不是相同的。下面的示例在 Joe 和 Smith 之间有三个空格。REPLACE 函数的参数指定要用一个空格来替换两个空格。在这种情况下,结果在原来的字符串的 Joe 和 Smith 之间留下了一个额外的空格。

SELECT REPLACE('Joe Smith',' ', ' ') AS replace FROM dual

REPLACE
---------
Joe Smith

  REGEXP_REPLACE 函数把替换功能向前推进了一步,其语法在表 9 中列出。以下查询用单个空格替换了任意两个或更多的空格。( ) 子表达式包含了单个空格,它可以按 {2,} 的指示重复两次或更多次。

SELECT REGEXP_REPLACE('Joe Smith', '( ){2,}', ' ') AS RX_REPLACE FROM dual

RX_REPLACE
----------
Joe Smith

后向引用

  正则表达式的一个有用的特性是能够存储子表达式供以后重用;这也被称为后向引用(在表 10 中对其进行了概述)。它允许复杂的替换功能,如在新的位置上交换模式或显示重复出现的单词或字母。子表达式的匹配部分保存在临时缓冲区中。缓冲区从左至右进行编号,并利用 \digit 符号进行访问,其中 digit 是 1 到 9 之间的一个数字,它匹配第 digit 个子表达式,子表达式用一组圆括号来显示。

  接下来的例子显示了通过按编号引用各个子表达式将姓名 Ellen Hildi Smith 转变为 Smith, Ellen Hildi。

SELECT REGEXP_REPLACE(
'Ellen Hildi Smith',
'(.*) (.*) (.*)', '\3, \1 \2')
FROM dual

REGEXP_REPLACE('EL
------------------
Smith, Ellen Hildi

  该 SQL 语句显示了用圆括号括住的三个单独的子表达式。每一个单独的子表达式包含一个匹配元字符 (.),并紧跟着 * 元字符,表示任何字符(除换行符之外)都必须匹配零次或更多次。空格将各个子表达式分开,空格也必须匹配。圆括号创建获取值的子表达式,并且可以用 \digit 来引用。第一个子表达式被赋值为 \1 ,第二个 \2,以此类推。这些后向引用被用在这个函数的最后一个参数 (\3, \1 \2) 中,这个函数有效地返回了替换子字符串,并按期望的格式来排列它们(包括逗号和空格)。表 11 详细说明了该正则表达式的各个组成部分。

  后向引用对替换、格式化和代替值非常有用,并且您可以用它们来查找相邻出现的值。接下来的例子显示了使用 REGEP_SUBSTR 函数来查找任意被空格隔开的重复出现的字母数字值。显示的结果给出了识别重复出现的单词 is 的子字符串。

SELECT REGEXP_SUBSTR(
'The final test is is the implementation',
'([[:alnum:]]+)([[:space:]]+)\1') AS substr
FROM dual

SUBSTR
------
is is



匹配参数选项

  您可能已经注意到了正则表达式操作符和函数包含一个可选的匹配参数。这个参数控制是否区分大小写、换行符的匹配和保留多行输入。

正则表达式的实际应用

  您不仅可以在队列中使用正则表达式,还可以在使用 SQL 操作符或函数的任何地方(比如说在 PL/SQL 语言中)使用正则表达式。您可以编写利用正则表达式功能的触发器,以验证、生成或提取值。

  接下来的例子演示了您如何能够在一次列检查约束条件中应用 REGEXP_LIKE 操作符来进行数据验证。它在插入或更新时检验正确的社会保险号码格式。如 123-45-6789 和 123456789 之类格式的社会保险号码对于这种列约束条件是可接受的值。有效的数据必须以三个数字开始,紧跟着一个连字符,再加两个数字和一个连字符,最后又是四个数字。另一种表达式只允许 9 个连续的数字。竖线符号 (|) 将各个选项分开。

ALTER TABLE students
ADD CONSTRAINT stud_ssn_ck CHECK
(REGEXP_LIKE(ssn,
'^([[:digit:]]{3}-[[:digit:]]{2}-[[:digit:]]{4}|[[:digit:]]{9})$'))


  由 ^ 和 $ 指示的开头或结尾的字符都是不可接受的。确保您的正则表达式没有分成多行或包含任何不必要的空格,除非您希望格式如此并相应地进行匹配。表 12 说明了该正则表达式示例的各个组成部分。

将正则表达式与现有的功能进行比较

  正则表达式有几个优点优于常见的 LIKE 操作符和 INSTR、SUBSTR 及 REPLACE 函数的。这些传统的 SQL 函数不便于进行模式匹配。只有 LIKE 操作符通过使用 % 和 _ 字符匹配,但 LIKE 不支持表达式的重复、复杂的更替、字符范围、字符列表和 POSIX 字符类等等。此外,新的正则表达式函数允许检测重复出现的单词和模式交换。这里的例子为您提供了正则表达式领域的一个概览,以及您如何能够在您的应用程序中使用它们。

实实在在地丰富您的工具包

  因为正则表达式有助于解决复杂的问题,所以它们是非常强大的。正则表达式的一些功能难于用传统的 SQL 函数来仿效。当您了解了这种稍显神秘的语言的基础构建程序块时,正则表达式将成为您的工具包的不可缺少的一部分(不仅在 SQL 环境下也在其它的编程语言环境下)。为了使您的各个模式正确,虽然尝试和错误有时是必须的,但正则表达式的简洁和强大是不容置疑的。

  Alice Rischert (ar280@yahoo.com) 是哥伦比亚大学计算机技术与应用系的数据库应用程序开发和设计方向的主席。她编写了 Oracle SQL 交互手册 第 2 版(Prentice Hall,2002)和即将推出的 Oracle SQL 示例 (Prentice Hall,2003)。Rischert 拥有超过 15 年的经验在财富 100 强公司内担任数据库设计师、DBA 和项目主管,并且她自从 Oracle version 5 起就一直使用 Oracle 产品。

  附表见下页:
表 1:定位元字符
元字符说明
^使表达式定位至一行的开头
$使表达式定位至一行的末尾

表 2:量词或重复操作符
量词说明
*匹配 0 次或更多次
?匹配 0 次或 1 次
+匹配 1 次或更多次
{m}正好匹配 m 次
{m,}至少匹配 m 次
{m, n}至少匹配 m 次但不超过 n 次

表 3:预定义的 POSIX 字符类
字符类说明
[:alpha:]字母字符
[:lower:]小写字母字符
[:upper:]大写字母字符
[:digit:]数字
[:alnum:]字母数字字符
[:space:]空白字符(禁止打印),如回车符、换行符、竖直制表符和换页符
[:punct:]标点字符
[:cntrl:]控制字符(禁止打印)
[:print:]可打印字符

表 4:表达式的替换匹配和分组
元字符说明
|替换分隔替换选项,通常与分组操作符 () 一起使用
( )分组将子表达式分组为一个替换单元、量词单元或后向引用单元(参见“后向引用”部分)
[char]字符列表表示一个字符列表;一个字符列表中的大多数元字符(除字符类、^ 和 - 元字符之外)被理解为文字

表 5:REGEXP_LIKE 操作符
语法说明
REGEXP_LIKE(source_string, pattern
[, match_parameter])source_string 支持字符数据类型(CHAR、VARCHAR2、CLOB、NCHAR、NVARCHAR2 和 NCLOB,但不包括 LONG)。pattern 参数是正则表达式的另一个名称。match_parameter 允许可选的参数(如处理换行符、保留多行格式化以及提供对区分大小写的控制)。

表 6:REGEXP_INSTR 函数
语法说明
REGEXP_INSTR(source_string, pattern
[, start_position
[, occurrence
[, return_option
[, match_parameter]]]])该函数查找 pattern ,并返回该模式的第一个位置。您可以随意指定您想要开始搜索的 start_position。 occurrence 参数默认为 1,除非您指定您要查找接下来出现的一个模式。return_option 的默认值为 0,它返回该模式的起始位置;值为 1 则返回符合匹配条件的下一个字符的起始位置。

表 7: 5 位数字加 4 位邮政编码表达式的说明
语法说明
必须匹配的空白
[:digit:]POSIX 数字类
]字符列表的结尾
{5}字符列表正好重复出现 5 次
(子表达式的开头
-一个文字连字符,因为它不是一个字符列表内的范围元字符
[字符列表的开头
[:digit:]POSIX [:digit:]类
[字符列表的开头
]字符列表的结尾
{4}字符列表正好重复出现 4 次
)结束圆括号,结束子表达式
?? 量词匹配分组的子表达式 0 或 1 次,从而使得 4 位代码可选
$定位元字符,指示行尾

表 8:REGEXP_SUBSTR 函数
语法说明
REGEXP_SUBSTR(source_string, pattern
[, position [, occurrence
[, match_parameter]]])REGEXP_SUBSTR 函数返回匹配模式的子字符串。

表 9: REGEXP_REPLACE 函数
语法说明
REGEXP_REPLACE(source_string, pattern
[, replace_string [, position
[,occurrence, [match_parameter]]]])该函数用一个指定的 replace_string 来替换匹配的模式,从而允许复杂的“搜索并替换”操作。

表 10:后向引用元字符
元字符说明
\digit反斜线紧跟着一个 1 到 9 之间的数字,反斜线匹配之前的用括号括起来的第 digit 个子表达式。
(注意:反斜线在正则表达式中有另一种意义,取决于上下文,它还可能表示 Escape 字符。

表 11:模式交换正则表达式的说明
正则表达式项目说明
(第一个子表达式的开头
.匹配除换行符之外的任意单字符
*重复操作符,匹配之前的 . 元字符 0 到 n 次
)第一个子表达式的结尾;匹配结果在 \1
中获取(在这个例子中,结果为 Ellen。)
必须存在的空白
(第二个子表达式的开头
.匹配除换行符之外的任意单个字符
*重复操作符,匹配之前的 . 元字符 0 到 n 次
)第二个子表达式的结尾;匹配结果在 \2
中获取(在这个例子中,结果为 Hildi。)
空白
(第三个子表达式的开头
.匹配除换行符之外的任意单字符
*重复操作符,匹配之前的 . 元字符 0 到 n 次
)第三个子表达式的结尾;匹配结果在 \3
中获取(在这个例子中,结果为 Smith。)

表 12:社会保险号码正则表达式的说明
正则表达式项目说明
^行首字符(正则表达式在匹配之前不能有任何前导字符。)
(开始子表达式并列出用 | 元字符分开的可替换选项
[字符列表的开头
[:digit:]POSIX 数字类
]字符列表的结尾
{3}字符列表正好重复出现 3 次
-连字符
[字符列表的开头
[:digit:]POSIX 数字类
]字符列表的结尾
{2}字符列表正好重复出现 2 次
-另一个连字符
[字符列表的开头
[:digit:]POSIX 数字类
]字符列表的结尾
{4}字符列表正好重复出现 4 次
|替换元字符;结束第一个选项并开始下一个替换表达式
[字符列表的开头
[:digit:]POSIX 数字类
]字符列表的结尾
{9}字符列表正好重复出现 9 次
)结束圆括号,结束用于替换的子表达式组
$定位元字符,指示行尾;没有额外的字符能够符合模式

正则表达式

URL: http://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F

正则表达式(Regular Expression,缩写为regexp,regex或regxp),又称正規表示式或常规表达式,是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。在很多文本编辑器或其他工具里,正规表达式通常被用来检索和/或替换那些符合某个模式的文本内容。许多程序设计语言都支持利用正规表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的在正规表达式引擎。正规表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。
目录

* 1 基本概念
* 2 历史
* 3 表达式全集
* 4 参考条目
* 5 外部链接


基本概念

正规表达式也经常被称为模式,用来描述或者匹配一系列符合某个句法规则的字符串。例如,Handel,Händel,和Haendel三个字符串,都可以由"H(a|ä|ae)ndel"这个模式来描述。大部分形式都有如下的结构:
替换
|

竖直分隔符代表替换。例如"gray|grey"可以匹配grey或gray。

数量限定
某个字符后的数量限定符用来限定前面这个字符允许出现的个数。最常见的数量限定符包括+, ?,和*(不加数量限定则代表出现一次且仅出现一次):

+

加号代表前面的字符必须至少出现一次。例如,"goo+gle"可以匹配google,gooogle,goooogle等;

?

问号代表前面的字符最多只可以出现一次。例如,"colou?r"可以匹配colour或者color;

*

星号代表前面的字符可以不出现,也可以出现一次或者多次。例如,"0*42"可以匹配42,042,0042,00042等。

捕获
圆括号可以用来定义操作符的范围和优先度。例如,"gr(a|e)y"等价于"gray|grey","(grand)?father"匹配father和grandfather。

上述这些构造子都可以自由组合,因此,"H(ae?|ä)ndel"和"H(a|ae|ä)ndel"是相同的。

精确的语法可能因不同的工具或程序而异。

历史

最初的正规表达式出现于理论计算机科学的自动控制理论和形式语言理论中。在这些领域中有对计算(自动控制)的模型和对形式语言描述与分类的研究。1940年代,Warren McCulloch与Walter Pitts将神經系統中的神经元描述成小而简单的自动控制元。稍后,数学家Stephen Kleene利用称之为正则集合的数学符号来描述此模型。Ken Thompson将此符号系统引入编辑器QED,然后是Unix上的编辑器ed,并最终引入grep。自此,正规表达式被广泛地使用于各种Unix或者类似Unix的工具,例如Perl。

Perl正规表达式源自于Henry Spencer写的regex,它已经演化成了pcre(Perl兼容正则表达式Perl Compatible Regular Expressions),一个由Philip Hazel开发的,为很多现代工具所使用的库。

各计算机语言之间的正规表达式的整合目前开展的很差。未来的Perl6的子项目Apocalypse的设计中已考虑到了这点。

表达式全集

下表是元字符及其在正规表达式上下文中的行为的一个完整列表:
字符 描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。
^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。
. 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
(pattern) 匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。
(?:pattern) 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。
(?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern) 负向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始
x|y 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。
[xyz] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
[^xyz] 负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\cx 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\d 匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。
\w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
\W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。
\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,'\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正规表达式中可以使用 ASCII 编码。.
\num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。
\n 标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
\nm 标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。
\nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。
\un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (©)。
[编辑]

参考条目

外部链接

* 各种不同风格的正则表达式
* 正则表达式的介绍(JScript.NET)

PHP中的正规表达式

URL: http://phpe.net/articles/21.shtml
URL: http://phpe.net/articles/22.shtml

PHP继承UNIX的一贯传统,完全支持正规表达式的处理。正规表达式提供了一种高级的,但不直观的字符串匹配和处理的方法。用过PERL的正规表达式的朋友都知道,正规表达式的功能非常强大,但学起来不是那么容易。
比如:
^.+@.+\..+$

这段有效却难以理解的代码足够使一些程序员头痛(我就是)或者让他们放弃使用正规表达式。相信当你读完这个教程后,就可以理解这段代码的含义了。

基本模式匹配

一切从最基本的开始。模式,是正规表达式最基本的元素,它们是一组描述字符串特征的字符。模式可以很简单,由普通的字符串组成,也可以非常复杂,往往用特殊的字符表示一个范围内的字符、重复出现,或表示上下文。例如:
^once

这个模式包含一个特殊的字符^,表示该模式只匹配那些以once开头的字符串。例如该模式与字符串\"once upon a time\"匹配,与\"There once was a man from NewYork\"不匹配。正如如^符号表示开头一样,$符号用来匹配那些以给定模式结尾的字符串。
bucket$

这个模式与\"Who kept all of this cash in a bucket\"匹配,与\"buckets\"不匹配。字符^和$同时使用时,表示精确匹配(字符串与模式一样)。例如:
^bucket$

只匹配字符串\"bucket\"。如果一个模式不包括^和$,那么它与任何包含该模式的字符串匹配。例如:模式
once

与字符串

There once was a man from NewYork
Who kept all of his cash in a bucket.

是匹配的。

在该模式中的字母(o-n-c-e)是字面的字符,也就是说,他们表示该字母本身,数字也是一样的。其他一些稍微复杂的字符,如标点符号和白字符(空格、制表符等),要用到转义序列。所有的转义序列都用反斜杠(\)打头。制表符的转义序列是\t。所以如果我们要检测一个字符串是否以制表符开头,可以用这个模式:
^\t

类似的,用\n表示“新行”,\r表示回车。其他的特殊符号,可以用在前面加上反斜杠,如反斜杠本身用\\表示,句号.用\.表示,以此类推。

字符簇

在INTERNET的程序中,正规表达式通常用来验证用户的输入。当用户提交一个FORM以后,要判断输入的电话号码、地址、EMAIL地址、信用卡号码等是否有效,用普通的基于字面的字符是不够的。

所以要用一种更自由的描述我们要的模式的办法,它就是字符簇。要建立一个表示所有元音字符的字符簇,就把所有的元音字符放在一个方括号里:
[AaEeIiOoUu]

这个模式与任何元音字符匹配,但只能表示一个字符。用连字号可以表示一个字符的范围,如:
[a-z] //匹配所有的小写字母
[A-Z] //匹配所有的大写字母
[a-zA-Z] //匹配所有的字母
[0-9] //匹配所有的数字
[0-9.-] //匹配所有的数字,句号和减号
[ frtn] //匹配所有的白字符

同样的,这些也只表示一个字符,这是一个非常重要的。如果要匹配一个由一个小写字母和一位数字组成的字符串,比如\"z2\"、\"t6\"或\"g7\",但不是\"ab2\"、\"r2d3\" 或\"b52\"的话,用这个模式:
^[a-z][0-9]$

尽管[a-z]代表26个字母的范围,但在这里它只能与第一个字符是小写字母的字符串匹配。

前面曾经提到^表示字符串的开头,但它还有另外一个含义。当在一组方括号里使用^是,它表示“非”或“排除”的意思,常常用来剔除某个字符。还用前面的例子,我们要求第一个字符不能是数字:
^[^0-9][0-9]$

这个模式与\"&5\"、\"g7\"及\"-2\"是匹配的,但与\"12\"、\"66\"是不匹配的。下面是几个排除特定字符的例子:
[^a-z] //除了小写字母以外的所有字符
[^\/^] //除了\"/\"和\"^\"字符之外的所有字符
[^\"\'] //除了双引号(\")和单引号(\')之外的所有字符


特殊字符\".\" (点,句号)在正规表达式中用来表示除了“新行”之外的所有字符。所以模式\"^.5$\"与任何两个字符的、以数字5结尾和以其他非“新行”字符开头的字符串匹配。模式\".\"可以匹配任何字符串,除了空串和只包括一个“新行”的字符串。

PHP的正规表达式有一些内置的通用字符簇,列表如下:
字符簇 含义
[[:alpha:]] 任何字母
[[:digit:]] 任何数字
[[:alnum:]] 任何字母和数字
[[:space:]] 任何白字符
[[:upper:]] 任何大写字母
[[:lower:]] 任何小写字母
[[:punct:]] 任何标点符号
[[:xdigit:]] 任何16进制的数字,相当于[0-9a-fA-F]


确定重复出现

到现在为止,你已经知道如何去匹配一个字母或数字,但更多的情况下,可能要匹配一个单词或一组数字。一个单词有若干个字母组成,一组数字有若干个单数组成。跟在字符或字符簇后面的花括号({})用来确定前面的内容的重复出现的次数。
字符簇 含义
^[a-zA-Z_]$ 所有的字母和下划线
^[[:alpha:]]{3}$ 所有的3个字母的单词
^a$ 字母a
^a{4}$ aaaa
^a{2,4}$ aa,aaa或aaaa
^a{1,3}$ a,aa或aaa
^a{2,}$ 包含多于两个a的字符串
^a{2,} 如:aardvark和aaab,但apple不行
a{2,} 如:baad和aaa,但Nantucket不行
\t{2} 两个制表符
.{2} 所有的两个字符

这些例子描述了花括号的三种不同的用法。一个数字,{x}的意思是“前面的字符或字符簇只出现x次”;一个数字加逗号,{x,}的意思是“前面的内容出现x或更多的次数”;两个用逗号分隔的数字,{x,y}表示“前面的内容至少出现x次,但不超过y次”。我们可以把模式扩展到更多的单词或数字:
^[a-zA-Z0-9_]{1,}$ //所有包含一个以上的字母、数字或下划线的字符串
^[0-9]{1,}$ //所有的正数
^\-{0,1}[0-9]{1,}$ //所有的整数
^\-{0,1}[0-9]{0,}\.{0,1}[0-9]{0,}$ //所有的小数

最后一个例子不太好理解,是吗?这么看吧:与所有以一个可选的负号(\-{0,1})开头(^)、跟着0个或更多的数字([0-9]{0,})、和一个可选的小数点(\.{0,1})再跟上0个或多个数字([0-9]{0,}),并且没有其他任何东西($)。下面你将知道能够使用的更为简单的方法。

特殊字符"?"与{0,1}是相等的,它们都代表着:“0个或1个前面的内容”或“前面的内容是可选的”。所以刚才的例子可以简化为:
^\-?[0-9]{0,}\.?[0-9]{0,}$

特殊字符"*"与{0,}是相等的,它们都代表着“0个或多个前面的内容”。最后,字符"+"与 {1,}是相等的,表示“1个或多个前面的内容”,所以上面的4个例子可以写成:
^[a-zA-Z0-9_]+$ //所有包含一个以上的字母、数字或下划线的字符串
^[0-9]+$ //所有的正数
^\-?[0-9]+$ //所有的整数
^\-?[0-9]*\.?[0-9]*$ //所有的小数

当然这并不能从技术上降低正规表达式的复杂性,但可以使它们更容易阅读。

正则表达式中的特殊字符

URL: http://phpe.net/articles/151.shtml

字符/
意义:对于字符,通常表示按字面意义,指出接着的字符为特殊字符,不作解释。
例如:/b/匹配字符’b’,通过在b 前面加一个反斜杠,也就是/b/,则该字符变成特殊字符,表示
匹配一个单词的分界线。
或者:
对于几个字符,通常说明是特殊的,指出紧接着的字符不是特殊的,而应该按字面解释。
例如:*是一个特殊字符,匹配任意个字符(包括0个字符);例如:/a*/意味匹配0个或多个a。为了匹配字面上的*,在a前面加一个反斜杠;例如:/a*/匹配’a*’。

字符^
意义:表示匹配的字符必须在最前边。
例如:/^A/不匹配"an A,"中的’A’,但匹配"An A."中最前面的’A’。

字符$
意义:与^类似,匹配最末的字符。
例如:/t$/不匹配"eater"中的’t’,但匹配"eat"中的’t’。

字符*
意义:匹配*前面的字符0次或n次。
例如:/bo*/匹配"A ghost booooed"中的’boooo’或"A bird warbled"中的’b’,但不匹配"Agoat g
runted"中的任何字符。

字符+
意义:匹配+号前面的字符1次或n次。等价于{1,}。
例如:/a+/匹配"candy"中的’a’和"caaaaaaandy."中的所有’a’。

字符?
意义:匹配?前面的字符0次或1次。
例如:/e?le?/匹配"angel"中的’el’和"angle."中的’le’。

字符.
意义:(小数点)匹配除换行符外的所有单个的字符。
例如:/.n/匹配"nay, an apple is on the tree"中的’an’和’on’,但不匹配’nay’。


字符(x)
意义:匹配’x’并记录匹配的值。
例如:/(foo)/匹配和记录"foo bar."中的’foo’。匹配子串能被结果数组中的素[1], ...,[n] 返
回,或被RegExp对象的属性, ..., 返回。

字符x│y
意义:匹配’x’或者’y’。
例如:/green│red/匹配"green apple"中的’green’和"red apple."中的’red’。

字符{ n }
意义:这里的n是一个正整数。匹配前面的n个字符。
例如:/a{ 2 }/不匹配"candy,"中的’a’,但匹配"caandy," 中的所有’a’和"caaandy."中前面的两个’a’。

字符{ n, }
意义:这里的n是一个正整数。匹配至少n个前面的字符。
例如:/a{ 2, }不匹配"candy"中的’a’,但匹配"caandy"中的所有’a’和"caaaaaaandy."中的所有’a’

字符{ n,m }
意义:这里的n和m都是正整数。匹配至少n个最多m个前面的字符。
例如:/a{ 1,3 }/不匹配"cndy"中的任何字符,但匹配 "candy,"中的’a’,"caandy," 中的前面两个
’a’和"caaaaaaandy"中前面的三个’a’,注意:即使"caaaaaaandy" 中有很多个’a’,但只匹配前面的三 个’a’即"aaa"。

字符[xyz]
意义:一字符列表,匹配列出中的任一字符。你可以通过连字符-指出一个字符范围。
例如:[abcd]跟[a-c]一样。它们匹配"brisket"中的’b’和"ache"中的’c’。

字符[^xyz]
意义:一字符补集,也就是说,它匹配除了列出的字符外的所有东西。 你可以使用连字符-指出一 字符范围。
例如:[^abc]和[^a-c]等价,它们最早匹配"brisket"中的’r’和"chop."中的’h’。

字符
意义:匹配一个空格(不要与b混淆)

字符b
意义:匹配一个单词的分界线,比如一个空格(不要与混淆)
例如:/bnw/匹配"noonday"中的’no’,/wyb/匹配"possibly yesterday."中的’ly’。

字符B
意义:匹配一个单词的非分界线
例如:/wBn/匹配"noonday"中的’on’,/yBw/匹配"possibly yesterday."中的’ye’。

字符cX
意义:这里的X是一个控制字符。匹配一个字符串的控制字符。
例如:/cM/匹配一个字符串中的control-M。

字符d
意义:匹配一个数字,等价于[0-9]。
例如:/d/或/[0-9]/匹配"B2 is the suite number."中的’2’。

字符D
意义:匹配任何的非数字,等价于[^0-9]。
例如:/D/或/[^0-9]/匹配"B2 is the suite number."中的’B’。

字符f
意义:匹配一个表单符

字符n
意义:匹配一个换行符

字符r
意义:匹配一个回车符

字符s
意义:匹配一个单个white空格符,包括空格,tab,form feed,换行符,等价于[ fnrtv]。
例如:/sw*/匹配"foo bar."中的’ bar’。

字符S
意义:匹配除white空格符以外的一个单个的字符,等价于[^ fnrtv]。
例如:/S/w*匹配"foo bar."中的’foo’。

字符t
意义:匹配一个制表符

字符v
意义:匹配一个顶头制表符

字符w
意义:匹配所有的数字和字母以及下划线,等价于[A-Za-z0-9_]。
例如:/w/匹配"apple,"中的’a’,".28,"中的’5’和"3D."中的’3’。

字符W
意义:匹配除数字、字母外及下划线外的其它字符,等价于[^A-Za-z0-9_]。
例如:/W/或者/[^$A-Za-z0-9_]/匹配"50%."中的’%’。

字符n
意义:这里的n是一个正整数。匹配一个正则表达式的最后一个子串的n的值(计数左圆括号)。

例如:/apple(,)sorange1/匹配"apple, orange, cherry, peach."中的’apple, orange’,下面有一个更加完整的例子。
注意:如果左圆括号中的数字比n指定的数字还小,则n取下一行的八进制escape作为描述。

字符ooctal和xhex
意义:这里的ooctal是一个八进制的escape值,而xhex是一个十六进制的escape值,允许在一个正则表达式中嵌入ASCII码

附:下表是元字符及其在正则表达式上下文中的行为的一个完整列表:



字符 描述
\
将下一个字符标记为一个特殊字符、或一个原义字符、或一个后向引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\' 匹配 "" 而 "\(" 则匹配 "("。
^
匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。
$
匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。
*
匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
?
匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
{n}
n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,}
n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m}
m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。刘, "o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
?
当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。
.
匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
(pattern)
匹配pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 {CONTENT}… 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。
(?:pattern)
匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。
(?=pattern)
正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如, 'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern)
负向预查,在任何不匹配Negative lookahead matches the search string at any point where a string not matching pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始
x|y
匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。
[xyz]
字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
[^xyz]
负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。
[a-z]
字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。
[^a-z]
负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。
\b
匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B
匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\cx
匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。 x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\d
匹配一个数字字符。等价于 [0-9]。
\D
匹配一个非数字字符。等价于 [^0-9]。
\f
匹配一个换页符。等价于 \x0c 和 \cL。
\n
匹配一个换行符。等价于 \x0a 和 \cJ。
\r
匹配一个回车符。等价于 \x0d 和 \cM。
\s
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S
匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t
匹配一个制表符。等价于 \x09 和 \cI。
\v
匹配一个垂直制表符。等价于 \x0b 和 \cK。
\w
匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
\W
匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。
\xn
匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如, '\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。.
\num
匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)' 匹配两个连续的相同字符。
\n
标识一个八进制转义值或一个后向引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
\nm
标识一个八进制转义值或一个后向引用。如果 \nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。
\nml
如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。
\un
匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (?)。