前几天,一位好朋友问我这样一个问题:
有一份html文件,里面有很多的网址引用的是相对地址,比如说,需要把它改成绝对地址,例如www.codeproject.com/image/logo.gif />。由于源文件体积不小,因此需要一个快速而且资源占用不大的处理方法。
我当时的第一反应就是使用正则表达式,因为与其它方式,比如说直接处理字符串或者使用XmlReader/XmlWriter等相比,正则表达式的速度和资源占用都是最佳的。因此,仔细考虑之后,我写成了下面的代码:
using System; using System.Text.RegularExpressions; using System.IO; class EvalDemo { public static string GetResult(Match m) { return Regex.Replace(m.Value, @"[/]", @"http://www.codeproject.com/"); } } class Demo { public static void Main() { StreamReader reader=File.OpenText("source.txt"); string source=reader.ReadToEnd(); reader.Close(); string reg=@"href\s*=\s*[""']?/"; string result=Regex.Replace(source, reg, new MatchEvaluator(EvalDemo.GetResult)); Console.WriteLine(result); } }
?
其中,放置在同一目录下的source.txt文件保存有需要修改的html源文件,当然你也可以把它放在其它目录下,或者采用不同的方式来获得,例如通过HttpResponse来获取相含有该文件的流。
在打开该文件并读入内存后,我使用StreamReader.ReadToEnd方法获取了流内容的字符串表示,然后用正则表达式对这一字符串进行操作。也许你会问,直接通过查找把所有的href=”\替换成href=”www.codeproject.com\不可以吗?这样是可以的,但如果html代码变成了href=\那么就无法处理了,另外因为html允许在有效字符间留有空格,所以如果用户在html文件中把代码写成href =? \,那么你也必须把这种情况考虑在内(尽管不太会发生),这样你的string.Replace方法就会变得很复杂,而应用正式表达式来处理这一问题就会简单多了,请看下面这行代码:
string reg=@"href\s*=\s*[""']?/";
如果你此前没接触过正则表达式,那么可能会感到有些复杂。其实只要我把其中各项所代表的内容解释在下面,你就会发现其实正则表达式没什么神秘的:
|
字符 |
含义 |
|
\s |
匹配一个空白字符,比如全角空格、半角空格、制表符等 |
|
* |
表示它前面的项目(\s)可以有零个或多个匹配,也就是说这里既可以没有空格,也可以有多个空格 |
|
[] |
匹配其中的单个字符 |
|
[“”’] |
匹配这两个字符:双引号或者单引号。由于双引号在C#里有特殊含义,因此需要以两个双引号的形式来表示单个双引号 |
|
? |
表示它前面的项目([“”’])可以有一个或多个匹配,与*的用法相似 |
有了上面的解释,再去看那段正则表达式是不是很简单了?其实就是要找一段类似href=”\的字符串,其中可能会含有一些空白字符或可选字符。好了,接着往下看。
string result=Regex.Replace(source, reg, new MatchEvaluator(EvalDemo.GetResult));
这是标准的正则表达式替换操作的用法,其中前两项参数的用意非常明确,而第三项参数比较特殊:在这里创建了一个MatchEvaluator委托的实例,并传入了一个回调方法——EvalDemo.GetResult的地址。为什么要这样设计呢?其实一般的正则表达式替换操作是不需要这样复杂的,你只需指定要替换的源,要替换的字符,以及替换后的字符即可,但在这个示例里情况很特殊——你无法确切获知要被替换的是什么字符!不是吗?可能是href=”\,也可能是href=’\,甚至可能是href?? =??? \,因此你需要通过一个回调函数来处理这个变化多端的字符串,在处理后传回处理结果,例如对于href=”\而言,处理结果将是href=”\www.codeproject.com,而href=’\的处理结果则是href=’\www.codeproject。理解了这一点以后,就请来看看这个简单有趣的回调方法:
class EvalDemo
{
??? public static string GetResult(Match m)
??? {
??????? return Regex.Replace(m.Value, @"[/]", @"http://www.codeproject.com/");
??? }
}
在这里,回调方法其实是自定义的EvalDemo类的静态方法,该方法接受一个Match类实例,通过Match.Value可以获得需要处理的字符串,然后对该字符串加以处理即可。因此,在GetResult方法里,我用了一个最基本的正则表达式替换操作,查找所有需要处理的字符串中的/(斜杠)字符,把它替换成http://www.codeproject.com,然后返回结果。这样,Main中的替换操作便获得了所需的第三个参数,替换操作可以进行了。
最后,为了演示方便,我把最终结果(即修改后的html文件内容)打印到Console上面。你可以自己选择是否打印,或者保存到文件中。
OK,一个不太复杂的正则表达式的应用就讲解到这里了,希望能通过这篇文章带你进入正则表达式的大门。如果你对本文有任何意见或看法,欢迎提出来!![]()
打印 | 张贴于 2004-02-25 18:32:00 | Tag:暂无标签
留言反馈
比如检测E-Mail地址
目前有几家第三方公司(机构)已经做了相关的努力,如MONO、DotGNU等。它们的实现效果各有千秋。
不懂的怎么说win32api了
多跟做这学这点。哈哈
支持支持
有用过的吗?
您说的这一API我的确未曾接触,不过我个人的习惯是尽可能地减少对Win32 API的依赖,因为这是在开发.NET,我会经常把.NET应用拿到Linux下去的。
不过您提的这一点的确很重要,大家如果对跨平台移植不感兴趣的话可以应用pinvoke来调用UrlCombine。
BTW:UrlCombine在哪个dll中?
代码空间只能大家想办法了:(,我没有办法提供给大家的:'(
usersample.joycode.com
大家如有兴趣,请到Johnny Hu所给出地址下载源码:)