正则表达式(Regular
Expression,在代码中常简写为regex、regexp或RE)是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。许多程序设计语言都支持利用正则表达式进行字符串操作。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。

1        概述

初学正则时,对于Regex类不熟悉,遇到问题不知道该用哪种方法解决,本文结合一些正则应用的典型应用场景,介绍一下Regex类的基本应用。这里重点进行.NET类的介绍,对于正则的运用,不做深入探讨。

正则的应用最终都是进行模式的匹配,而根据目的的不同,基本上可以分为以下几种应用:验证、提取、替换、分割。结合.NET提供的控件、类以及类的方法,可以很方便的实现这些应用。

以下将结合一些典型的应用场景,对.NET中常见的类、方法及属性进行介绍。本文旨在.NET类基础用法的引导,对于其中涉及到的正则表达式不做深入探讨。本文适合于在.NET平台下使用正则的初学者。

一、Regexp类的一些方法:

正则表达式

2        基础应用

    Regexp.new/compile (string/regexp,[options,[lang]]) :
构造一个正则表达式对象。第一个参数是一个字符串或者正则表达式;第二个参数是
正则表达式修饰符的按位OR。

^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$

2.1     验证

验证的目的是为了判断输入的源字符串是否符合某一规律或规则,根据需求的不同,可能是校验整个源字符串,也可能只是校验其中一个子串。

验证在.NET中一般有两种应用,一种是在验证控件RegularExpressionValidator中,另一种是在程序中。

    Regexp.escape/quote (string) :
对正则表达式中的特殊字符进行转义。如:

匹配 127.0.0.1 | 255.255.255.0 | 192.168.0.1

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代码来实现,也是很简单的。

 

不匹配 1200.5.4.3 | abc.def.ghi.jkl | 255.foo.bar.1

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

*/

Regexp.escape(‘\\*?{}.’)   #=> \\\\\*\?\图片 1{\}\.  
图片 2

正则表达式

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

提取主要是从源字符串中,取得一个或多个符合某一规律或规则的子串。一般来说,在字符串处理中,提取应用比较广泛。提取时用得比较多的是Match()和Matches()方法,以及结果处理时Match类和MatchCollection类的一些方法,有时也会用到Capture类的一些方法。

 rxp.match (str) : 返回一个表示匹配结果的MatchData
对象。如果没有匹配则返回nil

^((0|1[0-9]{0,2}|2[0-9]{0,1}|2[0-4][0-9]|25[0-5]|[3-9][0-9]{0,1})\.){3}(0|1[0-9]{0,2}|2[0-9]{0,1}|2[0-4][0-9]|25[0-5]|[3-9][0-9]{0,1})(?(\/)\/([0-9]|[1-2][0-9]|3[0-2])|)$

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

测试一

*/

这两种方法获取的结果都是一样的,使用哪一种,通常根据个人习惯而定。

 

匹配 192.168.0.1 | 192.168.0.1/32 | 255.255.0.0/1

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

 

不匹配 010.0.0.0 | 192.168.0.1/33 | 256.0.1.55

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()方法,在一些替换规则复杂的应用场景中,也可能会用到委托方法。

1str = “a123b456c789”  
2refs = /(a\d+)(b\d+)(c\d+)/.match(str)   
3puts refs[0]   # “a123b456c789”    
4puts refs[1,3]  # [“a123″,”b456″,”c789”]   
5refs.to_a.each {x| x}   # MatchData对象不是数组,在进行迭代前要调用to_a方法将其转换为一个数组。 

^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9]{1,2})){3}$

2.3.1  一般替换

替换的目的很明确,只要找出待替换子串的规律,替换为目标子串就可以了。

举例1

源字符串:<img
src=”/imgs/logo.jpg”> abc <img
src=”;

需求:将相对地址替换为绝对地址,已经是绝对地址的不替换。

string
test = “<img
src=\”/imgs/logo.jpg\”> abc <img
src=\”;”;

Regex
reg = new Regex(@”(?i)(?<=src=([‘””]?))(?!)”);

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

/*——–输出——–

<img
src=”; abc <img
src=”;

*/

这里需要说明的是,在.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处匹配成功或失败后,将不再对其它位置进行尝试匹配。

 

匹配 97.67.44.20 | 199.154.37.214 | 127.0.0.1

2.3.2  替换中的委托方法应用

对于一些比较复杂的替换规则,可能会用到委托方法,由于这种应用属于比较典型的一种应用,所以将在后面的文章中单独进行介绍。

 也可以使用全局变量$1,$2等引用匹配结果:

不匹配 63.125.94.287 | 140.370.a.187 | 94.923.1

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

*/

refs = /(a\d+)(b\d+)(c\d+)/.match(“a123b456c789”)   
puts “‘#$1′,’#$2’,’$3′”  # ‘a123′,’b456′,’c789’  

正则表达式
/^(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5])\/(\d{1}|[0-2]{1}\d{1}|3[0-2])$/

3       扩展应用

这里介绍一些可能涉及到的一些.NET中的正则扩展应用。

 

匹配 192.168.100.1/24 | 0.0.0.0/0

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()方法转义后,就可以得到正确的结果,而不会抛异常了。

在sub、gsub等方法中,
不能使用$1等来引用结果,因为这些参数在调用方法前就已经计算好。这时,可以采用特殊编码\1,\2等:

不匹配 192.168.100.1/33 | 0.0.0.0/90

3.2     静态方法

.NET中一些Regex类的常见方法都提供了相应的静态方法,可以不显式的声明Regex对象,而直接调用相应的方法,书写起来更方便,代码更简洁、易读。

比如替换IP地址最后一节为“*”,只需一行代码。

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

静态方法每次调用都会创建一个临时的Regex对象,使用之后释放,所以每次调用静态方法时,都会重新编译,而这将会降低执行效率。因此在循环或是频繁调用的方法中,不适合使用静态方法,而需要进行显式声明Regex对象。

但是对于一些只调用一次,或是对执行效率没有要求的场景下,静态方法则是很不错的选择。

 

 

正则表达式

refs = /(a\d+)(b\d+)(c\d+)/.match(“a123b456c789”)   
 puts “‘#$1′,’#$2’,’$3′”  # ‘a123′,’b456′,’c789’  
 “a123b456c789”.sub(/(a\d+)(b\d+)(c\d+)/, ‘1st=\1, 2nd=\2, 3rd=\3’)   # 1st=a123, 2nd=b456, 3rd=c789   
 “a123b456c789”.sub(/(a\d+)(b\d+)(c\d+)/, “1st=\\1, 2nd=\\2, 3rd=\\3”)   # 1st=a123, 2nd=b456, 3rd=c789   
 # 上面两个sub方法中,第一个使用的是单引号;第二个是双引号,需要使用双语义 

\d+\.\d+\.\d+\.\d+

 

匹配 127.0.0.1 | 255.255.255.0 | 192.168.0.1

 

不匹配 @#.5.4.3 | abc.def.ghi.jkl | 255.foo.bar.1

 

正则表达式

  

^((\d|\d\d|[0-1]\d\d|2[0-4]\d|25[0-5])\.(\d|\d\d|[0-1]\d\d|2[0-4]\d|25[0-5])\.(\d|\d\d|[0-1]\d\d|2[0-4]\d|25[0-5])\.(\d|\d\d|[0-1]\d\d|2[0-4]\d|25[0-5]))$

MatchData对象还有以下一些有用的方法:

匹配 1.198.0.1 | 100.10.0.1 | 200.200.123.123

  1. begin(n) : 返回第n个匹配开头的偏移量

  2. end(n) : 返回第n个匹配结束的偏移量(等于第n+1个匹配的开头偏移量)

  3. offset(n) : 返回一个包含第n个匹配开头和结束偏移量的数组

  4. pre_match : 返回匹配子字符串前面的字符串部分

  5. post_match : 返回匹配子字符串后面的字符串部分

不匹配 ..12.23 | a.23.345 | 400.500.300.300

 

正则表达式

 

^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$

二、一些常用的标记

匹配 0.0.0.0 | 255.255.255.02 | 192.168.0.136

1.  ^ 和 $   : 行或字符串开头/结尾(注意:匹配单行的行头/行尾)。

不匹配 256.1.3.4 | 023.44.33.22 | 10.57.98.23.

 

正则表达式

src = “abc\ndef\nghi”  
/^abc/ =~ src  #0   
/^def/ =~ src   #4   
/def$/ =~ src   #4   
/ghi$/ =~ src  #8  

^(http|https|ftp)\://(((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])|([a-zA-Z0-9_\-\.])+\.(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum|uk|me))((:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\’/\\\+&%\$#\=~])*)$

 

匹配 | |

  1. \A 和 \Z : 整个字符串的开头/末尾或最后的换行符前

不匹配

     \z : 基本同 \Z,但是不能匹配最后的换行符 

正则表达式

  src = “abc\ndef\nghi”  
  /\Aabc/ =~ src  #0   
  /\Adef/ =~ src   #nil   
  /def\Z/ =~ src   #nil   
  /ghi\Z/ =~ src  #8   
  /ghi\z/ =~ src  #8   
  src << “\n”  
  /ghi\Z/ =~ src  #8   
  /ghi\z/ =~ src  #nil 

^(([0-2]*[0-9]+[0-9]+)\.([0-2]*[0-9]+[0-9]+)\.([0-2]*[0-9]+[0-9]+)\.([0-2]*[0-9]+[0-9]+))$

 

匹配 113.173.40.255 | 171.132.248.57 | 79.93.28.178

 

不匹配 189.57.135 | 14.190.193999 | A.N.D.233

  1. \b : 单词边界(在[]外); \B : 非单词边界

正则表达式

 

\b(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5])\b

src = “this is a test”  
src.gsub(/\b/, ‘|’)  # “|this| |is| |a| |test|”   
src.gsub(/\B/, ‘-‘)  # “t-h-i-s i-s a t-e-s-t”  

匹配 217.6.9.89 | 0.0.0.0 | 255.255.255.255

 

不匹配 256.0.0.0 | 0978.3.3.3 | 65.4t.54.3

 

以上所述是小编给大家介绍的ip地址正则表达式匹配方法,希望对大家有所帮助!

  1. {?=} : 正预查
    ,当匹配子字符串sub后面接着的字符串与预查中=号后面的字符串匹配时,sub才匹配成功;{?!}:
    负预查,当匹配子字符串sub后面接着的字符串与预查中=号后面的字符串不匹配时,sub才匹配成功。

您可能感兴趣的文章:

  • 获取外网IP地址的批处理代码
  • 据说是中国国家授时中心的时间服务器IP地址
  • 腾讯与新浪的通过IP地址获取当前地理位置(省份)的接口
  • 一键自动更改本机IP地址BAT执行脚本
    非常好用
  • JS获取计算机mac地址以及IP的实现方法
  • 配置IP地址的批处理代码
  • 总结一些你可能不知道的ip地址

 

/(a\d+)(?=b)(b\d+)(c\d+)/.match(“a123b456c789”)    # [‘a123′,’b456′,’c789’]   
 /(a\d+)(?=c)(b\d+)(c\d+)/.match(“a123b456c789”)    # nil   
 /(a\d+)(?=b)(\d+)(c\d+)/.match(“a123b456c789”)     # nil   
  
 /(a\d+)(?!c)(b\d+)(c\d+)/.match(“a123b456c789”)    # [‘a123′,’b456′,’c789’ 

 

  

  1. () : 子表达式编组; (?:) : 非捕获组

 

refs = /(a\d+)(b\d+)(c\d+)/.match(“a123b456c789”)   
puts “‘#$1′,’#$2’,’$3′”  # ‘a123′,’b456′,’c789’  
  
refs = /(a\d+)(?:b\d+)(c\d+)/.match(“a123b456c789”)   
puts “‘#$1′,’#$2’,’$3′”  # ‘a123′,’c789′,’nil’ 

 

 

6.
字符类:包括在方括号[]中的一组字符,其中每一个子匹配是任意一个字符。

    (1) ^用于字符类的开头时有特殊意义,它对字符列表取反。

    (2)
像.和?之类的元字符在字符类中没有特殊含义,表示自身代表的字符。而\n这样的转义序列仍然有效。

    (3)
连字符-用于字符类的开头或结尾,脱字符^用于字符类的中间时,没有特殊含义,只表示自身;左括号[和右括号]用于字符类中时,也是如此,而且还必须显示进行转义。

 

/[abc]/ =~ “abcd”   #0   
/[^abc]/ =~ “abcd”   #3   
  
/[.?abc]/ =~ “.?”   #0   
  
/[-^\[\]]/ =~ “^” #0  

 

  1. 几个修饰符的介绍

           (1) i    :  正则表达式不区分大小写

           (2) o  :  只执行一次表达式替换

           (3) m   :  多行模式(句点匹配换行)

           (4) x    :  扩展正则表达式(允许空白、注释)

 

三、一些常用正则表达式实例

  1. 匹配IP地址

 

 

num = /\d|[01]?\d\d|2[0-4]\d|25[0-5]/   
ip = /^(#{num}\.){3}#{num}$/   
  
ip =~ ‘192.168.0.50’  # 0   
ip =~ ‘192.168.0.500’  # nil  

 

  1. 匹配email地址

 

before_at = /([a-zA-Z0-9]+(_?[a-zA-Z0-9])+)/   
after_at = /[a-zA-Z]+(-?[a-zA-Z])+(\.[a-zA-Z]+)+/   
email = /^(#{before_at}@#{after_at})$/   
  
email =~ ‘abc_123@xyz.com.cn’ #0   
email =~ ‘abc_123@xyz.com’ #0   
email =~ ‘abc_@xyz.com.cn’ #nil   
email =~ ‘abc_123@xy-z.com.cn’ #0   
email =~ ‘abc_123@xyz-.com.cn’ #nil 

 

 

  1. 匹配时间/日期类型(yyyy.mm.dd hh:mm:ss)

 

 

yyyy = /[1-9]\d\d\d/   
mm = /0?[1-9]|1[12]/   
dd = /0?[1-9]|[12]\d|3[01]/   
hh = /[01]?[1-9]|2[0-4]/   
MM = /[0-5]\d/   
ss = /[0-5]\d/   
date_time = /^(#{yyyy}\.#{mm}\.#{dd}) (#{hh}:#{MM}:#{ss})$/   
  
date_time =~ ‘2008.8.27 22:12:10’  # 0   
date_time =~ ‘2008.8.27 22:12:60’  # nil  

 

 


相关文章