Syndim's Blog

谨言,勤思,慎行

使用表达式树解析Lambda表达式

在使用Windows Azure Table Storage的API时,发现其查询API极其坑爹,用过C#的人都喜欢了这样的查询方式: x => x.Name == "test" 但是Windows Azure却没有提供这样的方式,没办法,求人不如求己,自己动手来改造它的API吧。 首先介绍一下什么是表达式树: 表达式树表示树状数据结构的代码,树状结构中的每个节点都是一个表达式,例如一个方法调用或类似 x 其实学过编译原理的话对这个概念应该不陌生,语法处理程序的最终结果是一棵抽象语法树,而表达式树就是类似于抽象语法树的一种结构,不过节点是表达式的元素罢了。 C#中提供了一些类来表示各种表达式,它们的名字都以Expression结尾,例如:BinaryExpression, ConstantExpression等,每个类代表一种表达式类型,这些XXXExpression类都继承于抽象类Expression。 C#提供了另一个类,用于访问表达式树:ExpressionVisitor。这是一个抽象类,有一个核心方法Visit,它接受一个Expression对象,并会根据这个对象的实际表达式类型调用相应的VisitXXX方法。 知道了这些,就可以开始写代码了。 首先,我们需要从ExpressionVisitor类中派生一个类,这里我们把它叫做QueryGenerator: public class QueryGenerator: ExpressionVisotor { } 接下来我们需要覆盖它的一些VisitXXX方法,用来处理特定类型的表达式,例如,我想处理函数调用表达式类型,获取函数调用的结果: protected override Expression VisitMethodCall(MethodCallExpression node) { LambdaExpression<Func<object>> lambda = Expression.Lambda(Expression.Convert(node, typeof(object))); var result = lambda.Compile()(); return ConstantExpression(result); } 最后,写一个公开方法,在其中调用Visit方法,开始遍历表达式树: public ConstantExpression GenerateQuery<T>(LambdaExpression<Predictate<T>> condition) { return Visit(condition.Body); } 之后,就可以使用 new QueryGenerator<TestModel>(x => x.Name = "Test"); 这样的表达式来生成查询字符串了。

Visual C++ 2010 独立编译器

因为vs2012刚发布,还有很多类库(比如Qt)还没有官方支持,并且vs2012编译的程序不能在xp下运行,因此vc2010编译器还是有不少作用的。 故从vs2010 sp1中提取出编译器来,以备不时之需。 压缩包53.7M,解压后586M,包含windows sdk 7.0A,未做精简。 已经用Vim源代码测试,编译通过。 下载地址: http://www.everbox.com/f/t3nPhApxcRN2nDTdbo2wCwpfSF

一个解决Windows下Vundle无法更新Bug的小工具

Vundle是一个非常不错的管理Vim插件的插件(怎么这么别扭…),但是我在使用的时候发现一个问题:Windows下使用BundleInstall!更新会出错,提示“文件名、目录名或卷标语法不正确”,原因是他在调用git命令的时候使用双引号将整行命令用引号括起来了,导致windows命令行无法识别命令。 本来想直接修改Vundle源代码的,但是一来没用过VimScript不知道能不能改成功,二来改了之后在作者Merge之前都会导致Vundle插件本身无法正常更新,于是便写了这么个小工具用来修复Vundle的bug。 使用方法很简单,将BundleUpdate.exe放入Vim73目录下,之后在需要更新插件的时候执行 :!BundleUpdate 就行了。 下载: http://www.everbox.com/f/t2LfiJnuzkv8ewepsGhQpcMaUq

麦库笔记导出工具 for Windows v0.1

麦库是个不错的知识管理工具,Windows下客户端的表现也不错,作为evernote的免费替代还是比较合格的,但是它有个坑爹的地方:笔记不提供导出(貌似Mac版有这个功能)。 Update:好吧,其实是可以导出的,不过导出效果不能让人满意。 花了点时间研究了下,windows客户端的笔记使用sqlite3数据库保存的,花了一下午写了这么个小程序,用于把windows客户端中的笔记导出来。 用法:找到麦库的笔记文件之后直接拖到程序上就好啦~之后会在笔记文件相同的文件夹下产生一个output文件夹,里面就是各个分类的笔记了。 PS:麦库笔记文件一般是 我的文档麦库你的盛大数字ID maiku.db 下载: http://www.everbox.com/f/XJFHoBT3DGYpYUVQAl2T89Effi

再次填坑,重写了GAE上的博客程序

要说这个GAE上的博客,最开始可以追溯到大一的暑假。那时候初学Python,苦于没有地方练手,便写了一个博客跑在GAE上,最初的版本使用svn做版本控制(其实我一直把版本控制作为代码备份来使用的,惭愧。。)。 源代码在此:https://code.google.com/p/simphome/ 现在看看,那时候写的十分丑陋,但是功能倒也还算齐全,之后我对这博客进行了一番大修改,改用mercurial做版本控制。 源代码在此:https://bitbucket.org/Syndim/simple/changeset/c3eacdb246a4 版本控制用的也不熟练,很多临时文件和二进制文件都包含在里面了,不过相比之前已经有了一些进步。 最近,在我希望找到一个能够不受人约束地写文章的地方的时候,我发现可以将GAE重新利用起来,便有了下面这个东西: 源代码在此:https://bitbucket.org/Syndim/simple 此次修改的内容主要有: 修改了Model,使之更加合理化(之前站点设置Model实在有点脑残) 将所有与GAE有关的代码放到model.py中,为今后移植做准备 使用装饰器来精简代码 使用自己的用户系统 后台使用bootstrap重构 写文章使用markdown渲染,而不是之前的bbcode 全新的分页方式 添加的功能有: 用户系统 缓存 “关于我”页面 移除的功能有: 订阅 待添加的功能有: 站点设置 更换模板 导入文章 其他 示例站点:http://simple.syndim.org 欢迎提出宝贵意见。

在Vim中使用omni completion补全Qt

Vim 7.3已经内置了Omni Completion插件,使用Vim开发C++程序可以自动补全。 Qt作为一个C++库,自然也是可以被补全的,不过需要进行一些配置,下面是主要步骤: 配置Vim的C++补全: 在.vimrc文件中加入: au BufNewFile,BufRead,BufEnter *.cpp,*.hpp set omnifunc=omni#cpp#complete#Main 然后安装ctags:http://ctags.sourceforge.net/,并将ctags加入path中(windows)。 接着使用ctags生成Qt的tag: cd ~/.vim/tags ctags -R --sort=yes --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ -f qt4 /usr/include/qt4/ 最后在.vimrc中加入: set tags+=~/.vim/tags/qt4 之后Vim就可以补全Qt了。

配置Visual Studio 2010来编译wxWidgets项目

包含目录: 在 项目属性->配置属性->C/C++->常规->附加包含目录 中添加: Release: C:wxWidgets-2.9.3include C:wxWidgets-2.9.3libvc_libmswu Debug: C:wxWidgets-2.9.3include C:wxWidgets-2.9.3libvc_libmswud 2.静态编译: 在 项目属性->配置属性->C/C++->代码生成->运行库 中 改为: Release: 多线程(/MT) Debug: 多线程调试(/MTd) 3.添加链接包含目录: 在 项目属性->配置属性->链接器->常规->附加库目录 中添加: C:wxWidgets-2.9.3libvc_lib 4.添加连接文件 在 项目属性->配置属性->链接器->输入->附加依赖项 中添加: Release: wxbase29u.lib wxbase29u_net.lib wxbase29u_xml.lib wxexpat.lib wxjpeg.lib wxmsw29u_adv.lib wxmsw29u_aui.lib wxmsw29u_core.lib wxmsw29u_gl.lib wxmsw29u_html.lib wxmsw29u_media.lib wxmsw29u_propgrid.lib wxmsw29u_qa.lib wxmsw29u_ribbon.lib wxmsw29u_richtext.lib wxmsw29u_stc.lib wxmsw29u_xrc.lib wxpng.lib wxregexu.lib wxscintilla.lib wxtiff.lib wxzlib.lib comctl32.lib rpcrt4.lib Debug: wxbase29ud_net.lib wxmsw29ud_html.lib wxbase29ud_xml.lib wxmsw29ud_adv.lib wxmsw29ud_aui.lib wxmsw29ud_gl.lib wxmsw29ud_media.lib wxmsw29ud_propgrid.lib wxmsw29ud_qa.lib wxmsw29ud_ribbon.lib wxmsw29ud_richtext.lib wxmsw29ud_stc.lib wxmsw29ud_xrc.lib wxscintillad.lib wxmsw29ud_core.lib wxbase29ud.lib

使用TeamCity进行ASP.NET MVC3项目的自动化部署

关于如何使用TeamCity进行项目代码检出,编译的文章网络上有很多,但是关于如何进行项目部署,尤其是关于ASP.NET MVC3项目部署的资料却少得可怜。折腾两天后,终于将部署完成,于是记录一下部署的方法: 准备 1 工程的准备 首先要稍微配置一下需要部署的工程,设置部署包的位置和目标IIS上的网站/应用程序名称,如下图: 2 构建(build)服务器的准备 构建服务器上.NET Framework 4和ASP.NET MVC3自然少不了,但是因为这是Web工程,因此仅安装这两个会造成便以失败,如下图: 看出错信息可知是缺少了Visual Studio 2010中的几个文件,需要将VS2010对应目录下的Web和WebApplications两个文件夹复制到构建服务器的相应位置: 除此以外,还需要安装Web deploy,因为我们需要用它来进行上传部署工作。 3 部署服务器的准备 部署服务器上也需要安装Web deploy,注意,不要通过Web Platform Installer安装,使用WebPI安装的话IIS中会缺少一个选项,具体过程可以参照 http://www.troyhunt.com/2010/11/you-deploying-it-wrong-teamcity_24.html 接下来就是TeamCity中的设置 1 创建项目 创建项目在此也不再赘述,详情可以自行谷歌。 2 创建构建配置 自动化部署主要分为三个部分: 1) 构建解决方案,进行单元测试 2) 单元测试通过后对Web项目进行打包 3) 打包完成后执行部署 首先创建构建配置来构建解决方案: 这部分的详细设置可以参考官方文档,在设置完配置文件后保存,返回Add Build Step页面,继续Add build step来添加部署的第二部分: 注意图中空色框部分,这个参数的作用是告诉MSBuild进行项目打包(当然也可以通过将上面的Targets属性设置为Package来实现相同的作用)。在这一步执行完成之后,在配置的目录下会生成用于部署的批处理文件和压缩文件: 生成文件的位置是由项目文件指定的(即由准备的第一步指定)。 保存后继续Add build step。 最后一步用于调用生成的批处理文件执行部署工作: 关于命令行参数的含义: =========================== 必需的标志: -------------------------- /T: 使用“-whatif”标志调用 msdeploy.exe,这将模拟部署。此操作不会部署包,而是创建一个报告,报告当您实际部署包时将发生的情况。 /Y: 不使用“-whatif”标志调用 msdeploy.exe,这会将包部署到当前计算机或目标服务器。在验证通过使用 /T 标志生成的输出之后,请使用 /Y。 注意: 不要在同一条命令中同时使用 /T 和 /Y。 =========================== 可选标志: --------------------------

用Python抓取QQ空间文章(终)

其实上一篇博文就已经将所有抓取工作解决了,这篇主要是抓取后的一点点处理工作(其实也没有处理完,充其量是个半成品)。 上篇说道使用正则表达式来匹配图片地址,不过上次方案有些缺陷,那就是疼迅给每张图片都加了链接,因此直接匹配会得到很多重复的地址,不过没关系,Python里有个很好用的模块:HTMLParser(Python 3是html.parser)。 文档上有个使用的例子: from HTMLParser import HTMLParser class MyHTMLParser(HTMLParser): def handle_starttag(self, tag, attrs): print "Encountered the beginning of a %s tag" % tag def handle_endtag(self, tag): print "Encountered the end of a %s tag" % tag 很明显的,handle_starttag方法在遇到开始标签时会被调用,而handle_endtag会在遇到结束标签时被调用,所以用HTMLParser结合正则表达式来获取图片地址就很方便了: def handle_starttag(self, tag, attrs): if tag == 'img': pattern = u"http://bd*.photo.store.qq.com/[^"]*" #图片地址 prog = re.compile(pattern); imgUrl = re.findall(prog, self.get_starttag_text()) if imgUrl: self.imgList.extend(imgUrl) 当然不是只定义这样一个方法就行了,使用HTMLParser需要创建自己的类,并继承HTMLParser: class PicParser(HTMLParser): 使用时只需要生成一个PicParser对象,并将网页内容作为参数调用其feed方法即可: picParser = PicParser() picParser.feed(self.content) 要找出日志的标题和内容,也可以用HTMLParser进行相似的操作,不赘述,详见源码(当然我写的比较ugly,只是没事用用也懒得改了)。 对于评论,疼迅是以JSON格式直接放在页面底端的:

用Python抓取QQ空间文章(2)

之前写过一篇文章简单说明如何用Python抓取QQ空间的文章,当时的脚本有两个缺陷:1.没有保存日志图片 2.未能获取日志发布时间。 当然原有的脚本还是可以使用的,今天对其进行了修改,改进了上面两个缺陷。 前篇文章说,未能获取日志发布时间的原因是文章是从简版抓取下来的,因此要想获取精确时间,就必须找到完整的日志地址。 在HttpFox的帮助下,地址并不难找: http://b1.cnc.qzone.qq.com/cgi-bin/blognew/blog_output_data?uin=QQ号码&blogid=文章ID 当然前面的二级地址与网络条件有关。这个地址就是真正的日志地址。 只要将上次的脚本进行小幅修改,就可以抓取日志的内容了。 接着要保存图片。 这里只考虑保存在QQ空间相册里的图片,其他图床的情况较复杂,有兴趣的同学可以自行分析。 既然是保存在QQ空间相册中的图片,域名自然是QQ的,但是QQ的图片域名并没有后缀,而是像下面这样: http://b214.photo.store.qq.com/psu?/28499588-e936-4ad1-9d29-8048ecba8c54/TynjoQTxqQWMDDZ43wMDg7x2EemJeXmuQRkFtZ4S7qY!/b/YUAUnX.eAQAAYlIImn99AQAA 上面这个是近期日志的图片地址,下面这个是之前日志的图片地址: http://b210.photo.store.qq.com/http_imgload.cgi?/rurl4_b=d43765322eef1b64785ae3ab1f68a8a7e8f3cd5f08244b76a9981b6e6a62e0f81f601ece0421fac90b29f6c18bb5ea2839f18d666a3069bf880fd98a97d8e857ade443f4479c3719504d07c2033c4ff3e0fcfde6&a=210&b=210 好在腾讯似乎没有做太多的防盗链,也就是说,直接复制上面的地址到浏览器,是可以直接打开的,并且图片的URL只是后面有变化。因此图片地址的正则表达式也就很好写了: http://bd*.photo.store.qq.com/[^"]* 但是因为这个URL是看不出后缀的,因此需要获取MIME类型并判断图片后缀: imgInfo = urllib2.urlopen(image).info() #获取图片信息 这样可以获取图片的所有相关信息,得到的是一个字典类型变量,其中的”Content-Type”项就保存了图片的MIME类型,通过对MIME字符串进行处理,就可以得到图片的后缀。 剩下的就是保存图片的工作了,与保存网页相同,不再赘述。 更新后的代码仍然托管在bitbucket:http://goo.gl/vTNL1。 至此,所有抓取的工作就完成了,剩下的就是对已抓取的内容进行处理,提取日志内容和评论。