ECMAScript.NET正则基础——.NET正则类似和艺术运用

1        概述

初学正则不时,对于Regex类不熟识,遇到问题非晓得该用啦种方式解决,本文结合一些刚则以之天下第一以场景,介绍一下Regex类的中心以。这里关键进行.NET类的介绍,对于正则的采取,不举行深入探讨。

适则的采用最终还是进展模式之相当,而基于目的的例外,基本上可以分为以下几栽采取:验证、提取、替换、分割。结合.NET提供的控件、类和近似的法,可以老有利的贯彻这些应用。

以下将成一些典型的采用场景,对.NET中广泛的切近、方法与性进行介绍。本文旨在.NET类基础用法的导,对于其中涉嫌到之正则表达式不做深入探讨。本文适合为在.NET平台下以正则的新家。

2        基础运用

2.1     验证

证实的目的是为判定输入的源字符串是否顺应某平等原理或规则,根据需要的例外,可能是校验整个源字符串,也可能不过是校验其中一个子串。

证明在.NET中一般发生点儿种植下,一种是以认证控件RegularExpressionValidator中,另一样种植是在次中。

2.1.1  验证控件RegularExpressionValidator

RegularExpressionValidator是.NET自带的一律栽客户端验证控件,通过简单的安装,即可形成对某控件输入值的校验。

主导使用语法如下:

       
<asp:RegularExpressionValidator

           
ID=”RegularExpressionValidator1″

           
runat=”server”

           
ControlToValidate=”TextBox1″

           
ErrorMessage=”RegularExpressionValidator”

           
ValidationExpression=”^([1-9][0-9]*|0)(\.[0-9][2])?$”>

        </asp:RegularExpressionValidator>

于RegularExpressionValidator控件不做了多介绍,只是说明一下运时索要留意的几乎接触:

1、 
RegularExpressionValidator进行的凡客户端验证;

2、 
RegularExpressionValidator中正则利用的凡JavaScript语法规则;

3、 
RegularExpressionValidator控件不可知征输入是否也空。

由RegularExpressionValidator做的凡客户端验证,很容易让跳过,所以于用RegularExpressionValidator验证的同时,还要做劳动器端验证。

RegularExpressionValidator最终是若深成客户端的JavaScript代码进行认证的,所以RegularExpressionValidator使用的正则要求符合JavaScript语法规则,与.NET的几接触分别:

1、 
不支持逆序环视,也尽管是(?<=Expression)和(?<!Expression)这样的语法;

2、 
元字符仅支持ASCII码,即\w等价于[a-zA-Z0-9_],\d等价于[0-9]

RegularExpressionValidator控件一般是为此来说明某同控件输入的字符串整体是否符合某平等平整的,所以便状态下“^”和“$”是必要的;在动用“|”表示“或”的涉经常,一定要是因此“()”来限定“|”作用范围,比如0-100足写“^([1-9]?[0-9]|100)$”。

RegularExpressionValidator是免可知证明输入是否为空的,验证是否也空要为此RequiredFieldValidator控件。

RegularExpressionValidator验证控件是.NET为便宜客户端验证封装的等同组求证控件之一,但由于RegularExpressionValidator受抑制支持之正则语法规则,只能开少的格式校验,一些繁杂的校验可以经投机写JavaScript代码来落实,也是挺简短的。

2.1.2  程序验证——IsMatch()

程序中的校验基本上就是是运IsMatch方法,验证的目标或是源字符串的圆,也恐怕仅是中间一个子串。

证实源字符串的完全是否适合某平规则,与下RegularExpressionValidator时之需求大多一致,不过由于是当.NET程序中,所以下的凡.NET的语法,比JavaScript中如强有力得多。比如验证一个文本框输入的字符串是否适合某同条条框框,就是一个一流的说明整体的急需。

举例1:验证textBox1输入内容,要求整数有些也0还是碰巧整数,小数可发生可不论是,有小数时必也2位。

           
Regex reg = new Regex(@”^(?:[1-9][0-9]*|0)(?:\.[0-9]{2})?$”);

           
if
(reg.IsMatch(textBox1.Text))

           
{

                richTextBox2.Text =
“输入格式正确!”;

           
}

           
else

           
{

                richTextBox2.Text =
“输入格式错误!”;

           
}

鉴于是针对源字符串的完整进行说明,所以“^”和“$”是少不了的。否则验证的结果或者是不当的,比如正则表达式“(?:[1-9][0-9]*|0)(?:\.[0-9]{2})?”,在输入“0.123”时凡好配合成功之,匹配结果吗“0.12”,此时恰好则单纯打至了相当的企图,没有于至说明的意向。

说明源字符串的片是否可某一样条条框框,就是于源字符串中子串的校验,通常是因此来判断源字符串中是否包含,或是不分包符合某平等原理的子串,作用类似于string类吃的IndexOf。

举例2(参考叩问两只正则表达式):

数据:

1985aaa1985bb

bcae1958fiefadf1955fef

atijc1944cvkd

df2564isdjfef2564d

abc1234def5678ghi5678jkl

求1:验证字符串中自由位置出现的连接四独数字在全体字符串中是否生再度,有再次为True,无复为False。

如上数量需求1底认证结果也True的应为:

1985aaa1985bb

df2564isdjfef2564d

abc1234def5678ghi5678jkl

为急需面临指明是随便位置的连天4单数字是否发再次,所以当找到更前,要任何历源字符串中每一个位置时行验证,这样即便非能够限定开始标识符“^”;而在配合过程中,除非一直到最终仍找不至还,否则如果匹配到发重复的职位就可以了,这样吗无待了标识符“$”,所以马上是数一数二的对字符串的子串行验证的需。

代码实现:

string[]
test = new string[] { “1985aaa1985bb”, “bcae1958fiefadf1955fef”, “atijc1944cvkd”, “df2564isdjfef2564d”, “abc1234def5678ghi5678jkl”
};

Regex
reg = new Regex(@”(\d{4})(?:(?!\1).)*\1″);

foreach
(string s in test)

{

      richTextBox2.Text += “源字符串: 

  • s.PadRight(25, ‘ ‘) + “验证结果: 
  • reg.IsMatch(s) + “\n”;

}

/*——–输出——–

源字符串:  1985aaa1985bb            验证结果: 
True

源字符串:  bcae1958fiefadf1955fef   验证结果: 
False

源字符串:  atijc1944cvkd            验证结果: 
False

源字符串:  df2564isdjfef2564d       验证结果: 
True

源字符串:  abc1234def5678ghi5678jkl
验证结果: 
True

*/

由涉及到了再也问题,所以这边以了反向引用,对于反朝引用的底细,可以参照刚好则基础之——反向引用。

急需2:验证字符串中首先单冒出的接连4只数字是否生再次,有再次为True,无复为False。

如上数量需求2的认证结果吧True的应为:

1985aaa1985bb

df2564isdjfef2564d

因要求中指明是第一单是否来还,所以要有初步标识符“^”,来管是第一独冒出的总是4个数字;而在配合过程中,除非一直顶最后仍找不至重,否则一经匹配到起再次的位置就得了,这样为无欲收尾标识符“$”,所以就仍是对准字符串的子串行验证的要求,只不过相对于需要1的话,加了一个限制条件。

代码实现:

string[]
test = new string[] { “1985aaa1985bb”, “bcae1958fiefadf1955fef”, “atijc1944cvkd”, “df2564isdjfef2564d”, “abc1234def5678ghi5678jkl”
};

Regex
reg = new Regex(@”^(?:(?!\d{4}).)*(\d{4})(?:(?!\1).)*\1″);

foreach
(string s in test)

{

     richTextBox2.Text += “源字符串: 

  • s.PadRight(25, ‘ ‘) + “验证结果: 
  • reg.IsMatch(s) + “\n”;

}

/*——–输出——–

源字符串:  1985aaa1985bb            验证结果: 
True

源字符串:  bcae1958fiefadf1955fef   验证结果: 
False

源字符串:  atijc1944cvkd            验证结果: 
False

源字符串:  df2564isdjfef2564d       验证结果: 
True

源字符串:  abc1234def5678ghi5678jkl
验证结果: 
False

*/

2.2     提取——Match()、Matches()

领到主要是打源字符串中,取得一个或多独副某平规律或规则的子串。一般的话,在字符串处理中,提取使用比较宽泛。提取时用得较多的是Match()和Matches()方法,以及结果处理时Match类和MatchCollection类的有些方法,有时也会用到Capture类的有主意。

2.2.1  提取单次匹配内容——Match()

当用领取的内容才发一个,或是只待得到第一不行得逞匹配的始末时,可以使用Match()方法。当用Match()方法时,只要在某某平位置匹配成功,就不再继续品尝匹配,并赶回一个Match类型的对象。

举例:提取姓名

源字符串:姓名:张三,性别:男,年龄:**25**

代码实现:

string
test = “姓名:张三,性别:男,年龄:25”;

Regex
reg = new Regex(@”(?<=姓名:)[^,]+”);

Match
m = reg.Match(test);

if
(m.Success)    //验证是否配合成功

{

     
richTextBox2.Text = m.Value;

}

/*——–输出——–

张三

*/

虽然Match()只是得到一赖匹配,但是得经捕获组来赢得多单指定子串,比如取第一只<a…>标签的链接和文件。

string
test = “abc<a
href=\”www.test1.com\”>测试一</a>def<a
href=\”www.test2.com\”>测试二</a>ghi”;

Regex
reg = new Regex(@”(?is)<a(?:(?!href=).)href=([‘””]?)(?<url>[^””\s>]*)\1[^>]*>(?<text>(?:(?!</?a\b).)*)</a>”);

Match
m = reg.Match(test);

if(m.Success)

{

     richTextBox2.Text +=
m.Groups[“url”].Value + “\n”;      //链接

     richTextBox2.Text +=
m.Groups[“text”].Value + “\n”;    
//文本

}

/*——–输出——–

www.test1.com

测试一

*/

对此捕获组捕获结果的援,还有雷同种植艺术

string
test = “abc<a
href=\”www.test1.com\”>测试一</a>def<a
href=\”www.test2.com\”>测试二</a>ghi”;

Regex
reg = new Regex(@”(?is)<a(?:(?!href=).)href=([‘””]?)(?<url>[^””\s>]*)\1[^>]*>(?<text>(?:(?!</?a\b).)*)</a>”); Match m = reg.Match(test);

if(m.Success)

{

     richTextBox2.Text +=
m.Result(“${url}”) + “\n”;      //链接

     richTextBox2.Text +=
m.Result(“${text}”) + “\n”;    
//文本

}

/*——–输出——–

www.test1.com

测试一

*/

顿时片栽方法取得的结果还是平的,使用啊一样栽,通常根据个体习惯而迟早。

2.2.2  提取多次相当内容——Matches()

当需要领取的情有多个,并且用领取所有符合规律的子串时,可以应用Matches()方法。当以Matches()方法时,需要遍历源字符串的各国一个岗位进行尝试匹配,匹配了返回一个MatchCollection类型的对象。

对于1.2.1节涉嫌的提链接和文件的例子,如果提取的是全部链接和文件,而不光是率先只时,可以利用Matches()方法。

string
test = “abc<a
href=\”www.test1.com\”>测试一</a>def<a
href=\”www.test2.com\”>测试二</a>ghi”;

Regex
reg = new Regex(@”(?is)<a(?:(?!href=).)href=([‘””]?)(?<url>[^””\s>]*)\1[^>]*>(?<text>(?:(?!</?a\b).)*)</a>”);

MatchCollection
mc = reg.Matches(test);

foreach(Match m in mc)

{

     richTextBox2.Text +=
m.Groups[“url”].Value + “\n”;      //链接

     richTextBox2.Text +=
m.Groups[“text”].Value + “\n”;    
//文本

}

/*——–输出——–

www.test1.com

测试一

www.test2.com

测试二

*/

对Matches(),某些场景下,也得以透过Count属性,用做统计称某同规律的子串出现的次数,例如统计字符串中独的“3”出现的次数。

string
test = “137,1,33,4,3,6,21,3,35,93,2,98”;

Regex
reg = new Regex(@”\b3\b”);

int
count = reg.Matches(test).Count;    //2

这会儿关心的独是相当成功之次数,对于匹配的始末是无关注的,所以实现这种需要时,正则应竭尽简单,能达标目的即可,这样可加快匹配效率,减少资源占用。比如上面的提取链接的源字符串中,统计<a…>标签出现的次数,一般的话,如下代码即可达到目的了。

string
test = “abc<a
href=\”www.test1.com\”>测试一</a>def<a
href=\”www.test2.com\”>测试二</a>ghi”;

Regex
reg = new Regex(@”(?i)<a\b”);

int
count = reg.Matches(test).Count;   
//2

2.2.3  捕获组匹配过程集合——Capture

每当一些情况下,一个正则表达式整体相当同差时,其中的捕获组可能会见配合多次。

举例

源字符串:<region
name=oldslist col=1 row=2 order=asc>abcsadf </region>
jfdsajf  <region name=newslist
class=list col=4 row=10 order=desc>abcsadf
</region>

要求:提取出每个region的性能和属性值,按region分组。

对于此要求,可以先领出具有region,再对每个region标签提取其的性质和属性值,但这么做比较累,可以设想当一个正则表达式中提取。由于性能的个数是匪定点的,所以不能够为此固定个数的量词来配合配属性对,正则可以描绘吧

(?is)<region\s+(?:(?<key>[^\s=]+)=(?<value>[^\s>]+)\s*)+>

这时只要还因此Groups来收获匹配结果时,由于Groups只保留最后一不好匹配结果,所以只好取得到结尾一不善匹配成功之子串。这时就要用到Captures属性。

string
test = “<region name=oldslist col=1
row=2 order=asc>abcsadf </region> jfdsajf  <region name=newslist class=list
col=4 row=10 order=desc>abcsadf
</region>”;

MatchCollection
mc = Regex.Matches(test, @”(?is)<region\s+(?:(?<key>[^\s=]+)=(?<value>[^\s>]+)\s*)+>”);

for
(int i = 0; i < mc.Count;
i++)

{

    richTextBox2.Text += “第”

  • (i + 1) + “个region的属性:\n”;

   
for (int j = 0; j < mc[i].Groups[“key”].Captures.Count; j++)

   
{

        richTextBox2.Text += “属性: “

  • mc[i].Groups[“key”].Captures[j].Value.PadRight(10,
    ‘ ‘) + ” 
    值: “
  • mc[i].Groups[“value”].Captures[j].Value + “\n”;

   
}

   
richTextBox2.Text += “\n”;

}

/*——–输出——–

第1个region的属性:

属性: name        值:
oldslist

属性: col         值:
1

属性: row         值:
2

属性: order       值:
asc

 

第2个region的属性:

属性: name        值:
newslist

属性: class       值:
list

属性: col         值:
4

属性: row         值:
10

属性: order       值:
desc

*/

Group实际上是Capture的一个会师,在捕获组只相当一个子串时,这个集只出一个因素,而于捕获组先后匹配多只子串时,Groups[i].Value只保留最后一个相当结果,而Capture集合却得以记下匹配过程被匹配到之兼具子串。

Capture的利用场景并无多,对于地方的事例,如果不应用
Capture,可以经过分次匹配的办法实现,但是以一些犬牙交错的表达式中,很为难展开分次匹配,这时Capture就较起因此了。

2.3      替换

轮换主要是从源字符串中,将适合某同规律或规则之子串替换为任何内容。一般的话,在字符串处理中,替换下为比较大。替换主要是故Replace()方法,在一部分调换规则复杂的使场景被,也可能会见用到委托方。

2.3.1  一般替换

轮换的目的非常显然,只要找来要替换子串的原理,替换为对象子串就足以了。

举例1

源字符串:<img
src=”/imgs/logo.jpg”> abc <img
src=”http://www.test.com/imgs/top.gif"&gt;

需:将相对地址替换为绝对地址,已经是绝地址之免替换。

string
test = “<img
src=\”/imgs/logo.jpg\”> abc <img
src=\”http://www.test.com/imgs/top.gif\\"&gt;”;

Regex
reg = new Regex(@”(?i)(?<=src=([‘””]?))(?!http://)(?=\[^'""\\s&gt;\]+\\1)”);

string
result = reg.Replace(test, “http://www.test.com”);

/*——–输出——–

<img
src=”http://www.test.com/imgs/logo.jpg"&gt; abc <img
src=”http://www.test.com/imgs/top.gif"&gt;

*/

此处用证实的是,在.NET中仅提供了一个Replace()方法,没有提供类似于Java被之replaceAll()和replaceFirst()两种艺术,所以只要以.NET中不过替换第一软出现的符合规律的子串时,需要在正则表达式中拍卖。

举例2

源字符串:abc123def123ghi

需:将率先赖面世的“123”替换为空,其余位置不替换。

string
test = “abc123def123ghi”;

Regex
reg = new Regex(@”(?s)^((?:(?!123).)*)123″);

string
result = reg.Replace(test, “$1”);

/*——–输出——–

abcdef123ghi

*/

这时用“^”限定只替换第一糟糕出现的子串,由于大部分刚刚则引擎都针对“^”进行了优化,所以正则表达式在位置0处匹配成功或破产后,将不再对任何位置进行尝试匹配。

2.3.2  替换着的寄托方以

于部分比较复杂的更迭规则,可能会见因此到委托方,由于这种用属于比较典型的同等种植使,所以用在背后的章中独开展介绍。

2.4     分割

分割就是用适合某平原理的子串,将源字符串分割成一个往往组,主要采用的凡Split()方法。由于Regex的Split()方法被,并不曾供类似于string的Split()方法的StringSplitOptions.RemoveEmptyEntries参数,而若符合规律的子串出现在起来或最后时,会现出非欲的空白,这时急需以正则表达式中展开一下拍卖。

举例1

源字符串:汉字123文字english

要求:按英文单词和无英文单词进行剪切(英文单词包括由a-z,A-Z,0-9,_组合的子串)。

string
str = “汉字123文字english”;

string[]
result = Regex.Split(str, @”(?<!^)\b(?!$)”, RegexOptions.ECMAScript);

foreach
(string s in result)

{

    
richTextBox2.Text += s + “\n”;

}

/*——–输出——–

汉字

123

文字

English

*/

这里分别用“(?<!^)”和“(?!$)”来限制不以开或最后的子串进行分割,结果遭到也便未见面出现不必要之空了。

还有局部行使,其实可以算是刚则就是用技术范畴的了。

举例2

源字符串:Left(姓名,1),Left(姓名,1) ,  Left    (姓名,1)

需求:以不在“()”内的“,”进行划分。

string
test = “Left(姓名,1),Left(姓名,1) ,  Left    (姓名,1)”;

Regex
reg = new Regex(@”(?<!\([^)]*),(?![^(]*\))”);

string[]
sArray = reg.Split(test);

foreach
(string s in sArray)

{

    
richTextBox2.Text += s + “\n”;

}

/*——–输出——–

Left(姓名,1)

Left(姓名,1)

  Left    (姓名,1)

*/

以正则的Split()方法时,有几许急需注意,那即便是如恰巧则遭遇冒出了捕获组,那么捕获组匹配到的始末为会保留到分结果丁。

以下举例不举行详细说明,看下结果多就是掌握了。

string
test = “aa11<bbb>cc22<ddd>ee”;

string[]
temp = Regex.Split(test, @”[0-9]+(<[^>]*>)”);

foreach
(string s in temp)

{

    
richTextBox2.Text += s + “\n”;

}

/*——–输出——–

aa

<bbb>

cc

<ddd>

ee

*/

如若非思量管捕获组匹配到的始末呢存入结果,可以使用非捕获组。

string
test = “aa11<bbb>cc22<ddd>ee”;

string[]
temp = Regex.Split(test, @”[0-9]+(?:<[^>]*>)”);

foreach
(string s in temp)

{

    
richTextBox2.Text += s + “\n”;

}

/*——–输出——–

aa

cc

ee

*/

3       扩展应用

此地介绍一些恐涉嫌到的片段.NET中之正则扩展应用。

3.1     动态变化正则常常的转义——Escape()

偶然用根据部分变量动态变化正则表达式,这时要变量中蕴含正则惨遭之元字符,会受分析成首字符,就可能会见造成正则编译不通过,从而致使程序非常,需要针对变量进行转义处理。Regex.
Escape()方法通过轮换为转义码来转义最小之字符集(\、*、+、?、|、{、[、(、)、^、$、.、# 和空白)。

按照根据用户输入的id取相应的div标签,id中绝非元字符时,可以抱是结果。

string
test = “<div
id=\”test1\”>abc</div><div
id=\”test2\”>def</div>”;           

string[]
ids = new string[] { “test1”, “test2” };

foreach
(string id in ids)

{

    
Regex reg = new Regex(@”(?is)<div\s+id=””” + id + @”””[^>]*>(?:(?!</?div\b).)*</div>”);

    
MatchCollection mc =
reg.Matches(test);

    
foreach (Match m in mc)

    
{

         
richTextBox2.Text += m.Value + “\n”;

    
}

}

/*——–输出——–

<div
id=”test1″>abc</div>

<div
id=”test2″>def</div>

*/

唯独一旦输入的id中如果出现未经转义的元字符,如“abc(”,就见面抛类似于下的不胜。

正巧以分析“(?is)<div\s+id=”abc(“[^>]*>(?:(?!</?div\b).)*</div>”- ) 不足。

这儿得为此Escape()方法对输入的变量进行转义处理。

string
test = “<div
id=\”test1\”>abc</div><div
id=\”test2\”>def</div>”;           

string[]
ids = new string[] { “test1”, “test2”, “abc(” };

foreach
(string id in ids)

{

    
Regex reg = new Regex(@”(?is)<div\s+id=””” + Regex.Escape(id) + @”””[^>]*>(?:(?!</?div\b).)*</div>”);

    
MatchCollection mc =
reg.Matches(test);

    
foreach (Match m in mc)

    
{

        
 richTextBox2.Text +=
m.Value + “\n”;

    
}

}

/*——–输出——–

<div
id=”test1″>abc</div>

<div
id=”test2″>def</div>

*/

以Escape()方法转义后,就可以博不错的结果,而非会见扔大了。

3.2     静态方法

.NET中部分Regex类的广大方式都提供了相应的静态方法,可以不显式的声明Regex对象,而一直调用相应的法门,书写起来重新便民,代码更简明、易读。

随替换IP地址最后一节约也“*”,只需要一行代码。

string
result = Regex.Replace(“10.27.123.12″, @”\d+$”, “*”);  
//10.27.123.*

静态方法每次调用都见面创一个临时之Regex对象,使用以后自由,所以每次调用静态方法时,都见面重编译,而及时将会晤降低执行效率。因此在循环或是频繁调用的方被,不相符采取静态方法,而需要进行显式声明Regex对象。

而是于有些只调用同样不良,或是对履行效率没有要求的气象下,静态方法则是十分正确的选取。