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

时间:2023-02-03 08:49:43

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

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的文件。

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