首页 > 代码库 > 正则表达式替换和不包含指定字符串

正则表达式替换和不包含指定字符串

需求

展示一段文字,段落中有些特殊标记的人名、刊名等,格式大体是:“(作者《刊名》其他)”,某个字段可以为空,比如作者为空。

那么对应的正则大体是这样的   ‘\((.*?)《(.*?)》.*?\)‘   

最终的效果是 “(<a>作者</a>《<a>刊名</a>》其他)”

第一版

 1 class Program 2     { 3         static string str = @"<p>[例]当夫广州之首难,武汉兴师,革命精神,震铄一世。(《东方杂志》1912年第9卷第1号)|欲去此不平等与压制,继政治革命而谋社会革命者,社会主义是也。(《青年杂志》1915年第1卷第1号)|俄、德等国的劳工社会,首先看破他们的野心,不惜在大战的时候,起了社会革命,防遏这资本家政府的战争。(李大钊《庶民的胜利》1918年)|近年来文学革命的运动渐见功效,除了几个讲“纲常名教”的经学家。(周作人《思想革命》1919年)</p><p>[按] “革命”本指实施变革以应天命。“革命”现在经常指各个领域的新的改革,推动事物发生根本变革,引起事物从旧质变为新质的飞跃。<p>"; 4          5         static string pattern = @"\((?<author>[^<>]*?)《(?<bookname>[^<>]*?)》.*?\)"; 6  7         static void Main(string[] args) 8         { 9             Regex regex = new Regex(pattern);10             while (regex.IsMatch(str))11             {12                 Match match = regex.Match(str);13 14                 string author = match.Groups["author"].Value;15                 string bookname = match.Groups["bookname"].Value;16                 if (author + "" != "")17                 {18                    str = str.Replace(author, string.Format("<a href=http://www.mamicode.com/‘#‘>{0}", author));19                 }20                 if (bookname + "" != "")21                 {22                     str = str.Replace(bookname, string.Format("<a href=http://www.mamicode.com/‘#‘>{0}", bookname));23                 }24             }25             Console.WriteLine(str);26         }27     }

这里使用了命名分组的匹配方式,之前有一篇写过相关东西,点击正则表达式分组小记查看

static string pattern = @"\((?<author>[^<>]*?)《(?<bookname>[^<>]*?)》.*?\)"; 

获取作者、刊名信息时,排除标签(‘<’和‘>’),效果还是可以的。

<p>[例]当夫广州之首难,武汉兴师,革命精神,震铄一世。(《<a href=http://www.mamicode.com/‘#‘>东方杂志》1912年第9卷第1号)|欲去此不平等与压制,继政治革命而谋社会革命者,社会主义是也。(<a href=http://www.mamicode.com/‘#‘>青年杂志1915年第1卷第1号)|俄、德等国的劳工社会,首先看破他们的野心,不惜在大战的时候,起了社会革命,防遏这资本家政府的战争。(<a href=http://www.mamicode.com/‘#‘>李大钊>1918年)|近年来文学革命的运动渐见功效,除了几个讲“纲常名教”的经学家。(<a href=http://www.mamicode.com/‘#‘>周作人《思想革命1919年)</p><p>[按] “革命”本指实施变革以应天命。“革命”现在经常指各个领域的新的改革,推动事物发生根本变革,引起事物从旧质变为新质的飞跃。<p>

当然没必要这样一次次循环替换,因为正则表达式替换可以一次帮你搞定。

至于这样做的目的,可以把不符合该正则表达式的作者名或者书名的内容一起替换为链接。而且最重要的是,可以针对每一次匹配值,可以做不同的处理。

比如通过匹配的作者或者书名再去数据库查找匹配的作者(或书名)的介绍(或者ID),然后添加到a标签的链接内(例如<a href=http://www.mamicode.com/‘这里的链接是东方杂志的ID‘>东方杂志</a>)

再比如为空的匹配组,我们可以跳过不进行替换,下边的正则表达式替换版本,便无法做到这点了。

正则表达式替换版本

 1 class Program 2     { 3         static string str = @"<p>[例]当夫广州之首难,武汉兴师,革命精神,震铄一世。(《东方杂志》1912年第9卷第1号)|欲去此不平等与压制,继政治革命而谋社会革命者,社会主义是也。(《青年杂志》1915年第1卷第1号)|俄、德等国的劳工社会,首先看破他们的野心,不惜在大战的时候,起了社会革命,防遏这资本家政府的战争。(李大钊《庶民的胜利》1918年)|近年来文学革命的运动渐见功效,除了几个讲“纲常名教”的经学家。(周作人《思想革命》1919年)</p><p>[按] “革命”本指实施变革以应天命。“革命”现在经常指各个领域的新的改革,推动事物发生根本变革,引起事物从旧质变为新质的飞跃。<p>"; 4          5         static string pattern = @"\((?<author>[^<>]*?)《(?<bookname>[^<>]*?)》(?<other>.*?)\)"; 
6
7 static void Main(string[] args) 8 { 9 str = Regex.Replace(str, pattern, "(<a href=http://www.mamicode.com/‘#‘>$1《$2》$3)");10 Console.WriteLine(str);11 }12 }

最后的效果如下,也还不错。

<p>[例]当夫广州之首难,武汉兴师,革命精神,震铄一世。(<a href=http://www.mamicode.com/‘#‘>《<a href=http://www.mamicode.com/‘>|欲去此不平等与压制,继政治革命而谋社会革命者,社会主义是也。(<a href=http://www.mamicode.com/‘#‘>《<a href=http://www.mamicode.com/‘#‘>青年杂志》1915年第1卷第1号)|俄、德等国的劳工社会,首先看破他们的野心,不惜在大战的时候,起了社会革命,防遏这资本家政府的战争。(<a href=http://www.mamicode.com/‘#‘>李大钊《庶民的胜利》1918年)|近年来文学革命的运动渐见功效,除了几个讲“纲常名教”的经学家。(<a href=http://www.mamicode.com/‘#‘>周作人《></p><p>[按] “革命”本指实施变革以应天命。“革命”现在经常指各个领域的新的改革,推动事物发生根本变革,引起事物从旧质变为新质的飞跃。<p>

这里用到了$n的东东,也是现查现用。

我理解的很简单,正则中使用了分组,而$n就是对应每个分组的匹配值,$0是整个正则匹配的结果,$1$2……是每个分组按前后顺序的匹配结果。

结果中标蓝的内容印证了为空匹配组也被替换的结果。

第二版

到目前为止,我们的程序没啥问题,但是数据是变化。看下边这个实例

 1 class Program 2     { 3         static string str = @"<p>[例]当夫广州之首难,武汉兴师,革命精神,震铄一世。(《东方杂志》1912年第9卷第1号)|欲去此不平等与压制,继政治革命而谋社会革命者,社会主义是也。(《青年杂志》1915年第1卷第1号)|俄、德等国的劳工社会,首先看破他们的野心,不惜在大战的时候,起了社会革命,防遏这资本家政府的战争。(李大钊《庶民的<font color=‘red‘>胜利</font>》1918年)|近年来文学革命的运动渐见功效,除了几个讲“纲常名教”的经学家。(周作人《思想革命》1919年)</p><p>[按] “革命”本指实施变革以应天命。“革命”现在经常指各个领域的新的改革,推动事物发生根本变革,引起事物从旧质变为新质的飞跃。<p>"; 4  5         static string pattern = @"\((?<author>[^<>]*?)《(?<bookname>[^<>]*?)》(?<other>.*?)\)"; 6  7         static void Main(string[] args) 8         { 9             str = Regex.Replace(str, pattern, "(<a href=http://www.mamicode.com/‘#‘>$1《$2》$3)");10             Console.WriteLine(str);11         }12       13     }

结果如下

<p>[例]当夫广州之首难,武汉兴师,革命精神,震铄一世。(<a href=http://www.mamicode.com/#></a>《<a href=http://www.mamicode.com/#‘>东方杂志</a>》1912年第9卷第1号)|欲去此不平等与压制,继政治革命而谋社会革命者,社会主义是也。(<a href=http://www.mamicode.com/#></a>《<a href=http://www.mamicode.com/#>青年杂志</a>》1915年第1卷第1号)|俄、德等国的劳工社会,首先看破他们的野心,不惜在大战的时候,起了社会革命,防遏这资本家政府的战争。(李大钊《庶民的<font color=‘red‘>胜利</font>》1918年)|近年来文学革命的运动渐见功效,除了几个讲“纲常名教”的经学家。(<a href=http://www.mamicode.com/#>周作人</a>《<a href=#>思想革命</a>》1919年)</p><p>[按] “革命”本指实施变革以应天命。“革命”现在经常指各个领域的新的改革,推动事物发生根本变革,引起事物从旧质变为新质的飞跃。<p>

标红的部分没有加上链接,当然看我们的正则,就会知道因为包含‘<‘和‘>‘标签,所以匹配失败了。

修改我们的正则,只排出a标签即可,如下

static string pattern = @"\((?<author>(?!.*?<\s*a).*?)《(?<bookname>(?!.*?<\s*a).*?)》(?<other>.*?)\)";

这个正则(author和bookname分组)的意思是 任意字符(.*?)的开头,后边不跟(?!)着<a(中间可以有空格),最后边是任意字符(.*?)结尾

我是参考这里,了解(?!)的用法。

运行效果如下:

<p>[例]当夫广州之首难,武汉兴师,革命精神,震铄一世。(<a href=http://www.mamicode.com/#></a>《<a href=http://www.mamicode.com/#‘>东方杂志</a>》1912年第9卷第1号)|欲去此不平等与压制,继政治革命而谋社会革命者,社会主义是也。(<a href=http://www.mamicode.com/#></a>《<a href=http://www.mamicode.com/#>青年杂志</a>》1915年第1卷第1号)|俄、德等国的劳工社会,首先看破他们的野心,不惜在大战的时候,起了社会革命,防遏这资本家政府的战争。(<a href=http://www.mamicode.com/‘#‘>李大钊《庶民的胜利》1918年)|近年来文学革命的运动渐见功效,除了几个讲“纲常名教”的经学家。(<a href=http://www.mamicode.com/#>周作人</a>《<a href=http://www.mamicode.com/#>思想革命</a>》1919年)</p><p>[按] “革命”本指实施变革以应天命。“革命”现在经常指各个领域的新的改革,推动事物发生根本变革,引起事物从旧质变为新质的飞跃。<p>

这里,我们就可以给特殊标签的内容添加上链接了。

小结

工作用到的东西,时间久了不用就会忘,及时记录一下。

正则表达式替换很好用,但是如果要针对每一组数据处理完(为空或者取到对应数据)再替换,则需要遍历每一次匹配结果再替换了。