Archive for category Programming
作为一个命令行偏执狂…
好久没有更新博客了,这次更新的原因是上次贴的Perl脚本查Google字典因为Google关闭字典服务的关系已经不能再用了。
前段时间接触了一个新东西叫XPath,名字听起来挺酷的,于是拿来又折腾了一个脚本出来。这次查的是有道辞典,没有Google的好用,但因为Google字典已经不再提供服务,目前能找到的Google字典服务都是通过Unofficial API实现的,也不知道能用多久,就先这么凑合着用吧。
上图

这次脚本代码还是主要分两部分,一部分是通过LWP::UserAgent抓网页内容,一部分是用HTML::TreeBuilder::XPath分析网页内容提取需要的数据。
- XPath其实是一门用来在XML文档中查找信息的语言,比较简单的说就是他能用一个路径表达式定位到一个XML文档里面的某个(或某几个)标签。因为XHTML借鉴了XML的结构,所以我们也可以用XPath来定位XHTML网页中的某个特定标签(XPath几乎总是能定位到一个正常网页中的特定标签的)。
- 在原来使用的网页解析模块HTML::TokenParser中,所有网页标签都按出现顺序排列,并且标签之间都是并列的关系。但是没有一个Browser DEV tool会用这种结构给开发者展示网页源代码,即便我们写代码时也不会这样写。所以这样并列的结构其实对开发者来说是不直观的,也使得编码复杂了很多。
- 而在XPath的世界里,网页的结构是树型的,每个标签都是这棵树上的结点或叶子,开发者会发现很容易就能找出一个路径通往我们想要的那个标签。不过如果你有Firebug和FireFinder这两个网页开发辅助插件,你会发现用起XPath来更加得心应手。
直接对比下面一个脚本和上一个脚本中网页分析部分的代码,你就能直观的感受到上面提到这两种方法的差别。XPath的详细介绍和语法,请猛击W3school Read the rest of this entry »
SVN导入外部项目到本项目版本库
Posted by twcai in Programming on May 27, 2011
为什么需要导入外部项目到本项目版本库
在项目开发的过程中我们很可能会遇到这种情况:我们手头开发的项目可能要用到其他项目的内容。
最容易想到的办法是从其他项目的版本库里取出那部分内容,拷贝并添加到本项目的版本库中。但如果我们要令其他项目那过来的那部分内容保持最新,就是一个非常繁琐的工作了。
有没有高效的办法
如果本项目的版本库自动取得被引用的外部项目的更新,例如每次”svn update”或者”svn checkout”都可以去外部项目的版本库取得最新的内容,那实在是非常方便。我们可以通过Subversion的外部定义功能来实现这个目的。外部定义是一组本地文件路径和URL的映射,使svn可以取得外部版本库的文件到本地路径。
主要要用到以下几个svn指令
svn propset svn:externals PROJECT_NAME svn propedit svn:externals PROJECT_NAME svn propget svn:externals PROJECT_NAME
前两个指令都可以用来设置对应PROJECT_NAME的svn:externals属性,一般推荐用第二个。svn:externals的属性列表指定项目中模块的相对路径,版本信息和对应的URL。
例如:
third-party/foo svn://example.com/repos/foo third-party/bar -r 1234 svn://example.com/repos/bar
Subversion 1.5及以上的版本也支持以下的格式:
http://example.com/foo third-party/foo
-r 1234 http://example.com/bar third-party/bar
第三个指令则可以查询项目的外部定义的属性列表。
Perl脚本查Google字典
这个Perl脚本其实并不能算我的原创,是师傅Perl帝拿出来分享的。本来拿的是iciba的翻译,我另外改了一个上Google字典拿翻译的版本。
要修改的原因:
1. Google字典的英中字典,有双语解释;
2. Google字典的例句和相关短语这些资源要丰富的多,可以帮助理解单词使用的语境,写英文材料时非常有用;
3. 我习惯用Google字典,我一个G粉。
为什么要用一个脚本查单词?对于命令行控来说,离开当前工作终端,开个网页查单词是很痛苦的事情,他们甚至根本不想让手离开主键盘区!有这样的一个脚本,然后扔进/user/bin/,就不用大费周章的移动手臂了。
这个脚本用LWP::UserAgent抓取网页,HTML::TokeParser解析网页,获取单词的翻译。
脚本实现了一个抓取和解析google字典的类,整体的逻辑在en2chs函数中:
1. 生成网址
2. 用LWP取得结果网页
3. 解析网页
_parse_html找到翻译信息所在的代码块——一个id叫“pr-root”的标签,然后主要的体力活就全都扔给_get_close_mean啦。
要通过html标签来定位自己想要的内容,还真是个蛮累人的事情。但是Chrome的Deveploper Tools让事情简单了很多,实在是让人心神舒畅啊。
Perl中建立一个实例方法的线程
标题有点复杂吧?其实就是新建一个线程,来运行某个对象实例中的特定函数。
一般在Perl中新建一个线程的方法很简单:
- use threads;
- my $th = threads->create( function_ref, parameters );
但是启动一个实例中的函数就不太一样了,因为不能用 \&$object->method 来取得该函数的引用。
因为自己写脚本的时候有用到,于是花了一个下午探索实验。然后发现一个确实可以work的办法:在一个匿名函数中调用该方法。
不过这个做法实在是丑陋,Perl这样灵活的语言,一定可以有更好的办法来解决这种问题。
实验加翻阅Intermediate perl一个下午还是无果,突然Perl帝出现,看了一眼代码后瞬间给出一个非常正规的解决方法。
具体请直接看示例代码:
- package Cat;
- use strict;
- use warnings;
- sub new {
- my $class = shift;
- my $self = {
- hello => 'Miao',
- @_
- };
- return bless $self, $class;
- }
- sub sayhi {
- my $self = shift;
- my $times = shift || 3;
- foreach ( 1 .. $times ) {
- print "$self->{hello}\n";
- sleep 1;
- }
- }
- 1;
- #!/usr/bin/perl
- use strict;
- use warnings;
- use threads;
- use FindBin qw($Bin);
- use lib "$Bin";
- use Cat;
- my $cat = Cat->new( hello => 'meow' );
- # solution 1: works but ugly
- print "\n+++++++ solution 1 +++++++\n";
- my $th1 = threads->create( sub { $cat->sayhi(4); } );
- foreach ( 1 .. 4 ) {
- print "This is main function.\n";
- sleep 1;
- }
- $th1->join;
- # solution 2: more professional
- print "\n+++++++ solution 2 +++++++\n";
- my $th2 = threads->create( \&Cat::sayhi, $cat, 4 );
- foreach ( 1 .. 4 ) {
- print "This is main function.\n";
- sleep 1;
- }
- $th2->join;
- print "\nDemo ends.\n";
Windows多线程笔记
最近手头上的东西终于有了一点小突破,这段时间代码上遇到一些问题,有些困了我蛮久。因为之前根本没接触过Windows下面的SDK,Windows核心编程和MSDN都翻了不少,也没少向集训队的学长请教。把这段时间遇到的几个问题整理下,如果能帮到别人就更好了。
子进程的标准输入输出重定向问题:
没有仔细看MSDN的例子和注释,代码写好后,子进程的标准输入输出还是在父进程的命令行下进行。
主要原因是 CreateProcess 之前, STARTUPINFO 这个结构不仅仅是指定一下hStdInput, hStdOutput这几个句柄就行了,dwFlags 这个变量需要设置为 STARTF_USESTDHANDLES 才能使以上几个句柄有效。CreateProcess 时,bInheritHandles 需要设置为 TRUE。不仅如此,还有一个容易遗忘的细节,就是 CreateFile 时的 LPSECURITY_ATTRIBUTES 也需要设置为TRUE(同样,CreatePipe 的 SECURITY_ATTRIBUTES 结构的 bInheritHandle 也要设置为TRUE)。
ReadFile堵塞问题:
如果父进程和子进程通过匿名管道来通信,且把子进程的标准输入输出重定向到了管道,那么会碰到下面这个问题。当子进程的输出被存在缓冲区内,没有刷新的话,管道中就一直没有数据,这时候如果用ReadFile读取管道中的数据则ReadFile被堵塞,于是父进程也被堵塞。目前我还没找到在不修改子进程代码的情况下解决这个问题的办法。只能用不使用缓冲区的输出函数来解决。
但是如果子进程确实没有输出,那么还是有办法防止父进程被堵塞的,就是事先用 GetFileSize 来检查管道文件容量是否为0。还有一个办法是使用异步I/O来完成通信。
ReadFile读取控制:
如果父进程在一个工作流程中,只需要从子进程发回的信息中读取一行的话,则只让ReadFile读取一个字符的数据,直到碰到换行符为止,Windows下文件的换行符为”\r\n”。










