﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-细水常流-随笔分类-正则表达式</title><link>http://www.cppblog.com/nchsea/category/2949.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 20 May 2008 06:00:43 GMT</lastBuildDate><pubDate>Tue, 20 May 2008 06:00:43 GMT</pubDate><ttl>60</ttl><item><title>深入浅出之正则表达式（一）(二)----转</title><link>http://www.cppblog.com/nchsea/archive/2006/11/03/14638.html</link><dc:creator>sea</dc:creator><author>sea</author><pubDate>Fri, 03 Nov 2006 12:19:00 GMT</pubDate><guid>http://www.cppblog.com/nchsea/archive/2006/11/03/14638.html</guid><wfw:comment>http://www.cppblog.com/nchsea/comments/14638.html</wfw:comment><comments>http://www.cppblog.com/nchsea/archive/2006/11/03/14638.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/nchsea/comments/commentRss/14638.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/nchsea/services/trackbacks/14638.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 深入浅出之正则表达式（一）前言：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;半年前我对正则表达式产生了兴趣，在网上查找过不少资料，看过不少的教程，最后在使用一个正则表达式工具RegexBuddy时发现他的教程写的非常好，可以说是我目前见过最好的正则表达式教程。于是一直想把他翻译过来。这个愿望直到这个五一长假才得以实现，结果就有了这篇文章。关于本文的名字，...&nbsp;&nbsp;<a href='http://www.cppblog.com/nchsea/archive/2006/11/03/14638.html'>阅读全文</a><img src ="http://www.cppblog.com/nchsea/aggbug/14638.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/nchsea/" target="_blank">sea</a> 2006-11-03 20:19 <a href="http://www.cppblog.com/nchsea/archive/2006/11/03/14638.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正则表达式简介</title><link>http://www.cppblog.com/nchsea/archive/2006/11/03/14637.html</link><dc:creator>sea</dc:creator><author>sea</author><pubDate>Fri, 03 Nov 2006 12:11:00 GMT</pubDate><guid>http://www.cppblog.com/nchsea/archive/2006/11/03/14637.html</guid><wfw:comment>http://www.cppblog.com/nchsea/comments/14637.html</wfw:comment><comments>http://www.cppblog.com/nchsea/archive/2006/11/03/14637.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/nchsea/comments/commentRss/14637.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/nchsea/services/trackbacks/14637.html</trackback:ping><description><![CDATA[<TBODY>
        <TR>
          <TD>
            <HR>

            <P align=center><B>正则表达式简介</B></P>
            <P align=center>翻译：<A 
            href="mailto:northtibet@sohu.com">NorthTibet</A></P>
            <P align=left>原文出处：<A 
            href="http://msdn.microsoft.com/msdnmag/issues/05/04/C/default.aspx?side=true#a" 
            target=_blank>Regular Expressions</A></P>
            <HR>
            　　有些新手对正则表达式不是很熟悉，有必要在此作一简单回顾。如果你是正则表达式高手，可以不用看这一部分。<BR>　　正则表达式是描述字符串集的字符串。例如，正则表达式“Mic*”描述所有包含“Mic”，后跟零个或多个字符的字符串。Mickey、Microsoft、Michelangelo 
            或 Mic 
            本身都是例子。句号“.”匹配任何字符，“+”类似“*”，但至少要一个字符，所以“Mic+”匹配前述所有除“Mic”以外的串。[a-z]指一个匹配范围，所以[a-zA-Z_0-9]匹配字母、数字或下划线。Regex 
            称之为单词字符，可以将它写成“\w”。所以“\w+”匹配至少有一个字符的单词字符序列——换句话说，叫 C 符号（C 
            tokens）。那么这样一来，几乎所有的C 
            符号都不能以数字开头，因此，下面这个正则表达式是正确的：“^[a-zA-Z_]\w*$”。专用字符“^”意思是“以...开始”（除非它位于某个范围之内，这时它的意思是“非”），“$”意思是“结尾”，那么“^[a-zA-Z_]\w*$”意思就是：以字母或下划线开始的字母、数字或下划线字符串。<BR>　　正则表达式在对输入进行有效性验证时非常有用。\d 
            匹配数字，{n}匹配重复n次，于是 ^5\d{15}$ 匹配5开头的16位数字，也即是说 MasterCard 信用卡号码。那 
            ^[45]\d{15}$ 就是Visa 卡号，它以4开头。你可以用大括弧对表达式进行分组，下面是个测试。这个表达式描述的是什么呢？<PRE>^\d{5}(-\d{4}){0,1}$
</PRE>
            <P>提示：{0,1} 意思是重复0次或1次（可以缩写成问号 
            ?）。想出来了吗？该表达式意思是：五个数字后重复0次或1次（破折号后跟四个数字）。它匹配 02142和98007-4235，但不匹配 
            3245 或 2345-98761。这也就是美国的邮政编码。大括弧将 ZIP+4 
            部分分组，所以{0,1}修饰符将应用于整个分组。<BR>　　以上我仅浅尝即止地说明了正则表达式能做什么。我还没提到替换，由于我没有具体资料，所以不敢描述在 
            Unicode 中会怎么样。但你能感觉到正则表达式有多么强大。多年来它们乃 UNIX 的中流砥柱，并且在Web 编程和 Perl 
            这样的语言中更臻完善，其对 HTML 的操作几乎完全是对文本的处理。正则表达式在 Windows 中一直没有得到充分使用，直到 .NET 
            框架面世，它才正式成为 Windows 家族的一员。<BR><BR><B>框架 Regex 类</B><BR><BR>.NET 框架用 
            Regex 类实现正则表达式，并有三个支持类：Match、Group 和 Capture （参见 Figure A）。典型情况下，你创建 
            Regex 并用输入串调用 Regex::Match 来获得第一个 Match，或用 Regex::Matches 
            来获取所有匹配：</P><PRE>Regex *r = new Regex("\b\w+\b");
MatchCollection* mc = 
  r-&gt;Matches("abc ,_foo ,&lt;&amp; mumble7");
for (int i=0; i&lt;mc-&gt;Count; i++) {
   Match *m = mc-&gt;Index(i);
   Console.WriteLine(m-&gt;Value);
}
</PRE>　　这将显示“abc”，“foo”和“mumble7”，每个匹配在一行。这个例子引入了一个专门的字符 
            \b，所谓锚或原子零宽度断言，就像 ^(开始)和$(结尾)。\b 
            指定某个单词的边界，所以“\b\w+\b”意思是用单词分隔的一个或多个单词字符。<BR>　
            <P></P><IMG 
            src="http://www.vckbase.com/document/journal/vckbase41/images/wrapperfigA.gif"><BR>Figure 
            A&nbsp;Regex 类
            <P>　　正则表达式中的每个括弧表达式都构成一个 Group。Regex::Groups 返回作为集合的 
            Groups，它决不会是空，因为整个正则表达式本身即是一组。Groups 很重要，因为它们使你进行逻辑 OR 
            匹配，如“(ying|yong)”，它们使你将限定符应用到子表达式，并让你吸取匹配的单独部分。正文的 Figure 1 中我的 
            RegexTest 程序运行后用邮编为例显示分组。<BR>　　在所有函数中最强大的函数要数 
            Regex::Replace，它使得正则表达式的威力惊人地强大。和许多开发人员一样，过去在多次传递字符串到多行编辑控件之前，我常常不得不手工将 
            “\n” 转换为“\r\n”，但使用 Regex::Replace，这个操作简直易如反掌。</P><PRE>s = Regex::Replace(s,"\n","\r\n");
</PRE>
            <P></P>
            <P>　　Regex::Match 和 Replace 具备静态重载，所以你可以不用创建对象，以快速使用正则表达式。我最喜欢的 
            Regex::Replace 
            重载之一是带有一个委托参数，使你能用过程代码动态计算替换文本——参见正文中那个有趣的例子。<BR>　　一些警告：每一种正则表达式的实现是有不太一样的。例如，在 
            Perl 中，{,1}是{0,1}的速记版，而微软的老大们不是那样做的。要当心一些微小的差别。权威的 .NET Regex 资料请参考 
            MSDN 库中的 “<A 
            href="http://www.vckbase.com/library/en-us/cpguide/html/cpconregularexpressionsaslanguage.asp" 
            target=_blank>Regular Expressions as a Language</A>”。</P>
            <HR>
          </TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><img src ="http://www.cppblog.com/nchsea/aggbug/14637.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/nchsea/" target="_blank">sea</a> 2006-11-03 20:11 <a href="http://www.cppblog.com/nchsea/archive/2006/11/03/14637.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正则表达式教程</title><link>http://www.cppblog.com/nchsea/archive/2006/11/03/14635.html</link><dc:creator>sea</dc:creator><author>sea</author><pubDate>Fri, 03 Nov 2006 12:02:00 GMT</pubDate><guid>http://www.cppblog.com/nchsea/archive/2006/11/03/14635.html</guid><wfw:comment>http://www.cppblog.com/nchsea/comments/14635.html</wfw:comment><comments>http://www.cppblog.com/nchsea/archive/2006/11/03/14635.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/nchsea/comments/commentRss/14635.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/nchsea/services/trackbacks/14635.html</trackback:ping><description><![CDATA[<DIV class=entity>
<H2 class=diaryTitle>正则表达式教程</H2><B>关键词</B>： <A 
href="http://tag.bokee.com/tag/%D5%FD%D4%F2%B1%ED%B4%EF%CA%BD" 
target=_blank>正则表达式</A> &nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 

<P>
<P>转载自<A 
href="http://www.regexlab.com/zh/regref.htm">http://www.regexlab.com/zh/regref.htm</A></P>
<H2><B><A name=title></A>揭开正则表达式的神秘面纱</B></H2>
<P><FONT size=1>[原创文章，转载请保留或注明出处：<A 
href="http://www.regexlab.com/zh/regref.htm">http://www.regexlab.com/zh/regref.htm</A>]</FONT></P>
<P><B>引言</B><BR><BR>&nbsp;&nbsp;&nbsp; 正则表达式（regular 
expression）描述了一种字符串匹配的模式，可以用来：（1）检查一个串中是否含有符合某个规则的子串，并且可以得到这个子串；（2）根据匹配规则对字符串进行灵活的替换操作。<BR><BR>&nbsp;&nbsp;&nbsp; 
正则表达式学习起来其实是很简单的，不多的几个较为抽象的概念也很容易理解。之所以很多人感觉正则表达式比较复杂，一方面是因为大多数的文档没有做到由浅入深地讲解，概念上没有注意先后顺序，给读者的理解带来困难；另一方面，各种引擎自带的文档一般都要介绍它特有的功能，然而这部分特有的功能并不是我们首先要理解的。<BR><BR>&nbsp;&nbsp;&nbsp; 
文章中的每一个举例，都可以点击进入到测试页面进行测试。闲话少说，开始。</P>
<HR color=#fea089 SIZE=1>

<P><B>1. 正则表达式规则</B></P>
<P><B><A name=common></A>1.1 普通字符</B></P>
<P>&nbsp;&nbsp;&nbsp; 
字母、数字、汉字、下划线、以及后边章节中没有特殊定义的标点符号，都是"普通字符"。表达式中的普通字符，在匹配一个字符串的时候，匹配与之相同的一个字符。<BR><BR>&nbsp;&nbsp;&nbsp; 
<A href="http://www.regexlab.com/zh/workshop.asp?pat=c&amp;txt=abcde">举例1：表达式 
"c"，在匹配字符串 "abcde" 
时</A>，匹配结果是：成功；匹配到的内容是："c"；匹配到的位置是：开始于2，结束于3。（注：下标从0开始还是从1开始，因当前编程语言的不同而可能不同）<BR><BR>&nbsp;&nbsp;&nbsp; 
<A href="http://www.regexlab.com/zh/workshop.asp?pat=bcd&amp;txt=abcde">举例2：表达式 
"bcd"，在匹配字符串 "abcde" 时</A>，匹配结果是：成功；匹配到的内容是："bcd"；匹配到的位置是：开始于1，结束于4。</P>
<HR color=#fea089 SIZE=1>

<P><B><A name=escaped></A>1.2 简单的转义字符</B></P>
<P>&nbsp;&nbsp;&nbsp; 一些不便书写的字符，采用在前面加 "\" 的方法。这些字符其实我们都已经熟知了。</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=70>
      <P>表达式</P></TD>
    <TD>
      <P>可匹配</P></TD></TR>
  <TR>
    <TD>
      <P>\r, \n</P></TD>
    <TD>
      <P>代表回车和换行符</P></TD></TR>
  <TR>
    <TD>
      <P>\t</P></TD>
    <TD>
      <P>制表符</P></TD></TR>
  <TR>
    <TD>
      <P>\\</P></TD>
    <TD>
      <P>代表 "\" 本身</P></TD></TR></TBODY></TABLE></P>
<P>&nbsp;&nbsp;&nbsp; 还有其他一些在后边章节中有特殊用处的标点符号，在前面加 "\" 后，就代表该符号本身。比如：^, $ 
都有特殊意义，如果要想匹配字符串中 "^" 和 "$" 字符，则表达式就需要写成 "\^" 和 "\$"。</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=66>
      <P>表达式</P></TD>
    <TD>
      <P>可匹配</P></TD></TR>
  <TR>
    <TD>
      <P>\^</P></TD>
    <TD>
      <P>匹配 ^ 符号本身</P></TD></TR>
  <TR>
    <TD>
      <P>\$</P></TD>
    <TD>
      <P>匹配 $ 符号本身</P></TD></TR>
  <TR>
    <TD>
      <P>\.</P></TD>
    <TD>
      <P>匹配小数点（.）本身</P></TD></TR></TBODY></TABLE></P>
<P>&nbsp;&nbsp;&nbsp; 这些转义字符的匹配方法与 "普通字符" 
是类似的。也是匹配与之相同的一个字符。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%5C$d&amp;txt=abc$de">举例1：表达式 
"\$d"，在匹配字符串 "abc$de" 时</A>，匹配结果是：成功；匹配到的内容是："$d"；匹配到的位置是：开始于3，结束于5。</P>
<HR color=#fea089 SIZE=1>

<P><B><A name=multi></A>1.3 能够与 '多种字符' 匹配的表达式</B></P>
<P>&nbsp;&nbsp;&nbsp; 正则表达式中的一些表示方法，可以匹配 '多种字符' 其中的任意一个字符。比如，表达式 "\d" 
可以匹配任意一个数字。虽然可以匹配其中任意字符，但是只能是一个，不是多个。这就好比玩扑克牌时候，大小王可以代替任意一张牌，但是只能代替一张牌。</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=66>
      <P>表达式</P></TD>
    <TD>
      <P>可匹配</P></TD></TR>
  <TR>
    <TD>
      <P>\d</P></TD>
    <TD>
      <P>任意一个数字，0~9 中的任意一个</P></TD></TR>
  <TR>
    <TD>
      <P>\w</P></TD>
    <TD>
      <P>任意一个字母或数字或下划线，也就是 A~Z,a~z,0~9,_ 中任意一个</P></TD></TR>
  <TR>
    <TD>
      <P>\s</P></TD>
    <TD>
      <P>包括空格、制表符、换页符等空白字符的其中任意一个</P></TD></TR>
  <TR>
    <TD>
      <P>.</P></TD>
    <TD>
      <P>小数点可以匹配除了换行符（\n）以外的任意一个字符</P></TD></TR></TBODY></TABLE></P>
<P>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cd%5Cd&amp;txt=abc123">举例1：表达式 
"\d\d"，在匹配 "abc123" 
时</A>，匹配的结果是：成功；匹配到的内容是："12"；匹配到的位置是：开始于3，结束于5。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=a.%5Cd&amp;txt=aaa100">举例2：表达式 
"a.\d"，在匹配 "aaa100" 时</A>，匹配的结果是：成功；匹配到的内容是："aa1"；匹配到的位置是：开始于1，结束于4。</P>
<HR color=#fea089 SIZE=1>

<P><B><A name=custom></A>1.4 自定义能够匹配 '多种字符' 的表达式</B></P>
<P>&nbsp;&nbsp;&nbsp; 使用方括号 [ ] 包含一系列字符，能够匹配其中任意一个字符。用 [^ ] 
包含一系列字符，则能够匹配其中字符之外的任意一个字符。同样的道理，虽然可以匹配其中任意一个，但是只能是一个，不是多个。</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=80>
      <P>表达式</P></TD>
    <TD>
      <P>可匹配</P></TD></TR>
  <TR>
    <TD>
      <P>[ab5@]</P></TD>
    <TD>
      <P>匹配 "a" 或 "b" 或 "5" 或 "@"</P></TD></TR>
  <TR>
    <TD>
      <P>[^abc]</P></TD>
    <TD>
      <P>匹配 "a","b","c" 之外的任意一个字符</P></TD></TR>
  <TR>
    <TD>
      <P>[f-k]</P></TD>
    <TD>
      <P>匹配 "f"~"k" 之间的任意一个字母</P></TD></TR>
  <TR>
    <TD>
      <P>[^A-F0-3]</P></TD>
    <TD>
      <P>匹配 "A"~"F","0"~"3" 之外的任意一个字符</P></TD></TR></TBODY></TABLE></P>
<P>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=[bcd][bcd]&amp;txt=abc123">举例1：表达式 
"[bcd][bcd]" 匹配 "abc123" 
时</A>，匹配的结果是：成功；匹配到的内容是："bc"；匹配到的位置是：开始于1，结束于3。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%5B%5Eabc%5D&amp;txt=abc123">举例2：表达式 
"[^abc]" 匹配 "abc123" 时</A>，匹配的结果是：成功；匹配到的内容是："1"；匹配到的位置是：开始于3，结束于4。</P>
<HR color=#fea089 SIZE=1>

<P><B><A name=times></A>1.5 修饰匹配次数的特殊符号</B></P>
<P>&nbsp;&nbsp;&nbsp; 
前面章节中讲到的表达式，无论是只能匹配一种字符的表达式，还是可以匹配多种字符其中任意一个的表达式，都只能匹配一次。如果使用表达式再加上修饰匹配次数的特殊符号，那么不用重复书写表达式就可以重复匹配。<BR><BR>&nbsp;&nbsp;&nbsp; 
使用方法是："次数修饰"放在"被修饰的表达式"后边。比如："[bcd][bcd]" 可以写成 "[bcd]{2}"。</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=67>
      <P>表达式</P></TD>
    <TD>
      <P>作用</P></TD></TR>
  <TR>
    <TD>
      <P>{n}</P></TD>
    <TD>
      <P>表达式重复n次，比如：<A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=\w{2}&amp;txt=ab+c6">"\w{2}" 
      相当于 "\w\w"</A>；<A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=a{5}&amp;txt=bbaaaaaddee">"a{5}" 
      相当于 "aaaaa"</A></P></TD></TR>
  <TR>
    <TD>
      <P>{m,n}</P></TD>
    <TD>
      <P>表达式至少重复m次，最多重复n次，比如：<A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=ba{1,3}&amp;txt=a,baaa,baa,b,ba">"ba{1,3}"可以匹配 
      "ba"或"baa"或"baaa"</A></P></TD></TR>
  <TR>
    <TD>
      <P>{m,}</P></TD>
    <TD>
      <P>表达式至少重复m次，比如：<A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=\w\d{2,}&amp;txt=b1,a12,_456,_4AA,M12344,12346546547446534543543">"\w\d{2,}"可以匹配 
      "a12","_456","M12344"...</A></P></TD></TR>
  <TR>
    <TD>
      <P>?</P></TD>
    <TD>
      <P>匹配表达式0次或者1次，相当于 {0,1}，比如：<A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=a[cd]%3F&amp;txt=a,c,d,ac,ad">"a[cd]?"可以匹配 
      "a","ac","ad"</A></P></TD></TR>
  <TR>
    <TD>
      <P>+</P></TD>
    <TD>
      <P>表达式至少出现1次，相当于 {1,}，比如：<A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=a%2Bb&amp;txt=a%2Cb%2Cab%2Caab%2Caaab">"a+b"可以匹配 
      "ab","aab","aaab"...</A></P></TD></TR>
  <TR>
    <TD>
      <P>*</P></TD>
    <TD>
      <P>表达式不出现或出现任意次，相当于 {0,}，比如：<A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=%5C%5E*b&amp;txt=%5E%2Cb%2C%5E%5E%5Eb%2C%5E%5E%5E%5E%5E%5E%5Eb">"\^*b"可以匹配 
      "b","^^^b"...</A></P></TD></TR></TBODY></TABLE></P>
<P>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cd%2B%5C.%3F%5Cd*&amp;txt=It%20costs%20%2412.5">举例1：表达式 
"\d+\.?\d*" 在匹配 "It costs $12.5" 
时</A>，匹配的结果是：成功；匹配到的内容是："12.5"；匹配到的位置是：开始于10，结束于14。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=go{2,8}gle&amp;txt=Ads%20by%20goooooogle%2C%20or%20gooogle">举例2：表达式 
"go{2,8}gle" 在匹配 "Ads by goooooogle" 
时</A>，匹配的结果是：成功；匹配到的内容是："goooooogle"；匹配到的位置是：开始于7，结束于17。</P>
<HR color=#fea089 SIZE=1>

<P><B><A name=special></A>1.6 其他一些代表抽象意义的特殊符号</B></P>
<P>&nbsp;&nbsp;&nbsp; 一些符号在表达式中代表抽象的特殊意义：</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=67>
      <P>表达式</P></TD>
    <TD>
      <P>作用</P></TD></TR>
  <TR>
    <TD>
      <P>^</P></TD>
    <TD>
      <P>与字符串开始的地方匹配，不匹配任何字符</P></TD></TR>
  <TR>
    <TD>
      <P>$</P></TD>
    <TD>
      <P>与字符串结束的地方匹配，不匹配任何字符</P></TD></TR>
  <TR>
    <TD>
      <P>\b</P></TD>
    <TD>
      <P>匹配一个单词边界，也就是单词和空格之间的位置，不匹配任何字符</P></TD></TR></TBODY></TABLE></P>
<P>&nbsp;&nbsp;&nbsp; 进一步的文字说明仍然比较抽象，因此，举例帮助大家理解。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=^aaa&amp;txt=xxx+aaa+xxx">举例1：表达式 
"^aaa" 在匹配 "xxx aaa xxx" 时</A>，匹配结果是：失败。因为 "^" 要求与字符串开始的地方匹配，因此，只有当 "aaa" 
位于字符串的开头的时候，"^aaa" 才能匹配，<A 
href="http://www.regexlab.com/zh/workshop.asp?pat=^aaa&amp;txt=aaa+xxx+xxx">比如："aaa 
xxx xxx"</A>。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=aaa$&amp;txt=xxx+aaa+xxx">举例2：表达式 
"aaa$" 在匹配 "xxx aaa xxx" 时</A>，匹配结果是：失败。因为 "$" 要求与字符串结束的地方匹配，因此，只有当 "aaa" 
位于字符串的结尾的时候，"aaa$" 才能匹配，<A 
href="http://www.regexlab.com/zh/workshop.asp?pat=aaa$&amp;txt=xxx+xxx+aaa">比如："xxx 
xxx aaa"</A>。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=.%5Cb.&amp;txt=@@@abc">http://www.regexlab.com/zh/workshop.asp?pat=.%5Cb.&amp;txt=@@@abc</A>，匹配结果是：成功；匹配到的内容是："@a"；匹配到的位置是：开始于2，结束于4。<BR>&nbsp;&nbsp;&nbsp; 
进一步说明："\b" 与 "^" 和 "$" 类似，本身不匹配任何字符，但是它要求它在匹配结果中所处位置的左右两边，其中一边是 "\w" 范围，另一边是 
非"\w" 的范围。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cbend%5Cb&amp;txt=weekend,endfor,end">举例4：表达式 
"\bend\b" 在匹配 "weekend,endfor,end" 
时</A>，匹配结果是：成功；匹配到的内容是："end"；匹配到的位置是：开始于15，结束于18。</P>
<P>&nbsp;&nbsp;&nbsp; 一些符号可以影响表达式内部的子表达式之间的关系：</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=65>
      <P>表达式</P></TD>
    <TD>
      <P>作用</P></TD></TR>
  <TR>
    <TD>
      <P>|</P></TD>
    <TD>
      <P>左右两边表达式之间 "或" 关系，匹配左边或者右边</P></TD></TR>
  <TR>
    <TD>
      <P>( )</P></TD>
    <TD>
      <P>(1). 在被修饰匹配次数的时候，括号中的表达式可以作为整体被修饰<BR>(2). 
      取匹配结果的时候，括号中的表达式匹配到的内容可以被单独得到</P></TD></TR></TBODY></TABLE></P>
<P>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=Tom%7CJack&amp;txt=I%27m+Tom%2C+he+is+Jack">举例5：表达式 
"Tom|Jack" 在匹配字符串 "I'm Tom, he is Jack" 
时</A>，匹配结果是：成功；匹配到的内容是："Tom"；匹配到的位置是：开始于4，结束于7。匹配下一个时，匹配结果是：成功；匹配到的内容是："Jack"；匹配到的位置时：开始于15，结束于19。<BR><BR>&nbsp;&nbsp;&nbsp; 
<A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%28go%5Cs*%29%2B&amp;txt=Let%27s%20go%20go%20go%21">举例6：表达式 
"(go\s*)+" 在匹配 "Let's go go go!" 时</A>，匹配结果是：成功；匹配到内容是："go go 
go"；匹配到的位置是：开始于6，结束于14。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%uFFE5%28%5Cd%2B%5C.%3F%5Cd*%29&amp;txt=%uFF0410.9%2C%uFFE520.5">举例7：表达式 
"￥(\d+\.?\d*)" 在匹配 "＄10.9,￥20.5" 
时</A>，匹配的结果是：成功；匹配到的内容是："￥20.5"；匹配到的位置是：开始于6，结束于10。单独获取括号范围匹配到的内容是："20.5"。</P>
<HR color=#fea089 SIZE=1>

<P><B>2. 正则表达式中的一些高级规则</B></P>
<P><B><A name=reluctant></A>2.1 匹配次数中的贪婪与非贪婪</B></P>
<P>&nbsp;&nbsp;&nbsp; 在使用修饰匹配次数的特殊符号时，有几种表示方法可以使同一个表达式能够匹配不同的次数，比如："{m,n}", 
"{m,}", "?", "*", "+"，具体匹配的次数随被匹配的字符串而定。这种重复匹配不定次数的表达式在匹配过程中，总是尽可能多的匹配。比如，针对文本 
"dxxxdxxxd"，举例如下：</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=93>
      <P>表达式</P></TD>
    <TD>
      <P>匹配结果</P></TD></TR>
  <TR>
    <TD>
      <P><A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=(d)(%5Cw%2B)&amp;txt=dxxxdxxxd">(d)(\w+)</A></P></TD>
    <TD>
      <P>"\w+" 将匹配第一个 "d" 之后的所有字符 "xxxdxxxd"</P></TD></TR>
  <TR>
    <TD>
      <P><A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=(d)(%5Cw%2B)(d)&amp;txt=dxxxdxxxd">(d)(\w+)(d)</A></P></TD>
    <TD>
      <P>"\w+" 将匹配第一个 "d" 和最后一个 "d" 之间的所有字符 "xxxdxxx"。虽然 "\w+" 也能够匹配上最后一个 
      "d"，但是为了使整个表达式匹配成功，"\w+" 可以 "让出" 它本来能够匹配的最后一个 
"d"</P></TD></TR></TBODY></TABLE></P>
<P>&nbsp;&nbsp;&nbsp; 由此可见，"\w+" 在匹配的时候，总是尽可能多的匹配符合它规则的字符。虽然第二个举例中，它没有匹配最后一个 
"d"，但那也是为了让整个表达式能够匹配成功。同理，带 "*" 和 "{m,n}" 的表达式都是尽可能地多匹配，带 "?" 
的表达式在可匹配可不匹配的时候，也是尽可能的 "要匹配"。这 种匹配原则就叫作 "贪婪" 模式 。</P>
<P>&nbsp;&nbsp;&nbsp; 非贪婪模式：<BR><BR>&nbsp;&nbsp;&nbsp; 在修饰匹配次数的特殊符号后再加上一个 "?" 
号，则可以使匹配次数不定的表达式尽可能少的匹配，使可匹配可不匹配的表达式，尽可能的 "不匹配"。这种匹配原则叫作 "非贪婪" 模式，也叫作 "勉强" 
模式。如果少匹配就会导致整个表达式匹配失败的时候，与贪婪模式类似，非贪婪模式会最小限度的再匹配一些，以使整个表达式匹配成功。举例如下，针对文本 
"dxxxdxxxd" 举例：</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=93>
      <P>表达式</P></TD>
    <TD>
      <P>匹配结果</P></TD></TR>
  <TR>
    <TD>
      <P><A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=(d)(%5Cw%2B%3F)&amp;txt=dxxxdxxxd">(d)(\w+?)</A></P></TD>
    <TD>
      <P>"\w+?" 将尽可能少的匹配第一个 "d" 之后的字符，结果是："\w+?" 只匹配了一个 "x"</P></TD></TR>
  <TR>
    <TD>
      <P><A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=(d)(%5Cw%2B%3F)(d)&amp;txt=dxxxdxxxd">(d)(\w+?)(d)</A></P></TD>
    <TD>
      <P>为了让整个表达式匹配成功，"\w+?" 不得不匹配 "xxx" 才可以让后边的 "d" 
      匹配，从而使整个表达式匹配成功。因此，结果是："\w+?" 匹配 "xxx"</P></TD></TR></TBODY></TABLE></P>
<P>&nbsp;&nbsp;&nbsp; 更多的情况，举例如下：<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%3Ctd%3E%28%2E%2A%29%3C%2Ftd%3E&amp;txt=%3Ctd%3E%3Cp%3Eaa%3C%2Fp%3E%3C%2Ftd%3E%3Ctd%3E%3Cp%3Ebb%3C%2Fp%3E%3C%2Ftd%3E">举例1：表达式 
"&lt;td&gt;(.*)&lt;/td&gt;" 与字符串 "&lt;td&gt;&lt;p&gt;aa&lt;/p&gt;&lt;/td&gt; 
&lt;td&gt;&lt;p&gt;bb&lt;/p&gt;&lt;/td&gt;" 匹配时</A>，匹配的结果是：成功；匹配到的内容是 
"&lt;td&gt;&lt;p&gt;aa&lt;/p&gt;&lt;/td&gt; 
&lt;td&gt;&lt;p&gt;bb&lt;/p&gt;&lt;/td&gt;" 整个字符串， 表达式中的 "&lt;/td&gt;" 
将与字符串中最后一个 "&lt;/td&gt;" 匹配。 <BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%3Ctd%3E%28%2E%2A%3F%29%3C%2Ftd%3E&amp;txt=%3Ctd%3E%3Cp%3Eaa%3C%2Fp%3E%3C%2Ftd%3E%3Ctd%3E%3Cp%3Ebb%3C%2Fp%3E%3C%2Ftd%3E">举例2：相比之下，表达式 
"&lt;td&gt;(.*?)&lt;/td&gt;" 匹配举例1中同样的字符串时</A>，将只得到 
"&lt;td&gt;&lt;p&gt;aa&lt;/p&gt;&lt;/td&gt;"， 再次匹配下一个时，可以得到第二个 
"&lt;td&gt;&lt;p&gt;bb&lt;/p&gt;&lt;/td&gt;"。</P>
<HR color=#fea089 SIZE=1>

<P><B><A name=backref></A>2.2 反向引用 \1, \2...</B></P>
<P>&nbsp;&nbsp;&nbsp; 表达式在匹配时，表达式引擎会将小括号 "( )" 
包含的表达式所匹配到的字符串记录下来。在获取匹配结果的时候，小括号包含的表达式所匹配到的字符串可以单独获取。这一点，在前面的举例中，已经多次展示了。在实际应用场合中，当用某种边界来查找，而所要获取的内容又不包含边界时，必须使用小括号来指定所要的范围。比如前面的 
"&lt;td&gt;(.*?)&lt;/td&gt;"。<BR><BR>&nbsp;&nbsp;&nbsp; 其实，"小括号包含的表达式所匹配到的字符串" 
不仅是在匹配结束后才可以使用，在匹配过程中也可以使用。表达式后边的部分，可以引用前面 "括号内的子匹配已经匹配到的字符串"。引用方法是 "\" 
加上一个数字。"\1" 引用第1对括号内匹配到的字符串，"\2" 
引用第2对括号内匹配到的字符串……以此类推，如果一对括号内包含另一对括号，则外层的括号先排序号。换句话说，哪一对的左括号 "(" 
在前，那这一对就先排序号。</P>
<P>&nbsp;&nbsp;&nbsp; 举例如下：<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%28%27%7C%22%29%28%2E%2A%3F%29%28%5C1%29&amp;txt=%27Hello%27%2C+%22World%22">举例1：表达式 
"('|")(.*?)(\1)" 在匹配 " 'Hello', "World" " 时</A>，匹配结果是：成功；匹配到的内容是：" 'Hello' 
"。再次匹配下一个时，可以匹配到 " "World" "。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%28%5Cw%29%5C1%7B4%2C%7D&amp;txt=aa%20bbbb%20abcdefg%20ccccc%20111121111%20999999999">举例2：表达式 
"(\w)\1{4,}" 在匹配 "aa bbbb abcdefg ccccc 111121111 999999999" 
时</A>，匹配结果是：成功；匹配到的内容是 "ccccc"。再次匹配下一个时，将得到 999999999。这个表达式要求 "\w" 
范围的字符至少重复5次，<A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cw%7B5%2C%7D&amp;txt=aa%20bbbb%20abcdefg%20ccccc%20111121111%20999999999">注意与 
"\w{5,}" 之间的区别</A>。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%3C%28%5Cw%2B%29%5Cs%2A%28%5Cw%2B%28%3D%28%27%7C%22%29%2E%2A%3F%5C4%29%3F%5Cs%2A%29%2A%3E%2E%2A%3F%3C%2F%5C1%3E&amp;txt=%3Ctd+id%3D%27td1%27+style%3D%22bgcolor%3Awhite%22%3E%3C%2Ftd%3E%0D%0A%3Cbody+onload%3D%22doit%28%29%22%3E%3C%2Fbody%3E">举例3：表达式 
"&lt;(\w+)\s*(\w+(=('|").*?\4)?\s*)*&gt;.*?&lt;/\1&gt;" 在匹配 "&lt;td id='td1' 
style="bgcolor:white"&gt;&lt;/td&gt;" 时</A>，匹配结果是成功。如果 "&lt;td&gt;" 与 
"&lt;/td&gt;" 不配对，则会匹配失败；如果改成其他配对，也可以匹配成功。</P>
<HR color=#fea089 SIZE=1>

<P><B><A name=forward></A>2.3 预搜索，不匹配；反向预搜索，不匹配</B></P>
<P>&nbsp;&nbsp;&nbsp; 
前面的章节中，我讲到了几个代表抽象意义的特殊符号："^"，"$"，"\b"。它们都有一个共同点，那就是：它们本身不匹配任何字符，只是对 "字符串的两头" 或者 
"字符之间的缝隙" 附加了一个条件。理解到这个概念以后，本节将继续介绍另外一种对 "两头" 或者 "缝隙" 附加条件的，更加灵活的表示方法。</P>
<P>&nbsp;&nbsp;&nbsp; 正向预搜索："(?=xxxxx)"，"(?!xxxxx)"<BR><BR>&nbsp;&nbsp;&nbsp; 
格式："(?=xxxxx)"，在被匹配的字符串中，它对所处的 "缝隙" 或者 "两头" 附加的条件是：所在缝隙的右侧，必须能够匹配上 xxxxx 
这部分的表达式。因为它只是在此作为这个缝隙上附加的条件，所以它并不影响后边的表达式去真正匹配这个缝隙之后的字符。这就类似 "\b"，本身不匹配任何字符。"\b" 
只是将所在缝隙之前、之后的字符取来进行了一下判断，不会影响后边的表达式来真正的匹配。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=Windows+%28%3F%3DNT%7CXP%29&amp;txt=Windows+98%2C+Windows+NT%2C+Windows+2000">举例1：表达式 
"Windows (?=NT|XP)" 在匹配 "Windows 98, Windows NT, Windows 2000" 时</A>，将只匹配 
"Windows NT" 中的 "Windows "，其他的 "Windows " 字样则不被匹配。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%28%5Cw%29%28%28%3F%3D%5C1%5C1%5C1%29%28%5C1%29%29%2B&amp;txt=aaa+ffffff+999999999">举例2：表达式 
"(\w)((?=\1\1\1)(\1))+" 在匹配字符串 "aaa ffffff 999999999" 
时</A>，将可以匹配6个"f"的前4个，可以匹配9个"9"的前7个。这个表达式可以读解成：重复4次以上的字母数字，则匹配其剩下最后2位之前的部分。当然，这个表达式可以不这样写，在此的目的是作为演示之用。</P>
<P>&nbsp;&nbsp;&nbsp; 格式："(?!xxxxx)"，所在缝隙的右侧，必须不能匹配 xxxxx 
这部分表达式。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%28%28%3F%21%5Cbstop%5Cb%29%2E%29%2B&amp;txt=fdjka+ljfdl+stop+fjdsla+fdj">举例3：表达式 
"((?!\bstop\b).)+" 在匹配 "fdjka ljfdl stop fjdsla fdj" 时</A>，将从头一直匹配到 "stop" 
之前的位置，如果字符串中没有 "stop"，则匹配整个字符串。<BR><BR>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=do%28%3F%21%5Cw%29&amp;txt=done%2C+do%2C+dog">举例4：表达式 
"do(?!\w)" 在匹配字符串 "done, do, dog" 时</A>，只能匹配 "do"。在本条举例中，"do" 后边使用 "(?!\w)" 和使用 
"\b" 效果是一样的。</P>
<P>&nbsp;&nbsp;&nbsp; 
反向预搜索："(?&lt;=xxxxx)"，"(?&lt;!xxxxx)"<BR><BR>&nbsp;&nbsp;&nbsp; 
这两种格式的概念和正向预搜索是类似的，反向预搜索要求的条件是：所在缝隙的 "左侧"，两种格式分别要求必须能够匹配和必须不能够匹配指定表达式，而不是去判断右侧。与 
"正向预搜索" 一样的是：它们都是对所在缝隙的一种附加条件，本身都不匹配任何字符。<BR><BR>&nbsp;&nbsp;&nbsp; 举例5：表达式 
"(?&lt;=\d{4})\d+(?=\d{4})" 在匹配 "1234567890123456" 
时，将匹配除了前4个数字和后4个数字之外的中间8个数字。由于 JScript.RegExp 
不支持反向预搜索，因此，本条举例不能够进行演示。很多其他的引擎可以支持反向预搜索，比如：Java 1.4 以上的 java.util.regex 包，.NET 
中System.Text.RegularExpressions 命名空间，boost::regex 以及 <A 
href="http://www.nk975.com/sswater/zh/greta/index.htm">GRETA 正则表达式库</A>等。</P>
<HR color=#fea089 SIZE=1>

<P><B><A name=othercommon></A>3. 其他通用规则</B></P>
<P>&nbsp;&nbsp;&nbsp; 还有一些在各个正则表达式引擎之间比较通用的规则，在前面的讲解过程中没有提到。</P>
<P>3.1 表达式中，可以使用 "\xXX" 和 "\uXXXX" 表示一个字符（"X" 表示一个十六进制数）</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=63>
      <P>形式</P></TD>
    <TD>
      <P>字符范围</P></TD></TR>
  <TR>
    <TD>
      <P>\xXX</P></TD>
    <TD>
      <P>编号在 0 ~ 255 范围的字符，比如：<A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cx20&amp;txt=It+is%2E">空格可以使用 
      "\x20" 表示</A></P></TD></TR>
  <TR>
    <TD>
      <P>\uXXXX</P></TD>
    <TD>
      <P>任何字符可以使用 "\u" 再加上其编号的4位十六进制数表示，比如：<A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cu4E2D&amp;txt=%D6%D0%B9%FA">"\u4E2D"</A></P></TD></TR></TBODY></TABLE></P>
<P>3.2 在表达式 "\s"，"\d"，"\w"，"\b" 表示特殊意义的同时，对应的大写字母表示相反的意义</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=55>
      <P>表达式</P></TD>
    <TD>
      <P>可匹配</P></TD></TR>
  <TR>
    <TD>
      <P>\S</P></TD>
    <TD>
      <P><A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=%5CS%2B&amp;txt=abc+123+%40%23%24%25">匹配所有非空白字符（"\s" 
      可匹配各个空白字符）</A></P></TD></TR>
  <TR>
    <TD>
      <P>\D</P></TD>
    <TD>
      <P><A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=%5CD%2B&amp;txt=abc+123+%40%23%24%25">匹配所有的非数字字符</A></P></TD></TR>
  <TR>
    <TD>
      <P>\W</P></TD>
    <TD>
      <P><A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=%5CW%2B&amp;txt=abc+123+%40%23%24%25">匹配所有的字母、数字、下划线以外的字符</A></P></TD></TR>
  <TR>
    <TD>
      <P>\B</P></TD>
    <TD>
      <P><A 
      href="http://www.regexlab.com/zh/workshop.asp?pat=%5CB%2E%5CB&amp;txt=abc+123+%40%23%24%25">匹配非单词边界，即左右两边都是 
      "\w" 范围或者左右两边都不是 "\w" 范围时的字符缝隙</A></P></TD></TR></TBODY></TABLE></P>
<P>3.3 在表达式中有特殊意义，需要添加 "\" 才能匹配该字符本身的字符汇总</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=55>
      <P>字符</P></TD>
    <TD>
      <P>说明</P></TD></TR>
  <TR>
    <TD>
      <P>^</P></TD>
    <TD>
      <P>匹配输入字符串的开始位置。要匹配 "^" 字符本身，请使用 "\^"</P></TD></TR>
  <TR>
    <TD>
      <P>$</P></TD>
    <TD>
      <P>匹配输入字符串的结尾位置。要匹配 "$" 字符本身，请使用 "\$"</P></TD></TR>
  <TR>
    <TD>
      <P>( )</P></TD>
    <TD>
      <P>标记一个子表达式的开始和结束位置。要匹配小括号，请使用 "\(" 和 "\)"</P></TD></TR>
  <TR>
    <TD>
      <P>[ ]</P></TD>
    <TD>
      <P>用来自定义能够匹配 '多种字符' 的表达式。要匹配中括号，请使用 "\[" 和 "\]"</P></TD></TR>
  <TR>
    <TD>
      <P>{ }</P></TD>
    <TD>
      <P>修饰匹配次数的符号。要匹配大括号，请使用 "\{" 和 "\}"</P></TD></TR>
  <TR>
    <TD>
      <P>.</P></TD>
    <TD>
      <P>匹配除了换行符（\n）以外的任意一个字符。要匹配小数点本身，请使用 "\."</P></TD></TR>
  <TR>
    <TD>
      <P>?</P></TD>
    <TD>
      <P>修饰匹配次数为 0 次或 1 次。要匹配 "?" 字符本身，请使用 "\?"</P></TD></TR>
  <TR>
    <TD>
      <P>+</P></TD>
    <TD>
      <P>修饰匹配次数为至少 1 次。要匹配 "+" 字符本身，请使用 "\+"</P></TD></TR>
  <TR>
    <TD>
      <P>*</P></TD>
    <TD>
      <P>修饰匹配次数为 0 次或任意次。要匹配 "*" 字符本身，请使用 "\*"</P></TD></TR>
  <TR>
    <TD>
      <P>|</P></TD>
    <TD>
      <P>左右两边表达式之间 "或" 关系。匹配 "|" 本身，请使用 "\|"</P></TD></TR></TBODY></TABLE></P>
<P>3.4 括号 "( )" 内的子表达式，如果希望匹配结果不进行记录供以后使用，可以使用 "(?:xxxxx)" 格式</P>
<P>&nbsp;&nbsp;&nbsp; <A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%28%3F%3A%28%5Cw%29%5C1%29%2B&amp;txt=a bbccdd efg">举例1：表达式 
"(?:(\w)\1)+" 匹配 "a bbccdd efg" 时</A>，结果是 "bbccdd"。括号 "(?:)" 范围的匹配结果不进行记录，因此 
"(\w)" 使用 "\1" 来引用。</P>
<P>3.5 常用的表达式属性设置简介：Ignorecase，Singleline，Multiline，Global</P>
<P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 
bgColor=#f8f8f8 border=1>
  <TBODY>
  <TR bgColor=#f0f0f0>
    <TD width=80>
      <P>表达式属性</P></TD>
    <TD>
      <P>说明</P></TD></TR>
  <TR>
    <TD>
      <P>Ignorecase</P></TD>
    <TD>
      <P>默认情况下，表达式中的字母是要区分大小写的。配置为 Ignorecase 可使匹配时不区分大小写。有的表达式引擎，把 "大小写" 概念延伸至 
      UNICODE 范围的大小写。</P></TD></TR>
  <TR>
    <TD>
      <P>Singleline</P></TD>
    <TD>
      <P>默认情况下，小数点 "." 匹配除了换行符（\n）以外的字符。配置为 Singleline 
    可使小数点可匹配包括换行符在内的所有字符。</P></TD></TR>
  <TR>
    <TD>
      <P>Multiline</P></TD>
    <TD>
      <P>默认情况下，表达式 "^" 和 "$" 只匹配字符串的开始 ① 和结尾 ④ 
      位置。如：<BR><BR>①xxxxxxxxx②\n<BR>③xxxxxxxxx④<BR><BR>配置为 Multiline 可以使 "^" 匹配 
      ① 外，还可以匹配换行符之后，下一行开始前 ③ 的位置，使 "$" 匹配 ④ 外，还可以匹配换行符之前，一行结束 ② 的位置。</P></TD></TR>
  <TR>
    <TD>
      <P>Global</P></TD>
    <TD>
      <P>主要在将表达式用来替换时起作用，配置为 Global 表示替换所有的匹配。</P></TD></TR></TBODY></TABLE></P>
<P>
<HR color=#fea089 SIZE=1>

<P>
<P><B><A name=prompt></A>4. 综合提示</B></P>
<P>4.1 如果要要求表达式所匹配的内容是整个字符串，而不是从字符串中找一部分，那么可以在表达式的首尾使用 "^" 和 "$"，比如："^\d+$" 
要求整个字符串只有数字。</P>
<P>4.2 如果要求匹配的内容是一个完整的单词，而不会是单词的一部分，那么在表达式首尾使用 "\b"，比如：<A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cb%28if%7Cwhile%7Celse%7Cvoid%7Cint%29%5Cb&amp;txt=if%28ifdo%29%0D%0A++++dosome%28%29%3B%0D%0Aelse%0D%0A++++doelse%28%29%3B">使用 
"\b(if|while|else|void|int……)\b" 来匹配程序中的关键字</A>。</P>
<P>4.3 表达式不要匹配空字符串。否则会一直得到匹配成功，而结果什么都没有匹配到。比如：准备写一个匹配 "123"、"123."、"123.5"、".5" 
这几种形式的表达式时，整数、小数点、小数数字都可以省略，但是不要将表达式写成："\d*\.?\d*"，因为如果什么都没有，这个表达式也可以匹配成功。<A 
href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cd%2B%5C%2E%3F%5Cd%2A%7C%5C%2E%5Cd%2B&amp;txt=123%2C+123%2E%2C+123%2E5%2C+%2E5%2C+%2E">更好的写法是："\d+\.?\d*|\.\d+"</A>。</P>
<P>4.4 能匹配空字符串的子匹配不要循环无限次。如果括号内的子表达式中的每一部分都可以匹配 0 
次，而这个括号整体又可以匹配无限次，那么情况可能比上一条所说的更严重，匹配过程中可能死循环。虽然现在有些正则表达式引擎已经通过办法避免了这种情况出现死循环了，比如 
.NET 的正则表达式，但是我们仍然应该尽量避免出现这种情况。如果我们在写表达式时遇到了死循环，也可以从这一点入手，查找一下是否是本条所说的原因。</P>
<P>4.5 合理选择贪婪模式与非贪婪模式，参见<A 
href="http://www.regexlab.com/zh/regtopic.htm#reluctant">话题讨论</A>。</P>
<P>4.6 或 "|" 的左右两边，对某个字符最好只有一边可以匹配，这样，不会因为 "|" 两边的表达式因为交换位置而有所不同。</P>
<HR color=#fea089 SIZE=1>

<P><B>5. 更多正则表达式话题 </B><BR><BR>访问“<A 
href="http://www.regexlab.com/zh/regtopic.htm">正则表达式话题</A>”，进一步讨论正则表达式运用。</P>
<P>也可以在以下搜索字段中输入关键字，查找问题的答案。 <BR></P><!-- Search Google -->
<FORM action=http://www.google.com/custom method=get target=_top>
<TABLE bgColor=#ffffff>
  <TBODY>
  <TR>
    <TD vAlign=top noWrap align=left height=32><INPUT maxLength=255 size=31 
      name=q></INPUT /> <INPUT type=submit value=提交查询内容 name=sa></INPUT 
      />&nbsp;</INPUT />&nbsp;</INPUT />&nbsp;</INPUT />&nbsp;</INPUT 
      />&nbsp;</INPUT />&nbsp;</INPUT /> </TD></TR></TBODY></TABLE></FORM><!-- Search Google -->
<P></P>
<P class=diaryFoot>【作者: <A 
onclick="window.open('http://publishblog.blogchina.com/blog/postMessage.b?receiver=234781','发送短消息','width=520, height=455')" 
href="javascript:void(0);">bym</A>】【访问统计:
<SCRIPT language=JavaScript 
src="http://counter.blogchina.com/PageServlet?pageid=5270254&amp;blogid=234067"></SCRIPT>
】【2006年06月20日 星期二 22:11】【 <A 
href="javascript:void(keyit=window.open('http://blogmark.blogchina.com/jsp/key/quickaddkey.jsp?k='+encodeURI('正则表达式教程')+'&amp;u='+encodeURI('http://anniekim.blogchina.com/anniekim/5270254.html')+'&amp;c='+encodeURI(''),'keyit','scrollbars=no,width=500,height=430,status=no,resizable=yes'));keyit.focus();">加入博采</A>】【<A 
href="javascript:window.print();">打印</A>】 </TD></P></DIV><img src ="http://www.cppblog.com/nchsea/aggbug/14635.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/nchsea/" target="_blank">sea</a> 2006-11-03 20:02 <a href="http://www.cppblog.com/nchsea/archive/2006/11/03/14635.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正则表达式之道</title><link>http://www.cppblog.com/nchsea/archive/2006/11/03/14634.html</link><dc:creator>sea</dc:creator><author>sea</author><pubDate>Fri, 03 Nov 2006 11:48:00 GMT</pubDate><guid>http://www.cppblog.com/nchsea/archive/2006/11/03/14634.html</guid><wfw:comment>http://www.cppblog.com/nchsea/comments/14634.html</wfw:comment><comments>http://www.cppblog.com/nchsea/archive/2006/11/03/14634.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/nchsea/comments/commentRss/14634.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/nchsea/services/trackbacks/14634.html</trackback:ping><description><![CDATA[<CENTER>
<H1>正则表达式之道</H1></CENTER>
<CENTER>
<P>原著：Steve Mansour <BR>sman@scruznet.com <BR><FONT size=-1>Revised: June 5, 
1999<BR>(copied by jm /at/ jmason.org from 
http://www.scruz.net/%7esman/regexp.htm, after the original disappeared! ) 
</FONT></P>
<P>翻译：Neo Lee<BR>neo.lee@gmail.com<BR><FONT 
size=-1>2004年10月16日</FONT></P></CENTER>
<HR>

<P><A href="http://sitescooper.org/tao_regexps.html">英文版原文</A></P>
<P>译者按：原文因为年代久远，文中很多链接早已过期（主要是关于vi、sed等工具的介绍和手册），本译文中已将此类链接删除，如需检查这些链接可以查看上面链接的原文。除此之外基本照原文直译，括号中有“译者按”的部分是译者补充的说明。如有内容方面的问题请直接和Steve 
Mansor联系，当然，如果你只写中文，也可以和我联系。</P>
<HR>

<H1>目 录</H1>
<P><B><A 
href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#WhatAreRegularExpressions">什么是正则表达式</A></B> 
<BR><B><A 
href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#SimpleCommands">范例</A></B> 
<BR>&nbsp;&nbsp; <A 
href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#SimpleCommands">简单</A> 
<BR>&nbsp;&nbsp; <A 
href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#MediumDifficultyExamples">中级（神奇的咒语）</A> 
<BR>&nbsp;&nbsp; <A 
href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#HardExamples">困难（不可思议的象形文字）</A><BR><B><A 
href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#Regular_Expressions_In_Various_Tools">不同工具中的正则表达式</A></B> 
</P>
<P></P>
<HR width="100%">

<H1><A 
name=WhatAreRegularExpressions></A>什么是正则表达式</H1>一个正则表达式，就是用某种模式去匹配一类字符串的一个公式。很多人因为它们看上去比较古怪而且复杂所以不敢去使用——很不幸，这篇文章也不能够改变这一点，不过，经过一点点练习之后我就开始觉得这些复杂的表达式其实写起来还是相当简单的，而且，一旦你弄懂它们，你就能把数小时辛苦而且易错的文本处理工作压缩在几分钟（甚至几秒钟）内完成。正则表达式被各种文本编辑软件、类库（例如Rogue 
Wave的tools.h++）、脚本工具（像awk/grep/sed）广泛的支持，而且像Microsoft的Visual C++这种交互式IDE也开始支持它了。 

<P>我们将在如下的章节中利用一些例子来解释正则表达式的用法，绝大部分的例子是基于<B><TT>vi</TT></B>中的文本替换命令和<B><TT>grep</TT></B>文件搜索命令来书写的，不过它们都是比较典型的例子，其中的概念可以在sed、awk、perl和其他支持正则表达式的编程语言中使用。你可以看看<A 
href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#Regular_Expressions_In_Various_Tools">不同工具中的正则表达式</A>这一节，其中有一些在别的工具中使用正则表达式的例子。还有一个关于vi中文本替换命令（s）的<A 
href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#ViSubstitutionCommandSyntax">简单说明</A>附在文后供参考。</P>
<H2>正则表达式基础</H2>正则表达式由一些普通字符和一些<I>元字符（metacharacters）</I>组成。普通字符包括大小写的字母和数字，而元字符则具有特殊的含义，我们下面会给予解释。 

<P>在最简单的情况下，一个正则表达式看上去就是一个普通的查找串。例如，正则表达式"testing"中没有包含任何元字符，，它可以匹配"testing"和"123testing"等字符串，但是不能匹配"Testing"。</P>
<P>要想真正的用好正则表达式，正确的理解元字符是最重要的事情。下表列出了所有的元字符和对它们的一个简短的描述。 
<P>
<TABLE cellSpacing=2 cellPadding=2>
  <TBODY>
  <TR vAlign=baseline>
    <TH align=left><B><I>元字符</I></B></TH>
    <TD>&nbsp;</TD>
    <TH align=left><B><I>描述</I></B></TH></TR>
  <TR>
    <TD>
      <HR width="100%">
    </TD>
    <TD></TD>
    <TD>
      <HR width="100%">
    </TD></TR>
  <TR>
    <TD vAlign=top align=middle>
      <CENTER><B><TT><FONT face="Courier New"><FONT 
      size=+1>.</FONT></FONT></TT></B> </CENTER></TD>
    <TD></TD>
    <TD>匹配任何单个字符。例如正则表达式<B><TT>r.t</TT></B>匹配这些字符串：<I>rat</I>、<I>rut</I>、<I>r 
      t</I>，但是不匹配<I>root</I>。&nbsp;</TD></TR>
  <TR>
    <TD vAlign=top>
      <CENTER><B><TT><FONT face="Courier New"><FONT 
      size=+1>$</FONT></FONT></TT></B> </CENTER></TD>
    <TD></TD>
    <TD>匹配行结束符。例如正则表达式<B><TT>weasel$</TT></B> 能够匹配字符串"<I>He's a 
      weasel</I>"的末尾，但是不能匹配字符串"<I>They are a bunch of weasels.</I>"。&nbsp;</TD></TR>
  <TR>
    <TD vAlign=top>
      <CENTER><B><FONT size=+1>^</FONT></B> </CENTER></TD>
    <TD></TD>
    <TD>匹配一行的开始。例如正则表达式<B><TT>^When in</TT></B>能够匹配字符串"<I>When in the course 
      of human events</I>"的开始，但是不能匹配"<I>What and When in the"。</I></TD></TR>
  <TR>
    <TD vAlign=top>
      <CENTER><B><TT><FONT face="Courier New"><FONT 
      size=+1>*</FONT></FONT></TT></B> </CENTER></TD>
    <TD></TD>
    <TD>匹配0或多个正好在它之前的那个字符。例如正则表达式<B><TT></TT></B><B><TT>.*</TT></B>意味着能够匹配任意数量的任何字符。</TD></TR>
  <TR>
    <TD vAlign=top>
      <CENTER><B><TT><FONT face="Courier New"><FONT 
      size=+1>\</FONT></FONT></TT></B> </CENTER></TD>
    <TD></TD>
    <TD>这是引用府，用来将这里列出的这些元字符当作普通的字符来进行匹配。例如正则表达式<B><TT>\$</TT></B>被用来匹配美元符号，而不是行尾，类似的，正则表达式<TT><STRONG>\.</STRONG></TT>用来匹配点字符，而不是任何字符的通配符。</TD></TR>
  <TR>
    <TD vAlign=top>
      <CENTER><B><TT><FONT face="Courier New"><FONT size=+1>[ 
      ]&nbsp;</FONT></FONT></TT></B> <BR><B><TT><FONT face="Courier New"><FONT 
      size=+1>[c</FONT><FONT size=-1>1</FONT><FONT size=+1>-c</FONT><FONT 
      size=-1>2</FONT><FONT size=+1>]</FONT></FONT></TT></B> <BR><B><TT><FONT 
      face="Courier New"><FONT size=+1>[^c</FONT><FONT size=-1>1</FONT><FONT 
      size=+1>-c</FONT><FONT size=-1>2</FONT><FONT 
      size=+1>]</FONT></FONT></TT></B> </CENTER></TD>
    <TD></TD>
    <TD>匹配括号中的任何一个字符。例如正则表达式<B><TT>r[aou]t</TT></B>匹配<I>rat</I>、<I>rot</I>和<I>rut</I>，但是不匹配<I>ret</I>。可以在括号中使用连字符-来指定字符的区间，例如正则表达式<B><TT>[0-9]</TT></B>可以匹配任何数字字符；还可以制定多个区间，例如正则表达式<B><TT>[A-Za-z]</TT></B>可以匹配任何大小写字母。另一个重要的用法是“排除”，要想匹配<I>除了</I>指定区间之外的字符——也就是所谓的补集——在左边的括号和第一个字符之间使用^字符，例如正则表达式<B><TT>[^269A-Z]</TT></B> 
      将匹配除了2、6、9和所有大写字母之外的任何字符。</TD></TR>
  <TR>
    <TD vAlign=top>
      <CENTER><B><TT><FONT face="Courier New"><FONT size=+1>\&lt; 
      \&gt;</FONT></FONT></TT></B> </CENTER></TD>
    <TD></TD>
    <TD>匹配词（<EM>word</EM>）的开始（\&lt;）和结束（\&gt;）。例如正则表达式<B><TT><FONT 
      face="Courier New">\&lt;the</FONT></TT></B>能够匹配字符串"<I>for the 
      wise</I>"中的"the"，但是不能匹配字符串"<I>otherwise</I>"中的"the"。<STRONG>注意</STRONG>：这个元字符不是所有的软件都支持的。</TD></TR>
  <TR>
    <TD vAlign=top>
      <CENTER><B><TT><FONT face="Courier New"><FONT size=+1>\( 
      \)</FONT></FONT></TT></B> </CENTER></TD>
    <TD></TD>
    <TD>将 \( 和 \) 
      之间的表达式定义为“组”（<EM>group</EM>），并且将匹配这个表达式的字符保存到一个临时区域（一个正则表达式中最多可以保存9个），它们可以用 
      <B><TT>\1</TT></B> 到<B><TT>\9</TT></B> 的符号来引用。</TD></TR>
  <TR>
    <TD vAlign=baseline>
      <CENTER><B><TT><FONT face="Courier New"><FONT 
      size=+1>|</FONT></FONT></TT></B> </CENTER></TD>
    <TD></TD>
    <TD>将两个匹配条件进行逻辑“或”（<EM>Or</EM>）运算。例如正则表达式<B><TT><FONT 
      face="Courier New">(him|her)</FONT></TT></B> 匹配"<I>it belongs to 
      him</I>"和"<I>it belongs to her</I>"，但是不能匹配"<I>it belongs to 
      them.</I>"。<STRONG>注意</STRONG>：这个元字符不是所有的软件都支持的。</TD></TR>
  <TR vAlign=baseline>
    <TD>
      <CENTER><B><TT><FONT face="Courier New"><FONT 
      size=+1>+</FONT></FONT></TT></B> </CENTER></TD>
    <TD></TD>
    <TD>匹配1或多个正好在它之前的那个字符。例如正则表达式<B><TT></TT></B><B><TT></TT></B><B><TT>9+</TT></B>匹配9、99、999等。<STRONG>注意</STRONG>：这个元字符不是所有的软件都支持的。</TD></TR>
  <TR vAlign=baseline>
    <TD>
      <CENTER><B><TT><FONT size=+1>?</FONT></TT></B> </CENTER></TD>
    <TD></TD>
    <TD>匹配0或1个正好在它之前的那个字符。<STRONG>注意</STRONG>：这个元字符不是所有的软件都支持的。</TD></TR>
  <TR vAlign=baseline>
    <TD>
      <CENTER><B><FONT size=+1><TT><FONT 
      face="Courier New">\{</FONT></TT><I>i</I><TT><FONT 
      face="Courier New">\}</FONT></TT></FONT></B> <BR><B><FONT 
      size=+1><TT><FONT face="Courier New">\{</FONT></TT><I>i</I><TT><FONT 
      face="Courier New">,</FONT></TT><I>j</I><TT><FONT 
      face="Courier New">\}</FONT></TT></FONT></B> </CENTER></TD>
    <TD></TD>
    <TD vAlign=baseline>匹配指定数目的字符，这些字符是在它之前的表达式定义的。例如正则表达式<B><TT><FONT 
      face="Courier New">A[0-9]\{3\}</FONT></TT></B> 
      能够匹配字符"A"后面跟着正好3个数字字符的串，例如A123、A348等，但是不匹配A1234。而正则表达式<B><TT><FONT 
      face="Courier New">[0-9]\{4,6\}</FONT></TT></B> 
      匹配连续的任意4个、5个或者6个数字字符。<STRONG>注意</STRONG>：这个元字符不是所有的软件都支持的。</TD></TR></TBODY></TABLE></P>
<P></P>
<HR width="100%">

<P>最简单的元字符是点，它能够匹配任何单个字符（注意<STRONG>不</STRONG>包括新行符）。假定有个文件test.txt包含以下几行内容：</P>
<UL><TT>he is a rat</TT><BR><TT>he is in a rut</TT><BR><TT>the food is 
  Rotten</TT><BR><TT>I like root beer</TT> 
</UL>我们可以使用grep命令来测试我们的正则表达式，grep命令使用正则表达式去尝试匹配指定文件的每一行，并将至少有一处匹配表达式的所有行显示出来。命令 
<UL><TT>grep r.t test.txt</TT> 
</UL>在test.txt文件中的每一行中搜索正则表达式<B><TT>r.t</TT></B>，并打印输出匹配的行。正则表达式<B><TT>r.t</TT></B>匹配一个<B><TT>r</TT></B>接着任何一个字符再接着一个<B><TT>t</TT></B>。所以它将匹配文件中的<B><TT>rat</TT></B>和<B><TT>rut</TT></B>，而不能匹配<B><TT>Rotten</TT></B>中的<B><TT>Rot</TT></B>，因为正则表达式是大小写敏感的。要想同时匹配大写和小写字母，应该使用字符区间元字符（方括号）。正则表达式<B><TT>[Rr]</TT></B>能够同时匹配<B><TT>R</TT></B>和<B><TT>r</TT></B>。所以，要想匹配一个大写或者小写的<B><TT>r</TT></B>接着任何一个字符再接着一个<B><TT>t</TT></B>就要使用这个表达式：<B><TT>[Rr].t</TT></B>。 

<P>要想匹配行首的字符要使用抑扬字符（<EM>^</EM>）——又是也被叫做插入符。例如，想找到text.txt中行首"he"打头的行，你可能会先用简单表达式<B><TT>he</TT></B>，但是这会匹配第三行的<B><TT>the</TT></B>，所以要使用正则表达式<B><TT>^he</TT></B>，它只匹配在行首出现的<B><TT>h</TT></B>。 
</P>
<P>有时候指定“除了×××都匹配”会比较容易达到目的，当抑扬字符（<EM>^</EM>）出现在方括号中是，它表示“排除”，例如要匹配<B><TT>he</TT></B> 
，但是排除前面是<B><TT>t</TT></B> or 
<B><TT>s</TT></B>的情性（也就是<B><TT>the</TT></B>和<B><TT>s</TT></B><B><TT>he</TT></B>），可以使用：<B><TT>[^st]he</TT></B>。 
</P>
<P>可以使用方括号来指定多个字符区间。例如正则表达式<B><TT>[A-Za-z]</TT></B>匹配任何字母，包括大写和小写的；正则表达式<B><TT>[A-Za-z][A-Za-z]*</TT></B> 
匹配一个字母后面接着0或者多个字母（大写或者小写）。当然我们也可以用元字符<B><TT>+</TT></B>做到同样的事情，也就是：<B><TT>[A-Za-z]+</TT></B> 
，和<B><TT>[A-Za-z][A-Za-z]*</TT></B>完全等价。但是要注意元字符<B><TT>+</TT></B> 
并不是所有支持正则表达式的程序都支持的。关于这一点可以参考后面的<A 
href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#Regular%20Expressions%20Syntax">正则表达式语法支持情况</A>。</P>
<P>要指定特定数量的匹配，要使用大括号（注意必须使用反斜杠来转义）。想匹配所有<B><TT>100</TT></B>和<B><TT>1000</TT></B>的实例而排除<B><TT>10</TT></B>和<B><TT>10000</TT></B>，可以使用：<B><TT>10\{2,3\}</TT></B>，这个正则表达式匹配数字1后面跟着2或者3个0的模式。在这个元字符的使用中一个有用的变化是忽略第二个数字，例如正则表达式<B><TT>0\{3,\}</TT></B> 
将匹配至少3个连续的0。</P>
<H2><A name=SimpleCommands></A>简单的例子</H2>
<P>这里有一些有代表性的、比较简单的例子。 
<P>
<TABLE cellSpacing=2 cellPadding=2>
  <TBODY>
  <TR>
    <TD><B><I>vi 命令</I></B></TD>
    <TD><B><I>作用</I></B></TD></TR>
  <TR>
    <TD>
      <HR width="100%">
    </TD>
    <TD>
      <HR width="100%">
    </TD></TR>
  <TR>
    <TD><B><TT><FONT face="Courier New"><FONT size=+1>:%s/ */ 
      /g</FONT></FONT></TT></B></TD>
    <TD>把一个或者多个空格替换为一个空格。</TD></TR>
  <TR>
    <TD><B><TT><FONT face="Courier New"><FONT size=+1>:%s/ 
      *$//</FONT></FONT></TT></B></TD>
    <TD>去掉行尾的所有空格。</TD></TR>
  <TR>
    <TD><B><TT><FONT face="Courier New"><FONT size=+1>:%s/^/ 
      /</FONT></FONT></TT></B></TD>
    <TD>在每一行头上加入一个空格。</TD></TR>
  <TR>
    <TD><B><TT><FONT face="Courier New"><FONT size=+1>:%s/^[0-9][0-9]* 
      //</FONT></FONT></TT></B></TD>
    <TD>去掉行首的所有数字字符。</TD></TR>
  <TR>
    <TD><B><TT><FONT face="Courier New"><FONT 
      size=+1>:%s/b[aeio]g/bug/g</FONT></FONT></TT></B></TD>
    <TD>将所有的<I>bag</I>、<I>beg</I>、<I>big</I>和<I>bog</I>改为<I>bug</I>。&nbsp;</TD></TR>
  <TR>
    <TD><B><TT><FONT face="Courier New"><FONT 
      size=+1>:%s/t\([aou]\)g/h\1t/g</FONT></FONT></TT></B></TD>
    <TD>将所有<I>tag</I>、<I>tog</I>和<I>tug</I>分别改为<I>hat</I>、<I>hot</I>和<I>hug</I>（注意用group的用法和使用\1引用前面被匹配的字符）。</TD></TR>
  <TR>
    <TD></TD>
    <TD></TD></TR></TBODY></TABLE>
<H2><A name=MediumDifficultyExamples></A>中级的例子（神奇的咒语）</H2>
<H3>例1</H3>
<P>将所有方法foo(<I>a,b,c</I>)的实例改为foo(<I>b,a,c</I>)。这里a、b和c可以是任何提供给方法foo()的参数。也就是说我们要实现这样的转换： 

<P>
<TABLE cellSpacing=4 cellPadding=0>
  <TBODY>
  <TR>
    <TD><B>之前</B></TD>
    <TD>&nbsp;</TD>
    <TD><B>之后</B></TD></TR>
  <TR>
    <TD><TT>foo(10,7,2)</TT></TD>
    <TD></TD>
    <TD><TT>foo(7,10,2)</TT></TD></TR>
  <TR>
    <TD><TT>foo(x+13,y-2,10)</TT></TD>
    <TD></TD>
    <TD><TT>foo(y-2,x+13,10)</TT></TD></TR>
  <TR>
    <TD><TT>foo( bar(8), x+y+z, 5)</TT></TD>
    <TD></TD>
    <TD><TT>foo( x+y+z, bar(8), 5)</TT></TD></TR></TBODY></TABLE>
<P>下面这条替换命令能够实现这一魔法：</P>
<UL><B><TT><FONT 
  face="Courier New">:%s/foo(\([^,]*\),\([^,]*\),\([^)]*\))/foo(\2,\1,\3)/g</FONT></TT></B> 
</UL>
<P>现在让我们把它打散来加以分析。写出这个表达式的基本思路是找出foo()和它的括号中的三个参数的位置。第一个参数是用这个表达式来识别的：：<B><TT><FONT 
face="Courier New">\([^,]*\)</FONT></TT></B>，我们可以从里向外来分析它：&nbsp; 
<P>
<TABLE>
  <TBODY>
  <TR>
    <TD><B><TT><FONT face="Courier New">[^,]</FONT></TT></B></TD>
    <TD>&nbsp;</TD>
    <TD>除了逗号之外的任何字符</TD></TR>
  <TR>
    <TD><B><TT><FONT face="Courier New">[^,]*</FONT></TT></B></TD>
    <TD></TD>
    <TD>0或者多个非逗号字符</TD></TR>
  <TR>
    <TD><B><TT><FONT face="Courier New">\([^,]*\)</FONT></TT></B></TD>
    <TD></TD>
    <TD>将这些非逗号字符标记为<B><TT>\1</TT></B>，这样可以在之后的替换模式表达式中引用它</TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT><FONT face="Courier New">\([^,]*\),</FONT></TT></B></TD>
    <TD></TD>
    <TD>我们必须找到0或者多个非逗号字符后面跟着一个逗号，并且非逗号字符那部分要标记出来以备后用。</TD></TR></TBODY></TABLE>
<P>现在正是指出一个使用正则表达式常见错误的最佳时机。为什么我们要使用<B><TT><FONT 
face="Courier New">[^,]*</FONT></TT></B>这样的一个表达式，而不是更加简单直接的写法，例如：<B><TT><FONT 
face="Courier New">.*</FONT></TT></B>，来匹配第一个参数呢？设想我们使用模式<B><TT><FONT 
face="Courier New">.*</FONT></TT></B>来匹配字符串"10,7,2"，它应该匹配"10,"还是"10,7,"？为了解决这个两义性（ambiguity），正则表达式规定一律按照最长的串来，在上面的例子中就是"10,7,"，显然这样就找出了两个参数而不是我们期望的一个。所以，我们要使用<B><TT><FONT 
face="Courier New">[^,]*</FONT></TT></B>来强制取出第一个逗号之前的部分。</P>
<P>这个表达式我们已经分析到了：<B><TT><FONT 
face="Courier New">foo(\([^,]*\)</FONT></TT></B>，这一段可以简单的翻译为“当你找到<B><TT>foo(</TT></B>就把其后直到第一个逗号之前的部分标记为<B><TT><FONT 
face="Courier New">\1</FONT></TT></B>”。然后我们使用同样的办法标记第二个参数为<B><TT><FONT 
face="Courier New">\2</FONT></TT></B>。对第三个参数的标记方法也是一样，只是我们要搜索所有的字符直到右括号。我们并没有必要去搜索第三个参数，因为我们不需要调整它的位置，但是这样的模式能够保证我们只去替换那些有三个参数的foo()方法调用，在foo()是一个重载（overoading）方法时这种明确的模式往往是比较保险的。然后，在替换部分，我们找到foo()的对应实例，然后利用标记好的部分进行替换，是的第一和第二个参数交换位置。</P>
<H3>例2</H3>假设有一个CSV（comma separated 
value）文件，里面有一些我们需要的信息，但是格式却有问题，目前数据的列顺序是：姓名，公司名，州名缩写，邮政编码，现在我们希望讲这些数据重新组织，以便在我们的某个软件中使用，需要的格式为：姓名，州名缩写-邮政编码，公司名。也就是说，我们要调整列顺序，还要合并两个列来构成一个新列。另外，我们的软件不能接受逗号前后面有任何空格（包括空格和制表符）所以我们还必须要去掉逗号前后的所有空格。 

<P>这里有几行我们现在的数据：</P>
<UL><TT>Bill Jones,&nbsp;&nbsp;&nbsp;&nbsp; HI-TEK Corporation ,&nbsp; CA, 
  95011</TT> <BR><TT><FONT face="Courier New">Sharon Lee Smith,&nbsp; Design 
  Works Incorporated,&nbsp; CA, 95012</FONT></TT> <BR><TT><FONT 
  face="Courier New">B. Amos&nbsp;&nbsp; ,&nbsp; Hill Street Cafe,&nbsp; CA, 
  95013</FONT></TT> <BR><TT><FONT face="Courier New">Alexander 
  Weatherworth,&nbsp; The Crafts Store,&nbsp; CA, 95014</FONT></TT> 
  <BR><TT><FONT face="Courier New">...</FONT></TT> </UL>我们希望把它变成这个样子： 
<UL><TT>Bill Jones,CA 95011,HI-TEK Corporation</TT> <BR><TT><FONT 
  face="Courier New">Sharon Lee Smith,CA 95012,Design Works 
  Incorporated</FONT></TT> <BR><TT><FONT face="Courier New">B. Amos,CA 
  95013,Hill Street Cafe</FONT></TT> <BR><TT><FONT face="Courier New">Alexander 
  Weatherworth,CA 95014,The Crafts Store</FONT></TT> <BR><TT><FONT 
  face="Courier New">...</FONT></TT> </UL>我们将用两个正则表达式来解决这个问题。第一个移动列和合并列，第二个用来去掉空格。 

<P>下面就是第一个替换命令：</P>
<UL><B><TT><FONT 
  face="Courier New">:%s/\([^,]*\),\([^,]*\),\([^,]*\),\(.*\)/\1,\3 
  \4,\2/</FONT></TT></B> </UL>这里的方法跟例1基本一样，第一个列（姓名）用这个表达式来匹配：<B><TT><FONT 
face="Courier New">\([^,]*\)</FONT></TT></B>，即第一个逗号之前的所有字符，而姓名内容被用<B><TT><FONT 
face="Courier New">\1</FONT></TT></B>标记下来。公司名和州名缩写字段用同样的方法标记为<B><TT><FONT 
face="Courier New">\2</FONT></TT></B>和<B><TT><FONT 
face="Courier New">\3</FONT></TT></B>，而最后一个字段用<B><TT><FONT 
face="Courier New">\(.*\)</FONT></TT></B>来匹配（"匹配所有字符直到行末"）。替换部分则引用上面标记的那些内容来进行构造。 

<P>下面这个替换命令则用来去除空格：</P>
<UL><B><TT><FONT face="Courier New">:%s/[ \t]*,[ \t]*/,/g</FONT></TT></B> 
</UL>我们还是分解来看：<B><TT><FONT face="Courier New">[ 
\t]</FONT></TT></B>匹配空格/制表符，<B><TT><FONT face="Courier New">[ 
\t]*</FONT></TT></B> 匹配0或多个空格/制表符，<B><TT>[ 
\t]*</TT></B>,匹配0或多个空格/制表符后面再加一个逗号，最后，<B><TT><FONT face="Courier New">[ \t]*,[ 
\t]*</FONT></TT></B>匹配0或多个空格/制表符接着一个逗号再接着0或多个空格/制表符。在替换部分，我们简单的我们找到的所有东西替换成一个逗号。这里我们使用了结尾的可选的<B><TT>g</TT></B>参数，这表示在每行中对所有匹配的串执行替换（而不是缺省的只替换第一个匹配串）。 

<H3>例3</H3>假设有一个多字符的片断重复出现，例如： 
<BLOCKQUOTE><TT>Billy tried really hard</TT> <BR><TT>Sally tried really really 
  hard</TT> <BR><TT>Timmy tried really really really hard</TT> <BR><TT>Johnny 
  tried really really really really hard</TT></BLOCKQUOTE>而你想把"really"、"really 
really"，以及任意数量连续出现的"really"字符串换成一个简单的"very"（simple is good!），那么以下命令： 
<BLOCKQUOTE><B><TT>:%s/\(really \)\(really \)*/very 
/</TT></B></BLOCKQUOTE>就会把上述的文本变成： 
<BLOCKQUOTE><TT>Billy tried very hard</TT> <BR><TT>Sally tried very hard</TT> 
  <BR><TT>Timmy tried very hard</TT> <BR><TT>Johnny tried very 
hard</TT></BLOCKQUOTE>表达式<B><TT>\(really \)*</TT></B>匹配0或多个连续的"really 
"（注意结尾有个空格），而<B><TT>\(really \)\(really \)*</TT></B> 匹配1个或多个连续的"really "实例。 
<H2><A name=HardExamples></A>困难的例子（不可思议的象形文字）</H2><I>Coming soon</I>. 
<P></P>
<HR>

<H1><A 
name=Regular_Expressions_In_Various_Tools></A>不同工具中的正则表达式</H1>OK，你已经准备使用RE（regular 
expressions，正则表达式），但是你并准备使用vi。所以，在这里我们给出一些在其他工具中使用RE的例子。另外，我还会总结一下你在不同程序之间使用RE可能发现的区别。 

<P>当然，你也可以在Visual C++编辑器中使用RE。选择Edit-&gt;Replace，然后选择"Regular 
expression"选择框，Find 
What输入框对应上面介绍的vi命令<B><TT>:%s/pat1/pat2/g</TT></B>中的pat1部分，而Replace输入框对应pat2部分。但是，为了得到vi的执行范围和<B><TT>g</TT></B>选项，你要使用Replace 
All或者适当的手工Find Next and 
Replace（译者按：知道为啥有人骂微软弱智了吧，虽然VC中可以选中一个范围的文本，然后在其中执行替换，但是总之不够vi那么灵活和典雅）。</P>
<H2>sed</H2>
<P>Sed是<B><U>S</U></B>tream 
<B><U>ED</U></B>itor的缩写，是Unix下常用的基于文件和管道的编辑工具，可以在手册中得到关于sed的详细信息。 </P>
<P>这里是一些有趣的sed脚本，假定我们正在处理一个叫做price.txt的文件。注意这些编辑并不会改变源文件，sed只是处理源文件的每一行并把结果显示在标准输出中（当然很容易使用重定向来定制）： 

<P>
<TABLE>
  <TBODY>
  <TR>
    <TD><B><I>sed脚本</I></B></TD>
    <TD>&nbsp;</TD>
    <TD><B><I>描述</I></B></TD></TR>
  <TR>
    <TD>
      <HR width="100%">
    </TD>
    <TD></TD>
    <TD>
      <HR width="100%">
    </TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT>sed 's/^$/d' price.txt</TT></B></TD>
    <TD></TD>
    <TD>删除所有空行</TD></TR>
  <TR>
    <TD><B><TT>sed 's/^[ \t]*$/d' price.txt</TT></B></TD>
    <TD></TD>
    <TD>删除所有只包含空格或者制表符的行</TD></TR>
  <TR>
    <TD><B><TT>sed 's/"//g' price.txt</TT></B></TD>
    <TD></TD>
    <TD>删除所有引号</TD></TR></TBODY></TABLE></P>
<H2>awk</H2>awk是一种编程语言，可以用来对文本数据进行复杂的分析和处理。可以在手册中得到关于awk的详细信息。这个古怪的名字是它作者们的姓的缩写（Aho，Weinberger和Kernighan）。 

<P>在Aho，Weinberger和Kernighan的书<U>The AWK Programming 
Language</U>中有很多很好的awk的例子，请不要让下面这些微不足道的脚本例子限制你对awk强大能力的理解。我们同样假定我们针对price.txt文件进行处理，跟sed一样，awk也只是把结果显示在终端上。&nbsp; 

<P>
<TABLE>
  <TBODY>
  <TR>
    <TD><B><I>awk脚本</I></B></TD>
    <TD>&nbsp;</TD>
    <TD><B><I>描述</I></B></TD></TR>
  <TR>
    <TD>
      <HR width="100%">
    </TD>
    <TD></TD>
    <TD>
      <HR width="100%">
    </TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT>awk '$0 !~ /^$/' price.txt</TT></B></TD>
    <TD></TD>
    <TD>删除所有空行</TD></TR>
  <TR>
    <TD><B><TT>awk 'NF &gt; 0' price.txt</TT></B></TD>
    <TD></TD>
    <TD>awk中一个更好的删除所有行的办法</TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT>awk '$2 ~ /^[JT]/ {print $3}' price.txt</TT></B></TD>
    <TD></TD>
    <TD>打印所有第二个字段是'J'或者'T'打头的行中的第三个字段</TD></TR>
  <TR vAlign=baseline>
    <TD noWrap><B><TT>awk '$2 !~ /[Mm]isc/ {print $3 + $4}' 
    price.txt</TT></B></TD>
    <TD></TD>
    <TD>针对所有第二个字段不包含'Misc'或者'misc'的行，打印第3和第4列的和（假定为数字）</TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT>awk '$3 !~ /^[0-9]+\.[0-9]*$/ {print $0}' price.txt</TT></B></TD>
    <TD></TD>
    <TD>打印所有第三个字段不是数字的行，这里数字是指<TT>d.d</TT>或者<TT>d这样的形式，其中</TT><TT>d</TT>是0到9的任何数字</TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT>awk '$2 ~ /John|Fred/ {print $0}' price.txt</TT></B></TD>
    <TD></TD>
    <TD>如果第二个字段包含'John'或者'Fred'则打印整行</TD></TR></TBODY></TABLE></P>
<H2>grep</H2>grep是一个用来在一个或者多个文件或者输入流中使用RE进行查找的程序。它的name编程语言可以用来针对文件和管道进行处理。可以在手册中得到关于grep的完整信息。这个同样古怪的名字来源于vi的一个命令，<B><TT>g/</TT></B><I>re</I><B><TT>/p</TT></B>，意思是<B>g</B>lobal 
<B>r</B>egular <B>e</B>xpression <B>p</B>rint。 
<P>下面的例子中我们假定在文件phone.txt中包含以下的文本，——其格式是姓加一个逗号，然后是名，然后是一个制表符，然后是电话号码：</P>
<UL>
  <P><TT>Francis, 
  John&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5-3871</TT> 
  <BR><TT>Wong, 
  Fred&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  4-4123</TT> <BR><TT>Jones, 
  Thomas&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1-4122</TT> 
  <BR><TT>Salazar, Richard&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  5-2522</TT></P></UL>
<P>
<TABLE>
  <TBODY>
  <TR>
    <TD><B><I>grep命令</I></B></TD>
    <TD><B><I>&nbsp;</I></B></TD>
    <TD><B><I>描述</I></B></TD></TR>
  <TR>
    <TD>
      <HR width="100%">
    </TD>
    <TD></TD>
    <TD>
      <HR width="100%">
    </TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT>grep '\t5-...1' phone.txt</TT></B></TD>
    <TD></TD>
    <TD>把所有电话号码以5开头以1结束的行打印出来，注意制表符是用<B><TT>\t</TT></B>表示的</TD></TR>
  <TR vAlign=baseline>
    <TD noWrap><B><TT>grep '^S[^ ]* R' phone.txt</TT></B></TD>
    <TD></TD>
    <TD>打印所有姓以S打头和名以R打头的行</TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT>grep '^[JW]' phone.txt</TT></B></TD>
    <TD></TD>
    <TD>打印所有姓开头是J或者W的行</TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT>grep ', ....\t' phone.txt</TT></B></TD>
    <TD></TD>
    <TD>打印所有姓是4个字符的行，注意制表符是用<B><TT>\t</TT></B>表示的</TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT>grep -v '^[JW]' phone.txt</TT></B></TD>
    <TD></TD>
    <TD>打印所有不以J或者W开头的行</TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT>grep '^[M-Z]' phone.txt</TT></B></TD>
    <TD></TD>
    <TD>打印所有姓的开头是M到Z之间任一字符的行</TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT>grep '^[M-Z].*[12]' phone.txt</TT></B></TD>
    <TD></TD>
    <TD>打印所有姓的开头是M到Z之间任一字符，并且点号号码结尾是1或者2的行</TD></TR></TBODY></TABLE>
<H2>egrep</H2>egrep是grep的一个扩展版本，它在它的正则表达式中支持更多的元字符。下面的例子中我们假定在文件phone.txt中包含以下的文本，——其格式是姓加一个逗号，然后是名，然后是一个制表符，然后是电话号码： 

<UL><TT>Francis, 
  John&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5-3871</TT> 
  <BR><TT>Wong, 
  Fred&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  4-4123</TT> <BR><TT>Jones, 
  Thomas&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1-4122</TT> 
  <BR><TT>Salazar, Richard&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5-2522</TT> 
</UL>
<P>
<TABLE>
  <TBODY>
  <TR>
    <TD><B><I>egrep command</I></B></TD>
    <TD><B><I>&nbsp;</I></B></TD>
    <TD><B><I>Description</I></B></TD></TR>
  <TR>
    <TD>
      <HR width="100%">
    </TD>
    <TD></TD>
    <TD>
      <HR width="100%">
    </TD></TR>
  <TR vAlign=baseline>
    <TD><B><TT>egrep '(John|Fred)' phone.txt</TT></B></TD>
    <TD></TD>
    <TD>打印所有包含名字<I>John</I>或者<I>Fred</I>的行</TD></TR>
  <TR vAlign=baseline>
    <TD noWrap><B><TT>egrep 'John|22$|^W' phone.txt</TT></B></TD>
    <TD></TD>
    <TD>打印所有包含<I>John</I> 或者以22结束或者以<I>W</I>的行</TD></TR>
  <TR>
    <TD><B><TT>egrep 'net(work)?s' report.txt</TT></B></TD>
    <TD></TD>
    <TD>从report.txt中找到所有包含<I>networks</I>或者<I>nets</I>的行</TD></TR></TBODY></TABLE>
<H2>
<HR width="100%">
</H2>
<H1><A name="Regular Expressions Syntax"></A>正则表达式语法支持情况</H1>
<TABLE cellSpacing=0 border=1>
  <TBODY>
  <TR>
    <TD><B>命令或环境</B></TD>
    <TD><B><TT><FONT face="Courier New">.</FONT></TT></B></TD>
    <TD><B><TT><FONT face="Courier New">[ ]</FONT></TT></B></TD>
    <TD><B><TT><FONT face="Courier New">^</FONT></TT></B></TD>
    <TD><B><TT><FONT face="Courier New">$</FONT></TT></B></TD>
    <TD><B><TT><FONT face="Courier New">\( \)</FONT></TT></B></TD>
    <TD><B><TT><FONT face="Courier New">\{ \}</FONT></TT></B></TD>
    <TD><B><TT><FONT face="Courier New">?</FONT></TT></B></TD>
    <TD><B><TT><FONT face="Courier New">+</FONT></TT></B></TD>
    <TD><B><TT><FONT face="Courier New">|</FONT></TT></B></TD>
    <TD><B><TT><FONT face="Courier New">( )</FONT></TT></B></TD></TR>
  <TR>
    <TD>vi</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD></TR>
  <TR>
    <TD>Visual C++</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD></TR>
  <TR>
    <TD>awk</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD></TR>
  <TR>
    <TD>sed</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD></TR>
  <TR>
    <TD>Tcl</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD></TR>
  <TR>
    <TD>ex</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD></TR>
  <TR>
    <TD>grep</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD></TR>
  <TR>
    <TD>egrep</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD></TR>
  <TR>
    <TD>fgrep</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;X&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD></TR>
  <TR>
    <TD>perl</TD>
    <TD>&nbsp;X</TD>
    <TD>&nbsp;X</TD>
    <TD>&nbsp;X</TD>
    <TD>&nbsp;X</TD>
    <TD>&nbsp;X</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;X</TD>
    <TD>&nbsp;X</TD>
    <TD>&nbsp;X</TD>
    <TD>&nbsp;X</TD></TR></TBODY></TABLE>
<P>&nbsp;</P>
<HR>

<H1><A name=ViSubstitutionCommandSyntax></A>vi替换命令简介</H1>Vi的替换命令： 
<UL><B><TT>:</TT></B><I>range</I><B><TT>s/</TT></B><I>pat1</I><B><TT>/</TT></B><I>pat2</I><B><TT>/g</TT></B> 
</UL>其中 
<UL><B><TT>:</TT></B> 这是Vi的命令执行界面。 </UL>
<UL><I>range 
  </I>是命令执行范围的指定，可以使用百分号（%）表示所有行，使用点（.）表示当前行，使用美元符号（$）表示最后一行。你还可以使用行号，例如<B><TT>10,20</TT></B>表示第10到20行，<B><TT>.,$</TT></B>表示当前行到最后一行，<B><TT>.+2,$-5</TT></B>表示当前行后两行直到全文的倒数第五行，等等。 

  <P><B><TT>s</TT></B> 表示其后是一个替换命令。</P>
  <P><I>pat1 </I>这是要查找的一个正则表达式，这篇文章中有一大堆例子。</P></UL>
<UL><I>pat2 </I>这是希望把匹配串变成的模式的正则表达式，这篇文章中有一大堆例子。 
  <P><B><TT>g</TT></B> 
可选标志，带这个标志表示替换将针对行中每个匹配的串进行，否则则只替换行中第一个匹配串。</P></UL>网上有很多vi的在线手册，你可以访问他们以获得更加完整的信息。 

<P></P>
<HR width="100%">

<CENTER>
<P><A 
href="http://matrix.foresee.cn/blogs/neo/">[回到主页]</A></P></CENTER><img src ="http://www.cppblog.com/nchsea/aggbug/14634.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/nchsea/" target="_blank">sea</a> 2006-11-03 19:48 <a href="http://www.cppblog.com/nchsea/archive/2006/11/03/14634.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>揭开正则表达式的神秘面纱--------转</title><link>http://www.cppblog.com/nchsea/archive/2006/11/03/14633.html</link><dc:creator>sea</dc:creator><author>sea</author><pubDate>Fri, 03 Nov 2006 11:42:00 GMT</pubDate><guid>http://www.cppblog.com/nchsea/archive/2006/11/03/14633.html</guid><wfw:comment>http://www.cppblog.com/nchsea/comments/14633.html</wfw:comment><comments>http://www.cppblog.com/nchsea/archive/2006/11/03/14633.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/nchsea/comments/commentRss/14633.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/nchsea/services/trackbacks/14633.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;反馈&nbsp;|&nbsp;关于&nbsp;                                                                                                                                                     ...&nbsp;&nbsp;<a href='http://www.cppblog.com/nchsea/archive/2006/11/03/14633.html'>阅读全文</a><img src ="http://www.cppblog.com/nchsea/aggbug/14633.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/nchsea/" target="_blank">sea</a> 2006-11-03 19:42 <a href="http://www.cppblog.com/nchsea/archive/2006/11/03/14633.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>