c# regex
正则表达式(regular expressions)是一套语法匹配规则,各种语言,如perl, .Net和Java都有其对应的共享的正则表达式类库。在.Net中,这个类库叫做regex。
简单的说,regex是从字符窗中查找匹配字符串的应用类。通过regex,编程人员能够非常方便的从一段数据中提取自己所需要的数据信息。举一个简单的例子,让大家对regex有个大概的了解:
regex regex = new regex(@"d+");
match m = regex.match("fox 9212gold");
console.writeline(m.value.tostring());
结果很明显,regex为我们找到了字符串”fox 9212gold”中的数字字符串,输出结果为”9212” .
对regex有了一个基本的概念之后,我需要告诉你一个非常好的消息,那就是regex可以为我们做的远不止这么一点点,他是一套功能非常强大语法匹配规则。当然,这里还有一个坏消息等着我们,那就是强大功能的语法规则自然需要大量纷繁复杂的keyword支持,这也为regex的学习带来了极大的难度。想要真正掌握正则表达式,可不是几个sample能够全部揭示与说明的。
创建一个regex对象
regex的构造函数有三种,在这里就不讨论默认构造函数了。另外两个构造函数中,一个构造函数接收正则表达式字符串作为入参,另一个以正则表达式字符串和regexoptions作为入参。如:
regex regex = new regex("w+$");
regex regex = new regex("s+", regexoptions.ignorecase | regexoptions.multiline);
regexoptions可以为我们提供一些特殊的帮助,比如ignorecase能够在匹配是忽略大小写,multiline能够调整^和$的意义,改为匹配一行的开头和结尾。
上面我们构造了一个正则表达式,只不过我们还没有用它来做任何事情,马上我们就可以通过使用下面的几个方法,实现对字符串对象的操作了。
匹配字符串
regex有两个获取匹配的方法match()和matches(),分别代表匹配一个,匹配多个结果。这里就用matches来展示一下怎么使用regex获取匹配字符串,并将其显示出来。
public static void showmatches(string expression, regexoptions option, string ms)
{
regex regex = new regex(expression, option);
matchcollection matches = regex.matches(ms);
//show matches
console.writeline("////////////////----------------------------------////////////////");
console.writeline(" string: "{0}" expression: "{1}" match result is:", ms, expression);
foreach(match m in matches)
{ console.writeline("match string is: "{0}", length: {1}",m.value.tostring(), m.value.length);
}
console.writeline("matched count: {0}", matches.count);
}
方法matched通过比较入参字符串和正则表达式,找到所有符合的结果,并将结果作为matchcollection传出来。这样,只要简单的遍历这个collection,就可以很快的获得所有的结果。
组的概念
当你获得这样的一个字符串”最后比分是:19/24”,你肯定希望有一个正则表达式,他不单能够找到形如 data1/data2的字符串,还应该能够直接把data1,data2作为单独的结果传送出来。否则你需要再对形如”19/24”的字符串进行分析,才能够顺利得到双方的比分。显然,正则表达式不会忽略这个问题,所以他增加了组的概念。你可以把一次搜索的结果分别放入不同的组中,并通过组名或者组的所以分别取得这些组的结果。比如上例,我们就可以用@”(\d+)/(\d+)”作为表达式。来看看结果吧:
regex regex = new regex(@"(d+)/(d+)");
matchcollection matches = regex.matches(@"最后比分是:19/24");
//show matches
console.writeline("////////////////----------------------------------////////////////");
foreach(match m in matches)
{
//console.writeline("match string is: "{0}", length: {1}", // m.value.tostring(), m.value.length);
foreach(string name in regex.getgroupnames())
{
console.writeline(" capture group "{0}" value is:"{1}"" , name, m.groups[name].value);
}
}
console.writeline("matched count: {0}", matches.count);
输出:
////////////////----------------------------------////////////////
capture group "0" value is:"19/24"
capture group "1" value is:"19"
capture group "2" value is:"24"
matched count: 1
现在清楚了吧,regex对象把匹配的结果放入组0中。同时,匹配的组信息也放入了对应的组中。组的名称在默认的情况下,是从1开始依次增加的整数。0作为保留名称,专门用于指示匹配的整个字符串。既然有”默认情况”这样的概念,自然也就意味着用户可以自定义组的名称。方法很简单,在组的前面加上:? 就可以了。好了,现在把前面的正则表达式修改一下,换成@”(? \d+)/(? \d+)”,现在再看看结果:
////////////////----------------------------------////////////////
capture group "0" value is:"19/24"
capture group "score1" value is:"19"
capture group "score2" value is:"24"
matched count: 1
换成自己定义的名字了吧,哈哈!为了在今后的测试中,能够更加方便的看到所有结果,我们对前面介绍过的showmatches()做一点小小的调整。这样,如果在表达式中包含了组的定义,我们也可以在不需要修改任何代码的情况下,直接看到所有的组信息了,调整后的方法showmatchespro()如下:
public static void showmatchespro(string expression, regexoptions option, string ms)
{
regex regex = new regex(expression, option);
matchcollection matches = regex.matches(ms);
//show matches
console.writeline("////////////////----------------------------------////////////////");
console.writeline(" string: "{0}" expression: "{1}" match result is:",ms, expression);
foreach(match m in matches)
{
foreach(string name in regex.getgroupnames())
{
console.writeline(" capture group "{0}" value is:"{1}"",name, m.groups[name].value);
}
}
console.writeline("matched count: {0}", matches.count);
// show group name
console.writeline("group name count {0}", regex.getgroupnames().length);
foreach(string name in regex.getgroupnames())
{
console.writeline("group name :"{0}"", name);
}
}
替换字符串
regex也提供了方便的匹配结果替换的功能。为了方便测试,我们也把他写成方法,代码如下:
public static string replacematch(string expression, regexoptions option, string ms, string rep)
{
regex regex = new regex(expression, option);
string result = regex.replace(ms, rep);
console.writeline("////////////////----------------------------------////////////////");
console.writeline("string: "{0}", expression:"{1}", replace by : "{2}"", ms, expression, rep);
console.writeline("replace result string is: "{0}", length: {1}", result.tostring(), result.length);
return result;
}
regex.replace通常接受两个string作为入参,第一个string为输入字符串。第二个字符串用来替代匹配字符串,它可以包含一些特殊字符串,用来代表特别转换。
特殊字符串 替换结果
$& 匹配的字符串,也可以用$0
$1, $2, . . . 匹配字符串中的对应组,用索引标示
${name} 匹配字符串中的对应组,用名称标示
$‘ 匹配位置之前的字符串
$’ 匹配位置之后的字符串
$$ 一个‘$’ 字符
$_ 输入字符串
$+ 匹配字符串的所有组中,最后一个组中的数据
是不是看了这么多怪型怪状的特殊字符串,有点头晕了?嗯,那就弄两个sample来看看结果吧!
sample1:
replacematch(@"\d+", regexoptions.none, "fef 12/21 df 33/14 727/1", "<<$&>>");
输出,所有数字型的数据都被替换成了<>:
////////////////----------------------------------////////////////
string: "fef 12/21 df 33/14 727/1", expression:"\d+", replace by : "<<$&>>"
replace result string is: "fef <<12>>/<<21>> df <<33>>/<<14>> <<727>>/<<1>>",
length: 50
sample2:
replacematch(@"(\d+)/(\d+)", regexoptions.none, "fef 12/21 df 33/14 727/1", "$+");
输出,所有data1/data2匹配的数据,都被替换成了data2:
////////////////----------------------------------////////////////
string: "fef 12/21 df 33/14 727/1", expression:"(\d+)/(\d+)", replace by : "$+"
replace result string is: "fef 21 df 14 1", length: 16
怎么样,regex的功能够丰富的吧!可是,也许你的需求不光这么简单,比如说,你要把”i have 200 dollars”中间的money加倍,怎么办?我晕倒,好像没有现成的东西可以用。没有关系,regex还有更好的功能。它允许你自己定义转换公式。
using system.text.regularexpressions;
class regularexpressions
{
static string captext(match m)
{
// get the matched string.
string x = m.tostring();
// double this value
string result = (int.parse(x) * 2).tostring();
return result;
}
static void main()
{
string text = "i have 200 dollars";
string result = regex.replace(text, @"d+",new matchevaluator(regularexpressions.captext));
system.console.writeline("result=[" + result + "]");
}
}
看看结果,太好了,我的钱真的变成了两倍!
但本文的目的是希望提供给大家一个方便好用的测试类,因此我们重载上面的repalcematch方法,也允许自定义转换公式作为入参:
public static string replacematch(string expression, regexoptions option, string ms,
matchevaluator evaluator)
{
regex regex = new regex(expression, option);
string result = regex.replace(ms, evaluator);
console.writeline("////////////////----------------------------------////////////////");
console.writeline("string: "{0}", expression:"{1}", replace by a evaluator.", ms, expression);
console.writeline("replace result string is: "{0}", length: {1}", result.tostring(), result.length);
return result;
}
拆分字符串
regex还提供了从匹配位置将字符串拆分的方法split。这个方法同样具有多个重载,不过这些都不是重点,大家可以自己看文档。我们继续完成我们用于测试的方法:
public static void splitmatch(string expression, regexoptions option, string ms)
{
regex regex = new regex(expression, option);
string[] result = regex.split(ms);
console.writeline("////////////////----------------------------------////////////////");
console.writeline("string: "{0}", expression: "{1}", split result is:", ms, expression);
foreach(string m in result)
{
console.writeline("splited string is: "{0}", length: {1}",m.tostring(), m.length);
}
console.writeline("splited count: {0}", result.length);
}
代码简单,不多做解释。直接来一个smaple看看结果:
splitmatch(@"/",regexoptions.none, "2004/4/25");
输出:
////////////////----------------------------------////////////////
string: "2004/4/25", expression: "/", split result is:
splited string is: "2004", length: 4
splited string is: "4", length: 1
splited string is: "25", length: 2
splited count: 3
这个文章的目的很简单:介绍regex的几个主要功能(匹配、替换和拆分),并提供几个简单方便的测试函数。让你能够测试你对正则表达式的理解是否准确。
比如想要确认^$的作用,你可以放入这样的(input, expression)数据:
(“123”, “^\d+$”) (“123aaa456”, “^\d+”) (“123aaa456”, “123&”)
确认\d, \s, \w, \w的作用,可以这样测试:
(“123abc gc 456”, “\d+”)(“123abc gc 456”, “\s+”)
(“123abc gc 456”, “\w+”)(“123abc gc 456”, “\w+”)
比较? + *之间的区别可以用这样的数据:
(“a123 abcd”, “a\d?”) (“a123 abcd”, “a\d+”) (“a123 abcd”, “a\d*”)
简单的说,regex是从字符窗中查找匹配字符串的应用类。通过regex,编程人员能够非常方便的从一段数据中提取自己所需要的数据信息。举一个简单的例子,让大家对regex有个大概的了解:
regex regex = new regex(@"d+");
match m = regex.match("fox 9212gold");
console.writeline(m.value.tostring());
结果很明显,regex为我们找到了字符串”fox 9212gold”中的数字字符串,输出结果为”9212” .
对regex有了一个基本的概念之后,我需要告诉你一个非常好的消息,那就是regex可以为我们做的远不止这么一点点,他是一套功能非常强大语法匹配规则。当然,这里还有一个坏消息等着我们,那就是强大功能的语法规则自然需要大量纷繁复杂的keyword支持,这也为regex的学习带来了极大的难度。想要真正掌握正则表达式,可不是几个sample能够全部揭示与说明的。
创建一个regex对象
regex的构造函数有三种,在这里就不讨论默认构造函数了。另外两个构造函数中,一个构造函数接收正则表达式字符串作为入参,另一个以正则表达式字符串和regexoptions作为入参。如:
regex regex = new regex("w+$");
regex regex = new regex("s+", regexoptions.ignorecase | regexoptions.multiline);
regexoptions可以为我们提供一些特殊的帮助,比如ignorecase能够在匹配是忽略大小写,multiline能够调整^和$的意义,改为匹配一行的开头和结尾。
上面我们构造了一个正则表达式,只不过我们还没有用它来做任何事情,马上我们就可以通过使用下面的几个方法,实现对字符串对象的操作了。
匹配字符串
regex有两个获取匹配的方法match()和matches(),分别代表匹配一个,匹配多个结果。这里就用matches来展示一下怎么使用regex获取匹配字符串,并将其显示出来。
public static void showmatches(string expression, regexoptions option, string ms)
{
regex regex = new regex(expression, option);
matchcollection matches = regex.matches(ms);
//show matches
console.writeline("////////////////----------------------------------////////////////");
console.writeline(" string: "{0}" expression: "{1}" match result is:", ms, expression);
foreach(match m in matches)
{ console.writeline("match string is: "{0}", length: {1}",m.value.tostring(), m.value.length);
}
console.writeline("matched count: {0}", matches.count);
}
方法matched通过比较入参字符串和正则表达式,找到所有符合的结果,并将结果作为matchcollection传出来。这样,只要简单的遍历这个collection,就可以很快的获得所有的结果。
组的概念
当你获得这样的一个字符串”最后比分是:19/24”,你肯定希望有一个正则表达式,他不单能够找到形如 data1/data2的字符串,还应该能够直接把data1,data2作为单独的结果传送出来。否则你需要再对形如”19/24”的字符串进行分析,才能够顺利得到双方的比分。显然,正则表达式不会忽略这个问题,所以他增加了组的概念。你可以把一次搜索的结果分别放入不同的组中,并通过组名或者组的所以分别取得这些组的结果。比如上例,我们就可以用@”(\d+)/(\d+)”作为表达式。来看看结果吧:
regex regex = new regex(@"(d+)/(d+)");
matchcollection matches = regex.matches(@"最后比分是:19/24");
//show matches
console.writeline("////////////////----------------------------------////////////////");
foreach(match m in matches)
{
//console.writeline("match string is: "{0}", length: {1}", // m.value.tostring(), m.value.length);
foreach(string name in regex.getgroupnames())
{
console.writeline(" capture group "{0}" value is:"{1}"" , name, m.groups[name].value);
}
}
console.writeline("matched count: {0}", matches.count);
输出:
////////////////----------------------------------////////////////
capture group "0" value is:"19/24"
capture group "1" value is:"19"
capture group "2" value is:"24"
matched count: 1
现在清楚了吧,regex对象把匹配的结果放入组0中。同时,匹配的组信息也放入了对应的组中。组的名称在默认的情况下,是从1开始依次增加的整数。0作为保留名称,专门用于指示匹配的整个字符串。既然有”默认情况”这样的概念,自然也就意味着用户可以自定义组的名称。方法很简单,在组的前面加上:?
////////////////----------------------------------////////////////
capture group "0" value is:"19/24"
capture group "score1" value is:"19"
capture group "score2" value is:"24"
matched count: 1
换成自己定义的名字了吧,哈哈!为了在今后的测试中,能够更加方便的看到所有结果,我们对前面介绍过的showmatches()做一点小小的调整。这样,如果在表达式中包含了组的定义,我们也可以在不需要修改任何代码的情况下,直接看到所有的组信息了,调整后的方法showmatchespro()如下:
public static void showmatchespro(string expression, regexoptions option, string ms)
{
regex regex = new regex(expression, option);
matchcollection matches = regex.matches(ms);
//show matches
console.writeline("////////////////----------------------------------////////////////");
console.writeline(" string: "{0}" expression: "{1}" match result is:",ms, expression);
foreach(match m in matches)
{
foreach(string name in regex.getgroupnames())
{
console.writeline(" capture group "{0}" value is:"{1}"",name, m.groups[name].value);
}
}
console.writeline("matched count: {0}", matches.count);
// show group name
console.writeline("group name count {0}", regex.getgroupnames().length);
foreach(string name in regex.getgroupnames())
{
console.writeline("group name :"{0}"", name);
}
}
替换字符串
regex也提供了方便的匹配结果替换的功能。为了方便测试,我们也把他写成方法,代码如下:
public static string replacematch(string expression, regexoptions option, string ms, string rep)
{
regex regex = new regex(expression, option);
string result = regex.replace(ms, rep);
console.writeline("////////////////----------------------------------////////////////");
console.writeline("string: "{0}", expression:"{1}", replace by : "{2}"", ms, expression, rep);
console.writeline("replace result string is: "{0}", length: {1}", result.tostring(), result.length);
return result;
}
regex.replace通常接受两个string作为入参,第一个string为输入字符串。第二个字符串用来替代匹配字符串,它可以包含一些特殊字符串,用来代表特别转换。
特殊字符串 替换结果
$& 匹配的字符串,也可以用$0
$1, $2, . . . 匹配字符串中的对应组,用索引标示
${name} 匹配字符串中的对应组,用名称标示
$‘ 匹配位置之前的字符串
$’ 匹配位置之后的字符串
$$ 一个‘$’ 字符
$_ 输入字符串
$+ 匹配字符串的所有组中,最后一个组中的数据
是不是看了这么多怪型怪状的特殊字符串,有点头晕了?嗯,那就弄两个sample来看看结果吧!
sample1:
replacematch(@"\d+", regexoptions.none, "fef 12/21 df 33/14 727/1", "<<$&>>");
输出,所有数字型的数据都被替换成了<>:
////////////////----------------------------------////////////////
string: "fef 12/21 df 33/14 727/1", expression:"\d+", replace by : "<<$&>>"
replace result string is: "fef <<12>>/<<21>> df <<33>>/<<14>> <<727>>/<<1>>",
length: 50
sample2:
replacematch(@"(\d+)/(\d+)", regexoptions.none, "fef 12/21 df 33/14 727/1", "$+");
输出,所有data1/data2匹配的数据,都被替换成了data2:
////////////////----------------------------------////////////////
string: "fef 12/21 df 33/14 727/1", expression:"(\d+)/(\d+)", replace by : "$+"
replace result string is: "fef 21 df 14 1", length: 16
怎么样,regex的功能够丰富的吧!可是,也许你的需求不光这么简单,比如说,你要把”i have 200 dollars”中间的money加倍,怎么办?我晕倒,好像没有现成的东西可以用。没有关系,regex还有更好的功能。它允许你自己定义转换公式。
using system.text.regularexpressions;
class regularexpressions
{
static string captext(match m)
{
// get the matched string.
string x = m.tostring();
// double this value
string result = (int.parse(x) * 2).tostring();
return result;
}
static void main()
{
string text = "i have 200 dollars";
string result = regex.replace(text, @"d+",new matchevaluator(regularexpressions.captext));
system.console.writeline("result=[" + result + "]");
}
}
看看结果,太好了,我的钱真的变成了两倍!
但本文的目的是希望提供给大家一个方便好用的测试类,因此我们重载上面的repalcematch方法,也允许自定义转换公式作为入参:
public static string replacematch(string expression, regexoptions option, string ms,
matchevaluator evaluator)
{
regex regex = new regex(expression, option);
string result = regex.replace(ms, evaluator);
console.writeline("////////////////----------------------------------////////////////");
console.writeline("string: "{0}", expression:"{1}", replace by a evaluator.", ms, expression);
console.writeline("replace result string is: "{0}", length: {1}", result.tostring(), result.length);
return result;
}
拆分字符串
regex还提供了从匹配位置将字符串拆分的方法split。这个方法同样具有多个重载,不过这些都不是重点,大家可以自己看文档。我们继续完成我们用于测试的方法:
public static void splitmatch(string expression, regexoptions option, string ms)
{
regex regex = new regex(expression, option);
string[] result = regex.split(ms);
console.writeline("////////////////----------------------------------////////////////");
console.writeline("string: "{0}", expression: "{1}", split result is:", ms, expression);
foreach(string m in result)
{
console.writeline("splited string is: "{0}", length: {1}",m.tostring(), m.length);
}
console.writeline("splited count: {0}", result.length);
}
代码简单,不多做解释。直接来一个smaple看看结果:
splitmatch(@"/",regexoptions.none, "2004/4/25");
输出:
////////////////----------------------------------////////////////
string: "2004/4/25", expression: "/", split result is:
splited string is: "2004", length: 4
splited string is: "4", length: 1
splited string is: "25", length: 2
splited count: 3
这个文章的目的很简单:介绍regex的几个主要功能(匹配、替换和拆分),并提供几个简单方便的测试函数。让你能够测试你对正则表达式的理解是否准确。
比如想要确认^$的作用,你可以放入这样的(input, expression)数据:
(“123”, “^\d+$”) (“123aaa456”, “^\d+”) (“123aaa456”, “123&”)
确认\d, \s, \w, \w的作用,可以这样测试:
(“123abc gc 456”, “\d+”)(“123abc gc 456”, “\s+”)
(“123abc gc 456”, “\w+”)(“123abc gc 456”, “\w+”)
比较? + *之间的区别可以用这样的数据:
(“a123 abcd”, “a\d?”) (“a123 abcd”, “a\d+”) (“a123 abcd”, “a\d*”)