最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【总结】关于(C#和Python中的)正则表达式

RegularExpression crifan 6200浏览 0评论

此贴已移至:正则表达式的通用知识 一些关于正则表达式中的比较


v2012-04-25

此处总结一下,关于正则表达式的相关知识。

此文目的是总结一下正则表达式的基本语法,以及总结个人接触过的一些不同语言的实现中需要注意的地方,以及相关经验。

 

【正则表达式的最简介】

正则表达式,英文叫做Regular Expression,一般缩写为regex或regexp。

正则表达式,简单说,就是一组规则,用于实现字符串的查找,匹配,以实现关于字符串的相关操作,比如替换,删除等。

很多语言目前都已实现了对应的正则表达式的支持。

目前个人已知的有,Python脚本语言,C#语言,PHP语言,Notepad++软件的查找/替换功能中。

学会了正则表达式后,很多常见的文字,字符串的处理,就简单的多了,或者可以更加高效地实现功能,实现更加复杂的操作了。

 

【正则表达式的基本规则】

下面的规则,是从Python的说明文档中翻译过来的。

网上也有类似的总结,此处只是觉得这个解释更全,更精确,所以采用这部分的内容为基准。

其他不同语言所实现的正则表达式,语法上,也许个别会有不同,但是基本语法和含义,都是通用的。

下表,以供借鉴。

 

字符匹配的规则:

特殊字符等价于含义解释提示
. 表示任意字符(除了换行符\n以外的任意单个字符) 
^ 表示字符串的开始 
$ 表示字符串行末或换行符之前 
*{0,无穷多个}0或多个前面出现的正则表达式贪婪原则,即尽量匹配尽可能多个
+{1,无穷多个}1或多个前面出现的正则表达式贪婪原则,即尽量匹配尽可能多个
?{0,1}0或1个前面出现的正则表达式贪婪原则,即尽量匹配尽可能多个
*?,+?,?? 使*,+,?尽可能少的匹配最少原则
{m} 匹配m个前面出现的正则表达式 
{m,n} 匹配最少m个,最多n个前面出现的正则表达式贪婪原则,即尽量匹配尽可能多个
{m,n}? 匹配最少m个,最多n个前面前出现的最少原则
\ 后接那些特殊字符,表示该字符;或者后接已经定义好的特殊含义的序列对于已经定义好的特殊序列,下面会详细解释。
[] 指定所要匹配的字符集,可以列出单个字符;或者是一个字符范围,起始和结束字符之间用短横线-分割; 
| A|B,其中A和B可以是任意正则表达式,其中也支持更多的抑或A|B|C|… 
…… 匹配括号内的字符串实现分组功能,用于后期获得对应不同分组中的字符串

 

已定义的字符序列的含义:

特殊序列/已定义的字符含义等价于含义解释提示
\数字 表示前面用括号()括起来的某个组group 
\A 表示字符串的开始 
\b 匹配空字符,但只是一个单词word的开始或者结束的空字符 
\B\b含义取反匹配空字符,但只是,一个单词word的,除了开始或者结束位置的,的空字符 
\d[0-9]匹配单个数字(0到9中的某个数字) 
\D[0-9]的取反非数字的单个字符,即除了0-9之外的任意单个字符 
\s[ \t\n\r\f\v]匹配单个空白字符,包括空格,水平制表符\t,回车\r,换行\n,换页\f,垂直制表符\v 
\S\s的含义取反匹配非空白字符之外的单个字符 
\w[a-zA-Z0-9_]匹配单个的任何字符,数字,下划线 
\W\w的含义取反匹配单个的,非字母数字下划线之外的字符 
\Z 匹配字符串的末尾 

 

【一些总结和注意事项】

1.关于贪婪原则和最少原则

星号*,加号+,问号?,{m,n},都是属于贪婪原则,即在满足这些条件的情况下,尽可能地匹配多个。

而对应的后面加上一个问号?,变成:

*?, +?, ??, {m,n}?就变成了最少原则,即,在满足前面的条件的情况下,尽量少地匹配。

其中??,个人很少用。

而最常用的是 .+?,表示任意字符,最少是1个,然后后面匹配尽量少的所出现的字符。

 

2.反斜杠\

在正则表达式中,反斜杠\后面接一些特殊字符,表示该特殊字符,这些特殊是,上面所说过的:

.,^,$,*,+,?

对应的是:

\.,\^,\$,\*,\+,\?

以及反斜杠自己:

\\

其中如果是在中括号[]内,反斜杠加上对应的中括号[]和短横线-,即:

\[,\],\-

分别表示对应的字符本身。

 

3.上尖括号^

在中括号之外,表示字符的开始;

在中括号之内,表示取反,比如常见的[^0-9]

比如[^5]表示除了数字5之外的所有字符。

尤其特别的是[^^]表示除了上尖括号字符本身之外的所有字符。

 

4. 中括号内的+,*,(,)

中括号内的加号+,星号*,括号(,)表示对应字符本身,就不是特殊字符了。

 

【正则表达式的特点】

  • 入门相对不难,但是能熟练,高效的利用其功能,还是不容易的。

 

【Python中的正则表达式:re模块】

优点:

1.python中字符串的表示,单引号和双引号,都是支持的。

所以对于字符串中,有双引号的,可以在写字符串最外层用单引号括起来,而不需要用反斜杠了。

反之,如果需要表示的其中包括单引号,那么最外层用双引号,所以,还是很方便的。

2.对于匹配多个字符串的时候,好像不能加括号分组的,如果加括号分组了,那么只能匹配单个一个group就结束了。对应的要匹配多个字符串,好像只能使用findall。

这部分内容,有空再好好总结一下。

 

【C#中的正则表达式:Regex类】

后来找到了,微软官方关于正则表达式知识的介绍,其中就有常用缩写所表示的含义:

Character Classes

 

优点:

1.可以一次性的即搜索多个匹配的整个的字符串,同时又可以一次性地,对于每个字符串,在给定Regex的时候,就分组group,然后得到macthes之后,foreach处理每个match,已经可以得到对应的匹配的结果,可以使用不同group的值了。还是很方便的。

 

注意事项:

1.正则表达式,是用字符串前面加上@字符来表示的。

2.双引号‘“’这个符号的表示是用两个双引号。

由于C#中本身字符串是双引号表示的,所以正则表达式中的双引号,就特殊了,是需要用两个双引号,表示对应的双引号这个字符的,而不是反斜杠加上双引号来表示双引号这个字符,这点,觉得还是很特殊的,需要注意一下。

 

关于C#中的Regex使用心得和注意事项,感兴趣的可以去看:

【总结】C#中的Regex的使用心得和注意事项

 

【C#和Python中关于正则表达式方面的对比】

1. 带名字的group

python和C#中的正则表达式,都支持带名字的group,即named group,关于具体的语法,两者有些微的区别:

Python: (?P<groupName>xxx)

C#: (?<groupName>xxx)

即Python中,named group的语法,比C#中,多了个P字母作为开头。

 

2.正则表达式字符串的开头标记字母

Python:r,比如r“(.+?)”

C#:@,比如@“(.+?)”

 

3.关于引用已捕获的带名字的组(back reference named group)

正则表达式的逻辑中,支持在写模式字符串中,引用前面已经过通过括号括起来的,带名字的组。

Python中的语法是:

(?P=name)

Matches whatever text was matched by the earlier group named name.

C#中的语法是:

(?<name> )
Captures the matched substring into a group name or number name. The string used for name must not contain any punctuation and it cannot begin with a number. You can use single quotes instead of angle brackets; for example, (?'name').

 

直接给出示例代码:

Python中关于引用named group的用法示例(记得要import re;):

#------------------------------------------------------------------------------
def testBackReference():
    # back reference (?P=name) test
    backrefValidStr = '"group":0,"iconType":"NonEmptyDocumentFolder","id":"9A8B8BF501A38A36!601","itemType":32,"name":"released","ownerCid":"9A8B8BF501A38A36"';
    backrefInvalidStr = '"group":0,"iconType":"NonEmptyDocumentFolder","id":"9A8B8BF501A38A36!601","itemType":32,"name":"released","ownerCid":"987654321ABCDEFG"';
    backrefP = r'"group":\d+,"iconType":"\w+","id":"(?P<userId>\w+)!\d+","itemType":\d+,"name":".+?","ownerCid":"(?P=userId)"'
    userId = "";

    foundBackref = re.search(backrefP, backrefValidStr);
    print "foundBackref=",foundBackref; # foundBackref= <_sre.SRE_Match object at 0x02B96660>
    if(foundBackref):
        userId = foundBackref.group("userId");
        print "userId=",userId; # userId= 9A8B8BF501A38A36
        print "can found userId here";

    foundBackref = re.search(backrefP, backrefInvalidStr);
    print "foundBackref=",foundBackref; # foundBackref= None
    if(not foundBackref):
        print "can NOT found userId here";

    return ;


C#关于引用named group的示例代码(记得要using System.Text.RegularExpressions;):

void testBackReference()
{
    // back reference \k<name> test
    string backrefValidStr = "\"group\":0,\"iconType\":\"NonEmptyDocumentFolder\",\"id\":\"9A8B8BF501A38A36!601\",\"itemType\":32,\"name\":\"released\",\"ownerCid\":\"9A8B8BF501A38A36\"";
    string backrefInvalidStr = "\"group\":0,\"iconType\":\"NonEmptyDocumentFolder\",\"id\":\"9A8B8BF501A38A36!601\",\"itemType\":32,\"name\":\"released\",\"ownerCid\":\"987654321ABCDEFG\"";
    string backrefP = @"""group"":\d+,""iconType"":""\w+"",""id"":""(?<userId>\w+)!\d+"",""itemType"":\d+,""name"":"".+?"",""ownerCid"":""\k<userId>""";
    string userId = "";
    Regex backrefValidRx = new Regex(backrefP);
    Match foundBackref;

    foundBackref = backrefValidRx.Match(backrefValidStr);
    if (foundBackref.Success)
    {
        // can found the userId
        userId = foundBackref.Groups["userId"].Value;
        MessageBox.Show("can found the userId !");
    }

    foundBackref = backrefValidRx.Match(backrefInvalidStr);
    if (foundBackref.Success)
    {
        // can NOT found the userId
    }
    else
    {
        MessageBox.Show("can NOT found the userId !");
    }    
}

 

4.关于向前匹配(prev match)和向后匹配(post match),以及向前一定不要匹配(prev non-match),和向后一定不要匹配(post non-match)

 

Python中的语法是:

(?=...)

Matches if ... matches next, but doesn’t consume any of the string. This is called a lookahead assertion. For example, Isaac (?=Asimov) will match 'Isaac ' only if it’s followed by 'Asimov'.(?!...)Matches if ... doesn’t match next. This is a negative lookahead assertion. For example, Isaac (?!Asimov) will match 'Isaac ' only if it’s not followed by 'Asimov'.(?<=...)Matches if the current position in the string is preceded by a match for ... that ends at the current position. This is called a positive lookbehind assertion. (?<=abc)def will find a match in abcdef, since the lookbehind will back up 3 characters and check if the contained pattern matches. The contained pattern must only match strings of some fixed length, meaning that abc or a|b are allowed, but a* and a{3,4} are not. Note that patterns which start with positive lookbehind assertions will never match at the beginning of the string being searched; you will most likely want to use the search() function rather than the match() function:

>>> import re
>>> m = re.search('(?<=abc)def', 'abcdef')
>>> m.group(0)
'def'


This example looks for a word following a hyphen:

>>> m = re.search('(?<=-)\w+', 'spam-egg')
>>> m.group(0)
'egg'

(?<!...)Matches if the current position in the string is not preceded by a match for .... This is called a negative lookbehind assertion. Similar to positive lookbehind assertions, the contained pattern must only match strings of some fixed length. Patterns which start with negative lookbehind assertions may match at the beginning of the string being searched.

 

C#的语法是:

Grouping Constructs

(?= )

Zero-width positive lookahead assertion. Continues match only if the subexpression matches at this position on the right. For example, \w+(?=\d) matches a word followed by a digit, without matching the digit. This construct does not backtrack.

(?! )

Zero-width negative lookahead assertion. Continues match only if the subexpression does not match at this position on the right. For example, \b(?!un)\w+\b matches words that do not begin with un.

(?<= )

Zero-width positive lookbehind assertion. Continues match only if the subexpression matches at this position on the left. For example, (?<=19)99 matches instances of 99 that follow 19. This construct does not backtrack.

(?<! )

Zero-width negative lookbehind assertion. Continues match only if the subexpression does not match at the position on the left.

 

直接给出相关示例代码:

Python中关于前向,后向,匹配,非匹配等的示例代码(记得要import re;):

#------------------------------------------------------------------------------
def testPrevPostMatch():
    # post match:       (?=xxx)
    # post non-match:   (?!xxx)
    # prev match:       (?<=xxx)
    # prev non-match:   (?<!xxx)

    #note that input string is:
    #src=\"http://b101.photo.store.qq.com/psb?/V10ppwxs00XiXU/5dbOIlYaLYVPWOz*1nHYeSFq09Z5rys72RIJszCsWV8!/b/YYUOOzy3HQAAYqsTPjz7HQAA\"
    qqPicUrlStr             = 'src=\\"http://b101.photo.store.qq.com/psb?/V10ppwxs00XiXU/5dbOIlYaLYVPWOz*1nHYeSFq09Z5rys72RIJszCsWV8!/b/YYUOOzy3HQAAYqsTPjz7HQAA\\"';
    qqPicUrlInvalidPrevStr  = '1234567http://b101.photo.store.qq.com/psb?/V10ppwxs00XiXU/5dbOIlYaLYVPWOz*1nHYeSFq09Z5rys72RIJszCsWV8!/b/YYUOOzy3HQAAYqsTPjz7HQAA\\"';
    qqPicUrlInvalidPostStr  = 'src=\\"http://b101.photo.store.qq.com/psb?/V10ppwxs00XiXU/5dbOIlYaLYVPWOz*1nHYeSFq09Z5rys72RIJszCsWV8!/b/YYUOOzy3HQAAYqsTPjz7HQAA123';
    canFindPrevPostP = r'(?<=src=\\")(?P<qqPicUrl>http://.+?\.qq\.com.+?)(?=\\")';
    qqPicUrl = "";

    foundPrevPost = re.search(canFindPrevPostP, qqPicUrlStr);
    print "foundPrevPost=",foundPrevPost; #
    if(foundPrevPost):
        qqPicUrl = foundPrevPost.group("qqPicUrl");
        print "qqPicUrl=",qqPicUrl; # qqPicUrl= http://b101.photo.store.qq.com/psb?/V10ppwxs00XiXU/5dbOIlYaLYVPWOz*1nHYeSFq09Z5rys72RIJszCsWV8!/b/YYUOOzy3HQAAYqsTPjz7HQAA
        print "can found qqPicUrl here";

    foundInvalidPrev = re.search(canFindPrevPostP, qqPicUrlInvalidPrevStr);
    print "foundInvalidPrev=",foundInvalidPrev; # foundInvalidPrev= None
    if(not foundInvalidPrev):
        print "can NOT found qqPicUrl here";

    foundInvalidPost = re.search(canFindPrevPostP, qqPicUrlInvalidPostStr);
    print "foundInvalidPost=",foundInvalidPost; # foundInvalidPost= None
    if(not foundInvalidPost):
        print "can NOT found qqPicUrl here";

    return ;

 

C#中关于前向,后向,匹配,非匹配等的示例代码(记得要using System.Text.RegularExpressions;):

void testPrevPostMatch()
{
    //http://msdn.microsoft.com/en-us/library/bs2twtah(v=vs.71).aspx
    // post match:       (?=xxx)
    // post non-match:   (?!xxx)
    // prev match:       (?<=xxx)
    // prev non-match:   (?<!xxx)

    //src=\"http://b101.photo.store.qq.com/psb?/V10ppwxs00XiXU/5dbOIlYaLYVPWOz*1nHYeSFq09Z5rys72RIJszCsWV8!/b/YYUOOzy3HQAAYqsTPjz7HQAA\"
    string qqPicUrlStr              = "src=\\\"http://b101.photo.store.qq.com/psb?/V10ppwxs00XiXU/5dbOIlYaLYVPWOz*1nHYeSFq09Z5rys72RIJszCsWV8!/b/YYUOOzy3HQAAYqsTPjz7HQAA\\\"";
    string qqPicUrlInvalidPrevStr   = "12345678http://b101.photo.store.qq.com/psb?/V10ppwxs00XiXU/5dbOIlYaLYVPWOz*1nHYeSFq09Z5rys72RIJszCsWV8!/b/YYUOOzy3HQAAYqsTPjz7HQAA\\\"";
    string qqPicUrlInvalidPostStr   = "src=\\\"http://b101.photo.store.qq.com/psb?/V10ppwxs00XiXU/5dbOIlYaLYVPWOz*1nHYeSFq09Z5rys72RIJszCsWV8!/b/YYUOOzy3HQAAYqsTPjz7HQAA1234";
    string canFindPrevPostP = @"(?<=src=\\"")(?<qqPicUrl>http://.+?\.qq\.com.+?)(?=\\"")";
    string qqPicUrl = "";

    Regex prevPostRx = new Regex(canFindPrevPostP);

    Match foundPrevPost = prevPostRx.Match(qqPicUrlStr);
    if (foundPrevPost.Success)
    {
        qqPicUrl = foundPrevPost.Groups["qqPicUrl"].Value;
        MessageBox.Show("can found the qqPicUrl !");
    }

    Match foundInvalidPrev = prevPostRx.Match(qqPicUrlInvalidPrevStr);
    if (!foundInvalidPrev.Success)
    {
        MessageBox.Show("can NOT found the qqPicUrl !");
    }

    Match foundInvalidPost = prevPostRx.Match(qqPicUrlInvalidPostStr);
    if (!foundInvalidPost.Success)
    {
        MessageBox.Show("can NOT found the qqPicUrl !");
    }
}

转载请注明:在路上 » 【总结】关于(C#和Python中的)正则表达式

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

网友最新评论 (1)

    84 queries in 0.247 seconds, using 22.17MB memory