转载

打磨程序员的专属利器——文本

打磨程序员的专属利器分三个专题展示--

1.命令行&文件

2.快捷键

3. 文本 (本文)

1. 记笔记

好记性不如烂笔头,对于程序员更是如此。学习某种新语言或者某个库,若事先不记点笔记,几年后再拣起来会非常地慢。

之前自己一直用“为知笔记”,但慢慢发现了几个问题。

a. 这个软件喜欢升级,而每次升级都将界面改得面目全非( 其实现在绝大多数软件都喜欢没事升级 )。我只是想一个简洁的软件界面,只想专注于笔记,而为知的每一次更新后都得花精力在熟悉界面上。

b. 为知的笔记不是文本,这样笔记内容几乎只能用为知才能打开。如果想在ubuntu或者Mac上看,只有期待它出对应的客户端或者用网页查看( 但如果没网时也不能查看本地数据了 )。不过现在我打开wiz的网页版笔记,只能另我大失所望,本人只是想要一个左边是树形控件展示笔记的结构,右边可以显示笔记内容的界面,而wiz网站的在线笔记做得太复杂了。

c. 有时不知是服务器还是网络问题,同步居然出现问题。在家里电脑写的东西, 来到公司后发现居然没有同步过来,fuck !!!!

忍无可忍后,就动了自己实现个笔记软件的想法。最开始是用c#写,笔记保存成.mht格式,用IE控件进行预览,用word进行编辑(这是从wiz中得到的启发)。不过后来也发现不是文本的笔记根本不能跨平台。于是又重写了一遍,用c++实现,下面是软件的界面,很简洁,但完全够自己用了。

打磨程序员的专属利器——文本

这个程序 从底层反锯齿的2d图形库,到界面库,到Markdown的解析,都是自己重新造轮子实现 (虽说在软件界不鼓励重新造轮子,但通过造轮子可以将图形库、界面库理解得更透彻)。由于太过简陋就不发布出来,等过段时间有空了用QT再重写一个相对漂亮点的界面再公布源码和程序。

2. Markdown

上面的笔记中提到了Markdown。《程序员修炼之道》中提到笔记得到文本来记录。最开始本人一直认为“文本”就是“纯文本”,直到在开源软件中发现有.md文件,于是知道了有Markdown这种东东,然后忽然识别到文本也可以做得很漂亮(html,css就是文本)。

Markdown是html的一个子集。可以用少量的标示符就可以构造出漂亮的文本排版。下面简单介绍下Markdown的标示符:

a. 行首的 # 可以指明段落,一个表示第一级,二个表示第二级,以此类推

b. 两行 ``` 之间的内容可以被解析为code格式,就像上图中有灰色背景的区域,这种可以方便放代码。

c. 行首的 * 可以被解析成html的 <li>

d. 用[name](http://www.test.com "test") 这种格式可以指定超链接

e. 用下面的格式可以构造出如下的表格

name | age ---|--- man1 | 45 man2 |2

打磨程序员的专属利器——文本

....

更多Markdown语法可以参数其官网。 反正都挺好学,也比较易用,可以在记笔记时不因格式问题而花太多的精力,让我们专注于内容

3. 备份、同步

有了上面DIY的笔记软件后,对于多地办公、多台电脑办公就得考虑如何同步笔记了。

开始本人是使用金山网盘,但也是因为同步问题,有时真是金山的服务器挂了,导致无法同步。还一个严重的问题,网盘没有像svn,git那样明确的update,commit,pull,push操作,这样在同步时真就会出现问题。然后本人试了几乎所有的网盘,发现在某些情况下100%的情况会出现同步失败的问题。

************************

在写这篇博文时为了再次证实下,于是本人又装了次金山快盘。

新建一个文件夹 ,在这个文件夹下再 新建两个文本文档 ,往其中一个文本文档中随便写点东西,这时去网页版的金山快盘上,就发现真就没有把刚才的东西同步上来。 比吃了蟑螂还恶心 !!!

qq云盘和360网盘以前还可以在Explorer中查看本地数据,但现在只有用它自己的程序来操作本地数据了。

百度云盘同样也有这样问题,没有本地路径。

************************

同样是忍无可忍

开始使用 http://svn.jundie.net/,但由于本人小气,不想花钱买私有项目,只有把自己的笔记弄成开源项目,虽说没什么重要东西,但总感觉不靠谱。

于是找到 git.oschina.net ,并且发现基于git有非常多的服务器,并且都可以免费申请私有项目。于是爱上了git,为了保险,将自己所有的代码都放到git上,当然是私有项目(遥想当年,由于本人折腾电脑、折腾分盘,将大一下刚学程序半年写的vb6俄罗斯方块程序源码弄丢了,多么地心疼啊)~~

于是妈妈再也不用担心代码弄丢了

为了方便在Explorer中访问笔记,可以使用前文介绍的subst命令,将笔记路径映射成一个虚拟磁盘以便访问。 

4. 学习一门文本语言

《程序员修炼之道》中说程序员应该每一年学习一门新语言,我们打个折扣1~2年学习一门新语言。并且非常有必要学习一门文本操作语言,比如Python,Ruby或者是Perl。虽然用C#,java,甚至是c/c++都可以进行文本操作,但编写代码的速度肯定不及脚本语言。

本人最开始学习的是Perl语言。这门语言咋一看觉得不好学——充满了各种奇奇怪怪的符号。不过如果沉下心来将《Perl语言入门》、《Perl语言编程》两本书看完,然后再动手自己写几个实用的小程序,Perl的学习之路基本上就算是毕业了。

下面展示几个本人所写的perl程序。也是比较简陋(本人侧重于实用):

a. ls程序

linux下的ls命令可以将当前路径下的文件、文件夹都显示出来。windows下没有这样的程序,于是本人实现了一个。

打磨程序员的专属利器——文本
  1 use 5.010;   2 use strict;   3 use warnings;   4    5 use Win32::Console;   6 use Win32::Console::ANSI;   7 use Term::ANSIColor;   8 use POSIX();   9   10   11 use utf8;  12 use Encode::Locale;  13   14 binmode STDIN, ":encoding(console_in)";  15 binmode STDOUT, ":encoding(console_out)";  16 binmode STDERR, ":encoding(console_out)";  17   18 sub Main;  19   20 Main @ARGV;  21   22 my $is_dir_show;  23 my $is_file_show;  24   25 my $is_show_size;  26 my $is_sort_by_size;  27   28 my @folds;  29 my @files;  30   31 my $max;  32   33 my $col_count;  34 my $col_width;  35   36 my $con_w;  37 my $con_h;  38   39 sub Help {  40     #system("chcp 936");  41     my $str = "ls 显示当前目录下的文件和文件夹名/n".  42     "默认情况下文件和文件夹都将显示。-f 显示文件   -d 显示文件夹/n".  43     "默认情况下不显示文件和文件夹的大小。   -s 将显示其大小/n".  44     "如果文件名中有中文,则一定要确保控制台的代码页为936,用chcp 936可以改变代码页";  45     print $str;  46 }  47   48 sub IsHelp {  49     foreach (@_) {  50         if (lc($_) eq '?' ||  51         lc($_) eq '/?' ||  52         lc($_) eq '-help' ||  53         lc($_) eq '--help'  54         ) {  55             return 1;  56         }  57     }  58     return 0;  59 }  60   61 #---------------  62 # 判断命令行中是否有-d,如果有则表示显示文件夹  63 #---------------  64 sub IsDir {  65     foreach (@_) {  66         if (lc($_) eq '-d') {  67             return 1;  68         }  69     }  70     return 0;  71 }  72 #---------------  73 # 多年命令行中是否有-f,如果有则表示显示文件  74 #---------------  75 sub IsFild {  76     foreach (@_) {  77         if (lc($_) eq '-f'){  78             return 1;  79         }  80     }  81     return 0;  82 }  83 #---------------  84 # 判断命令行中是否有-s, 如果有则要显示大小  85 #---------------  86 sub IsSize {  87     foreach (@_) {  88         if (lc($_) eq '-s') {  89             return 1;  90         }  91     }  92     return 0;  93 }  94   95 #---------------  96 # 判断命令行是否有-S,如果有则要按照文件大小排序,并且显示文件大小  97 #     即-S包含-s  98 #---------------  99 sub IsSortBySize { 100     foreach (@_) { 101         if ($_ eq '-S') { 102             return 1; 103         } 104     } 105     return 0; 106 } 107 #--------------- 108 # 获取文件夹的大小 109 # par_1: path 110 #--------------- 111 sub GetFoldSize { 112     my $path = shift; 113     my $size = 0; 114  115     if (-d $path) { 116         my $r = opendir(DIR, $path); 117  118         if (!$r) { 119             return 0; 120         } 121  122         my @files = readdir(DIR); 123         closedir(DIR); 124  125         foreach (@files) { 126             next if $_ eq '.' or $_ eq '..'; 127             my $file = "$path//$_"; 128  129             if (-d $file) { 130                 $size += GetFoldSize($file); 131             } else { 132                 my $s = (-s $file); 133                 $size = $size + $s; 134  135             } 136         } 137     } 138     return $size; 139 } 140  141 #--------------- 142 # 将字节数转化为G M K 显示 143 # par_1:byte_size; 144 #--------------- 145 sub ByteToString { 146     my $b = shift; 147     my $k=0; 148     my $m=0; 149     my $g=0; 150  151     if ($b >= 1024) { 152         $k = int($b/1024); 153         $b -= $k * 1024; 154     } 155  156     if ($k >= 1024) { 157         $m = int($k/1024); 158         $k -= $m * 1024; 159     } 160  161     if ($m >= 1024) { 162         $g = int($m/1024); 163         $m -= $g * 1024; 164     } 165  166 #    my $str=""; 167 #    my $temp; 168 #    if ($g != 0) { 169 #        $str .= "$g"."G"; 170 ##        $str .= $temp." "x(6 - length($temp)) ; 171 #    } 172 #    if ($m != 0) { 173 #        $str .= "$m"."M "; 174 ##        $str .= $temp." "x(6 - length($temp)) ; 175 #    } 176 #    if ($k != 0) { 177 #        $str .= "$k"."K "; 178 ##        $str .= $temp." "x(6 - length($temp)) ; 179 #    } 180 #    if ($b != 0) { 181 #        $str .= "$b"."B "; 182 ##        $str .= $temp." "x(6 - length($temp)) ; 183 #    } 184      185     if ($g) { 186         sprintf("%4dG %4dM %4dK %4dB", $g, $m, $k, $b); 187     } elsif ($m) { 188         sprintf("%10dM %4dK %4dB", $m, $k, $b); 189     } elsif ($k) { 190         sprintf("%16dK %4dB", $k, $b); 191     } else { 192         sprintf("%22dB", $b); 193     } 194      195  196 #    if ($str eq "") { 197 #        return "0B"; 198 #    } 199 # 200 #    return $str; 201 } 202  203 #--------------- 204 # 获取数组中最大的字符串长度 205 # par:@_ 数组 206 #--------------- 207 sub MaxLength { 208     my $max = 0; 209  210     foreach (@_) { 211         my $len = length $_; 212         if ($len > $max) { 213             $max = $len; 214         } 215     } 216     return $max; 217 } 218  219 #--------------- 220 # 根据获取的col_count, col_width打印文件和文件夹名 221 # 在没有-s选项中这样显示,只显示文件夹名和文件名 222 # par:@_ 文件或文件夹名数组 223 #--------------- 224 sub PrintFileName { 225     my $c = 0; 226  227     foreach (@_) { 228         my $s = $_; 229         print Encode::decode("gb2312", $s); 230  231         my $len = length $_; 232         my $diff = $col_width - $len -1; #-1 是为了防止窗口宽等于缓冲区宽时引起的空白行问题 233         my $black = " " x $diff; 234         print $black; 235  236         ++$c; 237         if ($c == $col_count) { 238             print "/n"; 239             $c = 0; 240         } 241     } 242 } 243  244 #--------------- 245 # 当不指定显示大小,或者不按大小排序时显示文件 246 #--------------- 247 sub PrintNoSize { 248     my $console = Win32::Console->new(); 249     ($con_w, $con_h) = $console->Size(); 250  251     $col_count = POSIX::floor($con_w / ($max+4)); 252     if ($col_count == 0) { 253         $col_count = 1; 254     } 255     $col_width = POSIX::floor($con_w / $col_count); 256  257     #print "screen_width: $con_w /n"; 258     #print "max_width: $max /n"; 259     #print "col_cout: $col_count/n"; 260     #print "col_width: $col_width /n"; 261  262     if ($is_dir_show && scalar(@folds)) { 263         my $c = $#folds+1; 264         my $s = "文件夹: $c 个/n"; 265         print $s; 266         print color 'bold yellow'; 267         PrintFileName @folds; 268         print color 'reset'; 269         print "/n"; 270     } 271  272     if ($is_file_show && scalar(@files)) { 273         my $c = $#files+1; 274         my $s = "文件: $c 个/n"; 275         print $s; 276         print color 'bold green'; 277         PrintFileName @files; 278         print color 'reset'; 279     } 280 } 281  282 #--------------- 283 # 显示文件或文件夹的大小 284 #--------------- 285 sub PrintBySize { 286      287     my $width = $max + 4; 288      289     if ($is_dir_show) { 290          291         my %hash_dir; 292         foreach (@folds) { 293             $hash_dir{$_} = GetFoldSize($_); 294         } 295          296         my @k; 297         if ($is_sort_by_size) { 298             @k = sort { $hash_dir{$b} <=> $hash_dir{$a} } keys %hash_dir; 299         } else { 300             @k = sort keys %hash_dir; 301         } 302  303         foreach (@k) { 304             print color 'bold yellow'; 305             print $_; 306             print color 'reset'; 307  308             my $len = length $_; 309             my $diff = $width - $len; 310             my $black = " " x $diff; 311             print $black; 312  313             print ByteToString($hash_dir{$_}); 314             print "/n"; 315         } 316     } 317     if ($is_file_show) { 318         my %hash_file; 319          320         foreach (@files) { 321             $hash_file{$_} = -s $_; 322         } 323          324         my @k; 325         if($is_sort_by_size) { 326             @k = sort { $hash_file{$b} <=> $hash_file{$a}} keys %hash_file; 327         } else { 328             @k = sort keys %hash_file; 329         } 330          331         foreach (@k) { 332             print color 'bold green'; 333             print $_; 334             print color 'reset'; 335  336             my $len = length $_; 337             my $diff = $width - $len; 338             my $black = " " x $diff; 339             print $black; 340             print ByteToString($hash_file{$_}); 341             print "/n"; 342         } 343     } 344 } 345  346 sub List { 347     $is_dir_show = IsDir @_; 348     $is_file_show = IsFild @_; 349     $is_show_size = IsSize @_; 350     $is_sort_by_size = IsSortBySize @_; 351  352     #如果即没有指定-f,也没有指定-d,则默认为都显示 353     if (!$is_dir_show && !$is_file_show) { 354         $is_dir_show = 1; 355         $is_file_show = 1; 356     } 357  358     opendir(DIR, '.'); 359     my @file = readdir(DIR); 360     closedir(DIR); 361  362     foreach (@file) { 363         next if $_ eq '.' or $_ eq '..'; 364  365         if (-d $_) { 366             push(@folds, $_); 367  368         } else { 369             push(@files, $_); 370         } 371     } 372  373     my $len1 = MaxLength @folds; 374     my $len2 = MaxLength @files; 375     $max = $len1 > $len2 ? $len1 : $len2; 376  377     if ($is_show_size) { 378         PrintBySize; 379  380     } else { 381         PrintNoSize; 382     } 383  384 } 385  386 sub Test { 387     #$s = "d://1.jpg"; 388     #my $size = GetFoldSize "d://lib"; 389     #print ByteToString $size; 390  391     #print length($str); 392  393 #    opendir(DIR, "e://"); 394 #    my @files = readdir(DIR); 395 #    closedir(DIR); 396  397 #    foreach (@files) { 398 #        print $_, "/n"; 399 #    } 400  401     my $len = -s "D://pagefile.sys"; 402     print "$len /n"; 403     print ByteToString($len) , "/n"; 404 } 405  406 sub Main { 407     if (IsHelp @_) { 408         Help; 409     } else { 410         List @_; 411 #        Test; 412     } 413 }
View Code

将上面的代码保存为ls.pl,放在系统路径中。然后在命令行中就可以用 perl ls.pl  来执行它。如果嫌这个命令太复杂,就想用ls来执行它,可以这样,在系统路径中建立一个ls.bat文件,内容为

@echo off perl e:/Tools/ls.pl %*

这样输入ls时,先执行ls.bat文件,然后在这个文件中再真正执行perl代码(这里指定ls.pl的路径得用绝对路径)。其中 %* 是将 ls后面所有的命令行选项传递给ls.pl。

ls所支持的命令行选项有:

  • ls  -f 只显示文件
  • ls -d 只显示文件夹
  • ls -s 显示文件或文件夹的大小
  • ls -S 按文件大小排序后再显示

b.grep程序

当我们阅读某个开源项目时往往想找一个类名、或者一个变量名在哪些地方使用过,如果这时没有将项目组织用IDE组织起来,想要查找就比较麻烦。在linux下有个grep可以对文本进行搜索,然后本人就用perl写了一个类似grep的程序,可以在文本文件中查找字符串,并且可以指定在特定的文件上查找。

打磨程序员的专属利器——文本
  1 use 5.010;   2 use strict;   3 use warnings;   4 use Cwd;   5    6 use Win32::Console::ANSI;   7 use Term::ANSIColor;   8    9 sub Main;  10 sub MainTest;  11   12 Main @ARGV;  13 #MainTest;  14   15 #--------------  16 # return 返回是否只查看一级目录,bool  17 #--------------  18 sub OnlyLocal {  19     foreach (@_) {  20         if (lc($_) eq '-l') {  21             return 1;  22         }  23     }  24     return 0;  25 }  26   27 #--------------  28 # 获取命令行参数的一般方法  29 # 用法 :GetPar('-f', @_);  30 # return 返回第一个参数后面的字符串  31 #--------------  32 sub GetPar {  33   34     my $next = 0;  35     my $str = $_[0];  36     shift @_;  37     #say @_;  38     foreach (@_) {  39         if ($next) {  40             return $_;      41         }  42         if ($_ =~ //Q$str/i) {  43             $next = 1;  44         }  45     }  46     return '';  47 }  48   49 #--------------------  50 # param 输入的命令行  51 # return 返回 -f后面的值  52 #--------------------  53 sub FileExp {  54   55     my $s = &GetPar('-f', @_);  56     if ($s ne '') {  57         return $s;      58     }      59     return '';  60 }  61   62 #--------------------  63 # return 返回 -t 后面的值  64 #--------------------  65 sub TxtExp {  66     return &GetPar('-t' ,@_);  67 }  68   69 my $is_loc;  70 my $file_exp;  71 my $txt_exp;  72 my $count;  73 my @scan_files;  74   75 #--------------  76 # 用 $txt_exp查找文件中的每一行,返回所有符合条件的行  77 #--------------  78 sub ScanFile {  79     my $file = shift;  80     my @text;  81       82     open(FILE, "$file");  83     while (<FILE>) {  84         if (/$txt_exp/i) {  85             #return 1;  86             push(@text, $_);  87         }  88     }  89     close FILE;  90     #return 0;  91     return @text;  92 }  93   94 sub PrintColor;  95 #--------------  96 # 用不同颜色来突出显示匹配到的文本  97 # par_0@:line_text  98 #--------------  99 sub PrintColor { 100     my $text = shift; 101      102     if ($text =~ /$txt_exp/i) { 103      104         print $`; 105          106         print color 'bold red'; 107         print $&; 108         print color 'reset'; 109          110          111         PrintColor $';   #'为了消除$后面的影响 112          113     } else { 114         print $text; 115     } 116  117 } 118  119 #-------------- 120 # 显示文件信息 121 # par_0: $file 122 # par_1: @text 123 #-------------- 124 sub PrintFile { 125     my $file = shift; 126      127     print color 'bold cyan';  128  129     print "$count  $file/n"; 130     print color 'reset'; 131          132     ++$count; 133     push(@scan_files, $file); 134      135     #现在一个文件中只显示一条信息 136      137     $_[0] =~ s/^/s+|/s+$//g; #去掉前后的空格 138     $_[0] =~ s//s+/ /g; #将多个空格替换成一个空格 139  140     print "    "; 141     PrintColor $_[0]; 142     print color 'reset'; 143     print "/n/n"; 144      145 } 146  147 #-------------- 148 # 查看一级目录中的文件 149 # param: $dir 150 #-------------- 151 sub ScanFold { 152      153     my $dir = shift; 154     opendir(DIR, "$dir"); 155     my @files = readdir(DIR); 156     closedir(DIR); 157      158     foreach (@files) { 159         next if $_ eq '.' or $_ eq '..'; 160         my $file = "$dir//$_"; 161          162         if (-d $file) { 163             if (!$is_loc) { 164                 ScanFold($file); 165             } 166              167         } else { 168              169             my $file_valid = 0; 170              171             #如果文件表达式为空,则判断文件是否为文本文件 172             #否则用文件表达式去匹配 $_ 173             if ($file_exp eq '') { 174                 $file_valid = -T $file; 175             } else { 176                 $file_valid = /$file_exp/i; 177             } 178          179              if ($file_valid) { 180                  181                 if ($txt_exp ne '') { 182                     my @text = &ScanFile($file); 183                      184                     if ($#text >= 0 ) {  # $#text是最后一个数组元素的index 185                         PrintFile($file, @text); 186                     } 187                      188                 } else { 189                     print color 'bold cyan'; 190                     print "$count $file/n"; 191                     print color 'reset'; 192                                          193                     ++$count; 194                     push(@scan_files, $file); 195                 } 196              } 197         } 198          199     } 200 } 201  202 sub isnumeric { 203     my $val = shift; 204     ($val ^ $val) eq '0';     205 } 206  207 sub Scan { 208  209     $is_loc = &OnlyLocal(@_); 210      211     $file_exp = &FileExp(@_); 212     $txt_exp = &TxtExp(@_); 213      214     $count = 0; 215      216     if ($file_exp eq '' && $txt_exp eq '' && $#_==0) { 217         $txt_exp = $_[0]; 218     } 219      220     #print "file_exp:", $file_exp, "/n"; 221     #print "txt_exp:", $txt_exp, "/n"; 222     #print "###============================/n"; 223      224     &ScanFold("."); 225      226     print "如果想打开文件,则输入对应编号按回车/n"; 227      228     my $num = <STDIN>; 229     chomp $num; 230   231     return if $num eq ""; 232          233     if ($num>=0 && $num<=$#scan_files) { 234         my $path = getcwd;    #获取当前路径,用于获取文件的完整路径 235         $path =~ s%/%//%g; #将/替换成/ 236          237         my $file = $scan_files[$num]; 238         $file = substr($file, 1);  #去掉$file前面的. 239         my $f = $path . $file; 240           241         system "OpenInExplorer.exe $f"; 242     }     243      244 } 245  246 sub Main { 247     Scan @_; 248 }
grep

同样为了方便,建立一个grep2.bat文件,其内容为(这里只所有取名为grep2,是因为本人在widnows中装了linux的一些软件后有grep程序了,为了不引起冲突而取名grep2)

@echo off perl e:/Tools/grep.pl %*

grep2 ClassName 查找所有文本文件中的ClassName

grep2 -f file 只查找文件名 (不查找内容)

grep2 -f /.cpp$ -t ClassName 在以.cpp结尾的文件中查找ClassName

c. 从开源代码构建vs项目

分析linux下的开源项目时往往没有IDE的支持,这里想要定位到变量的定义处,或者想查找在哪些地方有使用这个变量就很不方便。于是可以建立一个 不能编译的vs项目 ,将所有源码添加到vs后,仅仅用来浏览代码。但基本上开源项目的结构都非常复杂,子文件夹中包括子文件夹,而vs也只支持批量添加同一个文件夹中的所有文件。如果一个个文件夹手动去添加代码文件,是个非常重复的工作。—— 于是程序的天性,消除重担劳动在此得到体现

如果是建立c/c++项目,其项目拓展名是.vcproj,可以发现它就是一个xml文件。

其包括文件的关键节点如下:

<Files> <Filter Name="app"> <File ReleativePath="./app/about.h"> <File Releativepath="./app/cpp.c"> </Filter> <Files>

知道了这个结构后,就可以用程序自动生成了~~

文本操作,本人依然用Perl !!

打磨程序员的专属利器——文本
 1 #  2 #使用方法:将些文件复制到要建立VS项目的文件夹内,用perl create_vs.pl运行此文件。  3 #           在运行前先vs_pre.txt复制到与create_vs.pl同目录下,这样就可以生成直接生成vcproj文件  4 #  5   6 use Win32::OLE;  7 use warnings;  8 use 5.010;  9  10 use XML::Simple; 11 use XML::DOM; 12  13 #use XML::Tidy; 14 use strict; 15 use Encode; 16  17 sub addFile; 18  19 my $parser = new XML::DOM::Parser; 20 my $doc    = $parser->parse('<Files/>'); 21  22 #addFile( 2, 4 ); 23 addFile( $doc->getDocumentElement(), '.' ); 24 $doc->printToFile('file.xml'); 25 $doc->dispose; 26  27 open file_out, ">temp.vcproj"; 28 open file_in1, "vs_pre.txt"; 29 open file_in2, "file.xml"; 30  31 while(<file_in1>) { 32     chomp($_); 33     say file_out $_; 34 } 35 while(<file_in2>) { 36     chomp($_); 37     say file_out $_; 38 } 39 my $end ="     <Globals> 40     </Globals> 41 </VisualStudioProject>"; 42 say file_out $end; 43  44  45 #下面的格式正则代码有问题 46 #my $tidy = XML::Tidy->new( 'filename' => 'file.xml' ); 47 #$tidy->tidy(); 48 #$tidy->write(); 49  50 sub addFile { 51     my $node = shift; 52     my $path = shift; 53  54     opendir( DIR, "$path" ); 55     my @file = readdir(DIR); 56     closedir(DIR); 57     foreach (@file) { 58         next if $_ eq '.' or $_ eq '..'; 59         my $file = "$path//$_"; 60         if ( -d $file ) { 61  62             #print $file,"/n"; 63             my $n = $doc->createElement('Filter'); 64             my $att = $doc->createAttribute( 'Name', $_ ); 65             $n->setAttributeNode($att); 66             $node->appendChild($n); 67             addFile( $n, $file ); 68         } 69         else { 70             my $s = substr( $file, rindex( $file, "." ) ); 71             print $s,"/n"; 72             #只添加h,c文件 73             if ( $s ~~ /[h|hpp|cpp]/) { 74                 my $n = $doc->createElement('File'); 75                 my $att = $doc->createAttribute( 'RelativePath', $file ); 76                 $n->setAttributeNode($att); 77                 $node->appendChild($n); 78             } 79  80         } 81     } 82     #如果这个节点上没有子节点,则将其去掉 83     if ( !$node->hasChildNodes() ) { 84         $node->getParentNode()->removeChild($node); 85     } 86 }
create.pl
打磨程序员的专属利器——文本
<?xml version="1.0" encoding="gb2312"?> <VisualStudioProject  ProjectType="Visual C++"  Version="9.00"  Name="coreutils"  ProjectGUID="{D5524811-7F7F-49A7-80E0-85645B1D2B68}"  RootNamespace="coreutils"  Keyword="Win32Proj"  TargetFrameworkVersion="196613"  >  <Platforms>   <Platform    Name="Win32"   />  </Platforms>  <ToolFiles>  </ToolFiles>  <Configurations>   <Configuration    Name="Debug|Win32"    OutputDirectory="$(SolutionDir)$(ConfigurationName)"    IntermediateDirectory="$(ConfigurationName)"    ConfigurationType="1"    CharacterSet="1"    >    <Tool     Name="VCPreBuildEventTool"    />    <Tool     Name="VCCustomBuildTool"    />    <Tool     Name="VCXMLDataGeneratorTool"    />    <Tool     Name="VCWebServiceProxyGeneratorTool"    />    <Tool     Name="VCMIDLTool"    />    <Tool     Name="VCCLCompilerTool"     Optimization="0"     PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"     MinimalRebuild="true"     BasicRuntimeChecks="3"     RuntimeLibrary="3"     UsePrecompiledHeader="2"     WarningLevel="3"     DebugInformationFormat="4"    />    <Tool     Name="VCManagedResourceCompilerTool"    />    <Tool     Name="VCResourceCompilerTool"    />    <Tool     Name="VCPreLinkEventTool"    />    <Tool     Name="VCLinkerTool"     LinkIncremental="2"     GenerateDebugInformation="true"     SubSystem="1"     TargetMachine="1"    />    <Tool     Name="VCALinkTool"    />    <Tool     Name="VCManifestTool"    />    <Tool     Name="VCXDCMakeTool"    />    <Tool     Name="VCBscMakeTool"    />    <Tool     Name="VCFxCopTool"    />    <Tool     Name="VCAppVerifierTool"    />    <Tool     Name="VCPostBuildEventTool"    />   </Configuration>   <Configuration    Name="Release|Win32"    OutputDirectory="$(SolutionDir)$(ConfigurationName)"    IntermediateDirectory="$(ConfigurationName)"    ConfigurationType="1"    CharacterSet="1"    WholeProgramOptimization="1"    >    <Tool     Name="VCPreBuildEventTool"    />    <Tool     Name="VCCustomBuildTool"    />    <Tool     Name="VCXMLDataGeneratorTool"    />    <Tool     Name="VCWebServiceProxyGeneratorTool"    />    <Tool     Name="VCMIDLTool"    />    <Tool     Name="VCCLCompilerTool"     Optimization="2"     EnableIntrinsicFunctions="true"     PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"     RuntimeLibrary="2"     EnableFunctionLevelLinking="true"     UsePrecompiledHeader="2"     WarningLevel="3"     DebugInformationFormat="3"    />    <Tool     Name="VCManagedResourceCompilerTool"    />    <Tool     Name="VCResourceCompilerTool"    />    <Tool     Name="VCPreLinkEventTool"    />    <Tool     Name="VCLinkerTool"     LinkIncremental="1"     GenerateDebugInformation="true"     SubSystem="1"     OptimizeReferences="2"     EnableCOMDATFolding="2"     TargetMachine="1"    />    <Tool     Name="VCALinkTool"    />    <Tool     Name="VCManifestTool"    />    <Tool     Name="VCXDCMakeTool"    />    <Tool     Name="VCBscMakeTool"    />    <Tool     Name="VCFxCopTool"    />    <Tool     Name="VCAppVerifierTool"    />    <Tool     Name="VCPostBuildEventTool"    />   </Configuration>  </Configurations>  <References>  </References> 
vs_pre.txt

将create.pl vs_pre.txt得到到需要构建项目的地方,然后执行perl create.pl,这样就会生成一个temp.vcproj的项目,其中就包括了这相目录所所有的.h, .hpp, .cpp文件,在create.pl 的73行可以指定添加文件的类型。

之前本人 分析gimp和ffmpeg的源码就是用这种方法建立了vs项目,然后就极大地提高了分析代码的效率

如果以后有心情了,分析linux系统源码时也会用这种方式来构建项目。

d. git项目的批量pull, push

自从爱上了git.oschina.net后,将所有代码都放到git的私有项目中。c++代码都放在本地的 e:/cpp_app/ 文件夹下

打磨程序员的专属利器——文本

如图所示,左下角有小绿圆圈的标志都是有提交git的项目。

这么多项目,如果一个个手动地进入文件夹然后pull,push,非常繁琐。

于是先建立下面的git_syn.pl文件

 1 my $one = $ARGV[0];  2 my $path = "e://cpp_app//";  3 opendir(DIR, $path);  4 my @files = readdir(DIR);  5   6 foreach (@files) {  7     next if $_ eq '.' or $_ eq '..';  8           9     my $str = $path . $_ . "//" . ".git"; 10     if (-d $str) { 11         my $s = $path . $_; 12  13         say "/n/n=============== now directory : $s"; 14         chdir $s; 15  16         if ($one == 0) { 17             system "git add ."; 18             system "git commit -a"; 19             system "git push"; 20         } elsif ($one == 1) { 21             system "git pull"; 22         } 23     } 24 }

建立pull.bat文件

1 echo off 2 perl git_syn.pl 1 3 pause

建立push.bat文件

1 echo off 2 perl git_syn.pl 0 3 pause

git_syn.pl遍历e:/cpp_app文件夹下的所有文件夹,如果发现有.git子文件夹,则根据传入参数判断是push还是pull操作。

有了pull.bat, push.bat后, 妈妈再也不会担心有代码没更新了 。使用svn的项目也这样弄,只要将git 改成svn,pull,push换成update,commit即可。参见《命令行&界面》

5. 正则表达式

个人认为 程序员应该将正则表达式融入自己的血液

如果不沉下心来学习,或者学了后不用,都会出现想使用正则表达式而很茫然的情况。

本人借着学习Perl的机会,将正则表达式重新好好学了一遍,并且在日常的工作中有意识地强迫自己去使用,几个月下来后基本上可以称得上熟练掌握了正则表达式。

下面就介绍几个在vs中用正则表达式进行查找/替换的例子(vs的正则和标准的正则有所不同,不过思想是一样的,只是在表示符号上不所不同):

用如下图所示的方法打开vs的正则表达式查找、替换功能:

打磨程序员的专属利器——文本

  • 查找被注释掉的代码   .*//.*GetTickCount
  • 将for,if, while后面的 { 放在与其同一行。查找部分为  ^{:b*[for|if|while].*[^/{]}/n:b*/{  替换为 /1{
  • 给所有逗号后面都加上一个空格。查找部分为 ,{[^ ]} ,替换为 , /1

其中{}表示分组(相当于标准正则中的()),[]表示一类字符集(相当于标准正则中的{})

关于正则表达式的具体使用情况还有很多,结合上面介绍的grep2,可以用 /.cpp$ 来查找所有后缀是cpp的文件。

总之,学习正则表达式的回报会随着时间的累积越来越多,随着对其掌握的熟练程序而越来越多。

正文到此结束
Loading...