C#正则表达式

正则表达式语言可以识别各种字符模式。.NET中的正则表达式基于Perl 5的正则表达式,并支持搜索和替换功能。

所有的正则表达式相关类型都定义在System.Text.RegularExpressions命名空间中。

正则表达式基础

量词符号是正则表达式最常用的运算符之一。?表示匹配运算发前的项目0次或者1次。例如,正则表达式"colou? r"即可以匹配color也可以匹配colour,但不能匹配colouur

Console.WriteLine(Regex.Match("color", @"colo?r").Success); //True
Console.WriteLine(Regex.Match("colour", @"colou?r").Success); //True
Console.WriteLine(Regex.Match("colouur", @"colou?r").Success); //False

Regex.Match方法可以在一个大型字符串内进行搜索。其返回的对象的属性既包含了匹配部分所在的Index(位置)和Length(长度),还包含了具体的匹配值Value

Match m = Regex.Match("something you have to do?", @"you?");
Console.WriteLine(m.Success); //True
Console.WriteLine(m.Index); //10
Console.WriteLine(m.Length); //3
Console.WriteLine(m.Value); //you
Console.WriteLine(m.ToString()); //you

Regex.Match就像是string类型的IndexOf方法的增强版本。只不过前者搜索的是一种模式,而不是普通的字面量。

IsMatch方法相当于先调用Match方法,再测试其返回值的Success属性。

默认情况下,正则表达式引擎将按照从左到右的顺序对字符串进行匹配。因此它总会返回左起第一个匹配值。如需返回更多的匹配值,请调用NextMatch方法:

Match m1 = Regex.Match("One color? There are two colours in my head!", @"colou?rs?");
Match m2 = m1.NextMatch();
Console.WriteLine(m1); //color
Console.WriteLine(m2); //colours

Matches方法则会返回一个包含所有匹配值的数组。因此上例可写为:

foreach (Match m in Regex.Matches("One color? There are two colours in my head!", @"colou?rs?"))
{
    Console.WriteLine(m);
}

另一个常见的正则表达式运算符是替换运算符(alternator),用一个竖线表示:|。替换运算符代表了一种替代关系。例如,以下语句可以匹配“Jen”、“Jenny”和“Jennifer”

Console.WriteLine(Regex.IsMatch("Jenny", @"Jen(ny|nifer)?")); //True
Console.WriteLine(Regex.IsMatch("Jennifer", @"Jen(ny|nifer)?")); //True

从.NET Framework 4.5开始,正则表达式支持在匹配操作中指定超时时间。如果匹配操作超出了指定的时间间隔(TimeSpan)就会抛出RegexMatch-TimeoutException。如果应用程序需要处理任意的正则表达式(例如,在高级搜索对话框中)则务必使用该参数以防止一些恶意的正则表达式导致的无限计算。

编译正则表达式

实例化Regex对象,指定模式与RegexOptions.Compiled选项,调用该对象的实例方法进行匹配:

Regex r = new Regex(@"sausages?", RegexOptions.Compiled);
Console.WriteLine(r.Match("sausage")); //sausage
Console.WriteLine(r.Match("sausages")); //sausages

RegexOptions.Compiled选项将会使Regex实例通过轻量级的代码生成器(Re-flection.Emit命名空间下的DynamicMethod)动态地构建并编译针对特定正则表达式的代码。这种方式能提高匹配速度,但是需要额外的编译开销。

RegexOptions属性

RegexOptions枚举可以控制正则表达式匹配的行为。一个常见用法是在匹配中忽略大小写:

Console.WriteLine(Regex.Match("a", "A", RegexOptions.IgnoreCase)); // a

上述程序会在匹配中使用当前文化的大小写比较规则。如需使用不变文化,则应指定CultureInvariant标记:

Console.WriteLine(Regex.Match("a", "A", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant));

大多数RegexOptions标志也可以在正则表达式内使用单字母代码激活。例如:

Console.WriteLine(Regex.Match("a", @"(?i)A")); //a

在使用完毕后,也可以通过另一个表达式(-i)来关闭该选项,例如:

Console.WriteLine(Regex.Match("AAAa", @"(?i)a(?-i)a")); //Aa
Console.WriteLine(Regex.Match("AAAa", @"(?i)a(?i)a")); //AA

另一个常用的选项是IgnorePatternWhitespace或者(? x)。该选项允许在正则表达式中添加空白字符增强其可读性。如果不使用该选项,则表达式中的空白字符就会作为字面量。

常用RegexOptions的值及对象选项字母

C#正则表达式

字符转义

正则表达式有以下几种元字符,这些元字符不会作为字面量来处理,它们具有特殊的含义:

· \ * + ? | { [ () ^ $ . #

如果需要使用这些元字符的字面量,则需要在之前添加反斜线字符。

比如:

Console.WriteLine(Regex.Match("what?", @"what\?")); //what?

RegexEscape方法可以将包含元字符的字符串替换为转义形式,Unescape方法则正好相反。例如:

Console.WriteLine(Regex.Escape(@"?")); //\?
Console.WriteLine(Regex.Unescape(@"\?"));// ?

字符集合

正则表达式中的字符集合是一系列的通配符.

C#正则表达式

若要匹配集合中的一个字符,则需要将这些字符放在方括号中:

Console.WriteLine(Regex.Matches("That is that.", @"[Tt]hat").Count); //2

如果要匹配集合之外的字符,则需要将方括号内第一个字符前添加^符号:

Console.WriteLine(Regex.Match("quiz qwerty", @"q[^aeui]").Index); //5
Console.WriteLine(Regex.Match("quiz qwerty", @"q[^uw]").Success); //False

可以使用连字符定义一个字符范围。例如,以下正则表达式匹配了国际象棋棋子的移动规则:

Console.WriteLine(Regex.Match("b1-c4",@"[a-h]\d-[a-h]\d").Success);
  • \d表示一个十进制数字,因此\d匹配任意数字。
  • \D匹配非数字字符。\w匹配一个单词字符。包括字母、数字、下划线。
  • \W匹配任何非单词字符。该规则同时适用于非英文字符,例如西里尔字母(Cyrillic)。
  • .匹配\n之外的任意的字符(它可以匹配\r)。
  • \p匹配指定类型的字符。例如{Lu}匹配大写字母,或者{P}匹配标点符号。
Console.WriteLine(Regex.Match("Yes, please", @"\p{P}")); //,

量词符号

量词符号匹配特定次数的项目。

C#正则表达式

*可以对出现零次或者多次的字符和组进行匹配.

Console.WriteLine(Regex.Match("cv15.doc", @"cv\d*\.doc")); //cv15.doc
Console.WriteLine(Regex.Match("cv1.doc", @"cv\d*\.doc")); //cv1.doc
Console.WriteLine(Regex.Match("cv150.doc", @"cv\d*\.doc")); //cv150.doc

量词符号+可以对出现一次到多次的字符和组进行匹配。例如:

Console.WriteLine(Regex.Matches("helllo, chinese new year!", @"hel+\w").Count); //1

量词符号{}则匹配特定的次数或者次数范围。例如,以下正则表达式匹配数值:

Regex bp = new Regex(@"\d{2,3}/\d{2,3}");
Console.WriteLine(bp.Match("It used to be 160/110")); //160/110
Console.WriteLine(bp.Match("Now it's only 115/75")); //115/75

贪婪量词符号与懒惰量词符号

默认情况下,量词符号都是贪婪,而不是懒惰的。贪婪量词符号会尽可能多地匹配重复项目。而懒惰的量词符号则尽可能少地进行匹配。若在量词符号后添加?后缀,就可以将任何量词符号转换为懒惰的。

为了提取<i></i>中的短语:

string html = "<i>By default</i> quantifiers are <i>greedy</i> creatures";

假设我们需要提取斜体部分的短语。执行如下代码:

foreach (Match match in Regex.Matches(html, @"<i>.*</i>"))
{
    Console.WriteLine(match); 
}

结果只有一个匹配 ,而非两处匹配:

<i>By default</i> quantifiers are <i>greedy</i>

这是因为量词符号*将重复尽可能多次,直至匹配到最后一个</i>。因此它直接越过了第一个</i>,而仅仅到最后一个</i>才会停止(以这个位置起始的表达式可以继续进行匹配)。

采用懒惰量词符号:

foreach (Match match in Regex.Matches(html, @"<i>.*?</i>"))
{
    Console.WriteLine(match); 
}

其结果:

<i>By default</i>
<i>greedy</i>

零宽度断言

正则表达式语言允许在匹配的前后设置约束条件。这些条件包括后向条件(lookbehind)、前向条件(lookahead)、锚点(anchors)以及单词边界(word boundaries)。由于它们并不会增加匹配字符的长度,因此这些条件称为零宽度断言(zero-widthassertions)。

上一篇:KindEditor编辑器For DotNet控件


下一篇:sql2000 (附加数据库)错误9003:LSN(434:94:1)无效和数据库置疑处理