我的.NET生活

活着便精彩!
随笔 - 41, 评论 - 680, 引用 - 66

导航

关于

标签

每月存档

最新留言

广告

介绍一款强大的文档搜索工具——grep

在我的.NET开发过程中,一些来自GNU的非常优秀的自由软件(如Emacsgrep等)自始至终起着至关重要的作用。离开这些工具,我的开发过程将变得异常低效和单调。今天我就为大家介绍一下grep这款强大的搜索工具。请别把它和Google混在一起,grep将把你的文档搜索操作变得快速而高效。

 

Let's go!

 

posted on 2004-02-29 19:06:00 by musicland  评论(6) 阅读(7076)

介绍一款强大的文档搜索工具——grep

在我平时比较喜欢去的网站之中,GNU (http://www.gnu.org)是其中之一。其中的FSF/UNESCO Free Software Directory (http://www.gnu.org/directory/)就像一个深不见底的宝库,蕴藏了无以计数的优秀软件,其中有些软件已经成为我日常开发过程中不可或缺的利器,例如Emacsgrep等,今天我想给大家介绍的就是grep (Global Regular ExPression)——一款极其强大的文档搜索工具。

?

Grep的首页上(http://www.gnu.org/software/grep),关于grep的介绍只有这么简单的一句:

?

Grep searches one or more input files for lines containing a match to a specified pattern. By default, grep prints the matching lines.

?

简单说来,你可以用grep来查找位于某个文件中的某个字符串,并可以控制结果显示。在阅读源代码时,grep几乎是必不可少的工具。通过它你可以非常快速地找到一个大型项目的入口,并能轻松地在海量源代码之间找到你所需的函数或变量。

?

下面我来举个简单的例子:我想查询所有位于当前目录下的.cs文件中的Main,通过grep我可以轻松快速地完成这项任务,命令如下:

?

grep ‘Main’ *.cs

?

我机器上的示例输出结果为:

?

ChineseDemo.cs:??? public static void Main()

RegDemo1.cs:????? static void Main(string[] args)

RegDemo2.cs:??? public static void Main()

RegDemo3.cs:?? ?public static void Main()

?

可见,通过grep真的可以找到相关目录中符合条件的所有文件,并能打印出查询到的字符串所位于的那行内容。如果我只想确定哪些文件含有Main,而不需打印相应行的内容,那么可以使用以下命令:

?

grep –l ‘Main’ *.cs

?

输出结果为:

?

ChineseDemo.cs

RegDemo1.cs

RegDemo2.cs

RegDemo3.cs

?

只有相应的文件名称被显示。

?

在找到了含有Main字符串的几个文件后,我想粗略地查看某一具体文件的里源代码的相关信息,比如查看RegDemo1.cs文件中含有Main这一行的前后三行,相关的命令如下:

?

grep –C 3 ‘Main’ RegDemo1.cs

?

输出结果为:

?

?

class GroupingApp

? {

????? static void Main(string[] args)

????? {

????????? Reg7();

????? }

?

输出结果完全符合我的需求,static void Main(string[] args)这一行前后三行范围内的所有代码被全部打印出来(第一行是空行)。

?

以上的查询字符串没有对查找结果是否为一个完整的单词进行限制,也就是说TheMainMain_Func都会被认定为查询目标。如果我想限定该查询字符串为一个完整单词,那么可以使用\w参数,相关命令如下:

?

grep –w ‘Main’ *.cs

?

结果为:

?

ChineseDemo.cs:??? public static void Main()

RegDemo1.cs:????? static void Main(string[] args)

RegDemo2.cs:??? public static void Main()

RegDemo3.cs:??? public static void Main()

?

注意:Main后面的开始括号不会被grep内嵌的正则表达式处理引擎认定为单词。

?

以上的查询只是基于单个字符串的简单查询,grep最强大之处就是可以直接使用正则表达式,从而可以完成极尽复杂的各种查询操作。比如下面的这个简单命令就是查询所有当前目录下.cs文件中的以arg开头的字符串:

?

grep –e ‘arg[\S]*’ *.cs

?

输出结果为:

?

RegDemo.cs:????? private string arg;

RegDemo.cs:????? public static void Main(string[] args)

RegDemo.cs:????????? foreach(string arg in args)

RegDemo.cs:????????????? Console.WriteLine(arg);

RegDemo1.cs:????? static void Main(string[] args)

?

OK,关于grep的使用方法就先简单介绍到这里。大家如果感兴趣可以到grep的主(http://www.gnu.org/software/grep/)去查找相关文档,也可以到GNU ftp (ftp://ftp.gnu.org/gnu/grep/) 去下载源代码并编译,目前最新版本为2.5。不过,对于大多数Windows开发人员来说,机器上可能并没有相应的make环境,因此可能要换用以下两种方法来实现:

?

1.?????? 安装并配置Cygwin (http://www.cygwin.com),在选择安装组件的时候选中grep即可。安装完成后,记得把\Cygwin\bin目录添加至PATH变量。我所采用的就是这种方法,配置后我可以很方便地在Emacscmd里使用grep

2.?????? 下载并安装第三方厂商为Windows平台开发的grep。目前我所知道的有两款:PowerGREP (http://www.powergrep.com)Windows Grep (http://www.wingrep.com)。这两款工具我并未用过,大家可以查看相应的文档以决定是否使用。

?

posted on 2004-02-29 18:57:00 by musicland  评论(20) 阅读(15552)

Simple & Funny——用正则表达式处理html文档

前面我写出一篇Simple & Funny——My MSDN TV Library后,很多初学.NET的朋友都表示出了浓厚的兴趣,纷纷下载源代码进行学习。我这才意识到,其实走在前面的人应该更多地拿出些时间来为后来者们做点什么。我们每个人在学习的初期都遇到过非常多的困难,当我们把这些困难度过之后,其实还有更多的人在同样地面临着它们,他们是多么渴望能分享一些经验,少走一些弯路呀。

 

出于这一点考虑,我想在近期为初学.NET的朋友们写一系列入门文章。每篇文章都很浅显,针对某一个技术细节展开。文章所采用的实例都是我在实战中遇到的,因此里面所含的讲解也都会是我在实战中反复考虑并总结下来的。希望对大家,特别是.NET初学者们带来帮助!笑脸

 

今天这一篇是我上星期在开发时遇到的一个问题——应用正则表达式来处理html文档。

posted on 2004-02-25 18:50:00 by musicland  评论(3) 阅读(3735)

Simple & Funny——用正则表达式处理html文档

前几天,一位好朋友问我这样一个问题:

?

有一份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,一个不太复杂的正则表达式的应用就讲解到这里了,希望能通过这篇文章带你进入正则表达式的大门。如果你对本文有任何意见或看法,欢迎提出来!笑脸

posted on 2004-02-25 18:32:00 by musicland  评论(26) 阅读(9381)

Simple & Funny——My MSDN TV Library

这几天手头没什么项目,难得轻闲,正好自己机器上下载的MSDN TV视频差不多满600m该刻盘了(硬盘太小),于是就花了一个晚上写了个管理这些文件的可爱的WinForms程序——My MSDN TV Library,用上它以后原本杂乱无章的一堆.wmv文件还真变得井井有条了笑脸

简介请看这里

posted on 2004-02-24 22:51:00 by musicland  评论(1) 阅读(1596)

Simple & Funny——My MSDN TV Library

这几天手头项目做完了,闲来无事,自己写了个简单的WinForms程序My MSDN TV Library玩。

我是个微软MSDN TV的忠实观众,新的一集推出后,我总是赶在第一时间把它的内容下载到本地,然后慢慢细品。时间一长,硬盘里的MSDN TV影像文件就变得杂乱起来,查找起来非常困难。正好最近几个项目做完了非常轻松,于是我便想着写个简单的WinForms项目来管一管这些文件。以下是My MSDN TV Library的运行界面:

1. 显示本地硬盘上的所有MSDN TV文件,同时显示每一文件的具体详情:


2. 单击图像后可调用系统缺省的.wmv播放器播放。

3. 显示MSDN TV网站的RSS:


4. 可在内嵌的浏览器中浏览最新的MSDN TV更新信息


OK,主要功能就是这些。很简单不是吗??最后说一句,My MSDN TV Library是开源的,如果你对它感兴趣,那么请告诉我你的邮件地址,我会把源码发过去的。如果能帮我找一个可用的网络存储空间的话那就更好了!

posted on 2004-02-24 22:36:00 by musicland  评论(100) 阅读(8265)

从弹吉他说起——程序员成长最危险的时刻

从高中开始算到今日,我弹吉他已经有八年了。这期间经历的乐队,参加的演出,写的歌曲,真的都已经记不清楚。我只知道当自己选择了软件开发之后,花在弹吉他上的时间越来越少,几年时间内一直在吃过去的老底,再也没认真、正式地练过琴,甚至有段时间都想把这种爱好放弃了。我想自己可能遇到一个瓶颈了吧。

前天晚上我在MSN上和开心聊天时说,自己感到不知该做点什么了,技术上不知该如何突破,找不到下一个应该学习的方向,甚至找不到开发的热情。我想自己可能遇到一个瓶颈了吧。

记得去年在CSDN上看到一篇题为《程序员成长最危险的时刻》的帖子,里面有一段给我留下的印象特别深,我把它引用在下面:

其实程序员成长最危险的时刻不是在你什么都不懂的时候,而是在你懂了一些的时候。开始的时候,你觉得什么都不懂,于是你天天看书,通宵编程。后来你懂了c了,算法数据结构操作系统在学校也学了,用VC 写程序时你边看MSDN边用MFC,觉得感觉还不错;你用Delphi甚至做了一个个像模像样数据库的项目了。至于COM,你懂了一点点,说起来头头是到,虽然没用过。标准C++嘛,你在大学学过基本的C++,工作时用VC,什么继承,虚函数,const,引用,模板你也都用过了。你也听说过设计模式,用过最简单的单件模式什么的,虽然还有很多你不懂的。有的时候你觉得操作系统很有意思,你还写过些多线程的控制系统的东西。可是现在你反倒觉得你什么都不会了,看这别人用VC 写的大系统,你觉得很写的很好,可是你不知道怎样达到那样的水平。你觉得你有很多的东西都不懂,可是你不知道怎么学得更好,有的时候你对编程序都快没激情了,于是你也跟我一样到了程序员成长最危险的时刻。有些朋友觉得已经可以混到饭吃了,就不再努力,这样就危险了!

在CSDN论坛的汪洋大海中,这是一篇再普通不过的帖子了,然而却是这篇普通的帖子给了我最大的冲击,里面的每句话都仿佛在描述一个过去的我。比如说弹吉他,我曾在大学里以两年的时间和无数次翘课为代价苦练了小林克己的那套教材,在演出时能轻松弹一些诸如Hotel California的曲子,然而后来我却没有继续练下去,多年来站在原来的水平无法前进,甚至技艺渐趋倒退;至于软件开发的情形也大体相似。当我对.NET一无所知的时候拼命地看书写代码,到CSDN上去问问题找答案,后来考下了MCAD/MCSD.NET,又做了几个或大或小的项目,自己感觉对.NET (特别是ASP.NET/XML/C#)掌握得已经很不错了,于是就开始松懈起来,开始止步不前。到了后来,我甚至不愿去CSDN问问题,有了疑问后便去查MS KB,查不到就去Google,再找不到就捡一个自己会的解决方案代替了。如此一来,技术长进也就真的遥不可及了。

OK,从现在开始以这篇文章为警示,放弃一切负担,重拾热情,像初学者一样认认真真地去学。如果您在自己的身上也发现了同样的问题,那么就让我们共勉吧。:)

posted on 2004-02-22 17:12:00 by musicland  评论(16) 阅读(5204)

那是编程的书!

我那四岁的小外甥cc经常会做出些很让我吃惊的事儿。今天在地铁里,对面坐着的一位男青年手里拿着本书看得认真,cc看了眼书皮后大声说:“那是编程的书!”

当时我不在场,姐姐特意记下了那本书的名字,回来后告诉了我,您猜是哪本?

Design Patterns – Elements of Reusable Object-Oriented Software

没错,就是鼎鼎大名的“四人帮”(Gang Of Four)合写的那本传世经典。平时我一直在学的,而且还照着其中的英文原文来教cc英语。cc耳濡目染,竟在地铁里能把这本书认出来,真牛了他了!

对了,今天是cc的生日,happy birthday my dear!

posted on 2004-02-19 00:12:00 by musicland  评论(4) 阅读(1899)

最近写的关于MSBuild的文章

由于不久前才装上了宽带,因此最近才有机会接触.NET Framework v1.2(这儿的好多朋友早已经用起来了),对里面的MSBuild工具产生了浓厚的兴趣。此前我是用NAnt管理生成过程的,用起来一直感觉不错,所以这次用上MSBuild之后还一时有点不适应,特别是两者在语法风格上的差异让我在一段时间内颇感不适。不过现在好多了笑脸

 

为了让自己别忘得太快,同时也想让更多还没接触MSBuild的朋友能了解这款不错的Build工具,我最近陆续写了点东西放在下面,大家有兴趣可以一看,我还会陆续把我所知道的有关MSBuild的一些应用写出来的。

 

MSBuild入门(一)(http://blog.joycode.com/musicland/posts/11833.aspx)

MSBuild入门(二)(http://blog.joycode.com/musicland/posts/12161.aspx)

posted on 2004-02-02 21:07:00 by musicland  评论(6) 阅读(2145)

MSBuild入门(二)

在我上一篇“MSBuild入门”(http://blog.joycode.com/musicland/posts/11833.aspx)中介绍了使用MSBuild生成.NET应用程序的基本方法。通过对该文的学习,想必您已经可以比较灵活地在项目开发中应用MSBuild了,那么从本文开始,我将介绍MSBuild的一项高级操作——自定义Task

?

什么是Task?为什么要自定义Task?

在上一篇文章中,您已经看到了几项Task的应用,其中包括CscMakeDirExec,你可以使用Csc Task来编译C#程序,使用MadeDir Task来创建目录,使用Exec Task来执行任何一项shell命令……可以说,只有这些Task才是MSBuild生成过程中真正执行预定义操作的部分,它们是MSBuild的灵魂所在。

?

由此,您也就不难理解创建属于自己的Task的重要性了——当MSBuild自带的几个Task无法满足您的要求时,您就必须自己开发相应的Task以满足需求,而这篇文章的目的就在于演示如何开发属于自己的MSBuild Task

?

在进行下一步的讲解之前,请您先看下面的这份图示(摘自MSBuild Task Extensibility Specification,作者是AKipman, RGoel, SumedhK)来看清Task的来龙去脉:

通过图示可见,每个Task都是一个继承于Microsoft.Build.Utilities.Task(该类存在于MSBuildUtilities.dll中)的类,而Microsoft.Build.Utilities.Task继承了Microsoft.Build.Framework.ITask(存在于MSBuildFramework.dll)接口,并且实现了Execute方法,该方法将是每一个Task执行不同预定义任务的主体。这样,我们如果想开发自定义的Task就必须遵循上述原则,直接或间接继承ITask接口,同时实现Execute方法。好,让我们来一步步实现吧。

?

Demo

首先我们要创建一个简单的Task——Message,它的用途是把传入的一个字符串显示在Console上,以方便与用户的交互。在NAnt中就有类似的一个名为EchoTask执行同样的任务,在微软提供的几份MSBuild演示资料(请参考我在上一篇文章中给出的链接)也多处用到了Message Task,但在我得到的v1.2.30703.4MSBuild中却意外地漏掉了这个Task,因此就让我们从它开始,演练一下基本的Task创建方法:

?

首先请创建一个继承自Microsoft.Build.Utilities.Task的类。从上面的说明可以看出,我们的Message必须直接或间接继承Microsoft.Build.Framework.ITask接口,而从Microsoft.Build.Utilities.Task类开始继承是个不错的主意。如果你用的是Visual Studio .NET,那么请创建一个C#类库项目,然后增加对目录>\MSBuildFramework.dll目录>\MSBuildUtilities.dll的引用。如果你用的是其它文本编辑器,那么请记得在编译时增加对上述两个dll的引用。

?

下面是Message类代码:

?

using System;

using Microsoft.Build.Framework;

using Microsoft.Build.Utilities;

?

namespace Musicland.Build.Tasks

? {

????? public class Message: Task

????? {

????????? private string _text;

????????? [Required]

????????? public string Text

????????? {

????????????? get {return _text;}

????????????? set {_text=value;}

????????? }

?

????????? public override bool Execute()

????????? {

????????????? Console.WriteLine(Text);

????????????? return true;

????????? }

????? }

? }

?

注意在Text属性定义之上应用了一个[Required]属性,这就要求开发人员在使用Message时必须为Text属性设值,否则MSBuild引擎会报错。在Execute方法内,我们只是简单地把传入的Text属性值打印到控制台上,这也是这个Task的目标所在。

?

OK,把上述代码编译成Message.dll文件,然后把它复制在MSBuild.exe所在目录中(在我机器上是C:\windows\Microsoft.NET\Framework\v1.2.30703\ )。这样就引出了下一个话题——怎样注册Task

?

既然我们把自定义功能放在单独的程序集里(Message.dll),那么怎样保证MSBuild引擎在运行时能找到这个程序集并运行其中的类的方法呢?答案是注册这个Task。根据MSBuild提供的文档表明,至少有两种方法可以用来注册Task:全局和局部。顾名思义,在全局注册的Task可以被所有的项目生成文件使用,也就是说当你注册了一个全局性的Task后可以在每个项目文件中使用到它;相反,局部性注册的Task只能在注册它的那个项目文件里使用,而其它的项目文件是无法访问它的。这样一来,你就可以把那些经常要使用的Task注册在全局范围内方便使用,而偶尔一用的Task则只在局部注册就可以了。

?

上面我们提到的把Message.dll复制到MSBuild.exe所在目录就是全局性注册的一个步骤。接下来请用文本编辑器打开该目录下的Microsoft.BuildTasks文件(关于这一文件的用处请看上一篇文章),在下面增加一行UsingTask

?

???

?

MSBuild在运行时会到这个文件中查找所注册的Task,并确定相应的程序集。所以当我们把上一行代码增加好以后就可以随时随地使用Message Task了。

?

下面就写一个项目生成文件来使用这个Message Task,请在随意一个目录下创建Build.proj文件:

?

?

????????? Text="MSBuild is fun!" />/>

?

?

执行以下命令:

msbuild

?

运行结果:

?

Target "Message" in project "Build.proj"

?? Task "Message"

MSBuild is fun!

?

如果你看到了与上面类似的结果,那么祝贺你成功了。

?

上面介绍的是一个在全局范围内注册的简单的Task,由于ITask接口实现起来非常简单,所以你可以非常自由地发挥你的想象力,按照项目需要创建自定义的TaskMSBuild工具(以及NAnt和其它build工具)引入的初衷就是让用户高度定制生成过程,把原来黑盒般的magic F5演变成一个有创造力且有实效的生成流程,从而满足每一个生成过程的定制需求。

?

OK,今天就介绍到这儿,在下一篇里我会给大家演示一个略为复杂的Task,同时介绍在局部的注册方法。

posted on 2004-02-02 20:46:00 by musicland  评论(2) 阅读(3828)

推荐阅读:Essential Blogging—Selecting and Using Weblog Tools

来自O’Reily,是blogger写给blogger的书。其中的内容与我们的现实生活有些脱节,不过这不怪书本身,我们所使用的文字在blog世界真的是很受限制。

 

以下是书的简介:

 

With weblogs-or "blogs"-exploding all over the Web, the only thing lacking for power users and developers is detailed advice on how choose, install, and run blogging software. Written by leading bloggers, Essential Blogging includes practical advice and insider tips on the features, requirements, and limitations of applications such as Blogger, Radio Userland, Movable Type, and Blosxom. This book will get you up and blogging in no time.

 

书的封面,点击后可以到O’Reily的网站上进一步了解该书:

国内下载地址:

 

ftp://ftp.math.nankai.edu.cn/Ebook/Oreilly/Oreilly.Essential.Blogging.eBook-LiB/

posted on 2004-02-01 10:39:00 by musicland  评论(5) 阅读(1526)

Powered by: Joycode.MVC引擎 0.5.2.0