2006年12月27日

Mastering Regular Expressiongs圆括号

圆括号有两种用法

  • 将“或”操作(“|“符号)的两个值括起来,比如(ABC|abc)
  • 将多个字符括起来做为一个整体,使之可以用?、+、* 或{m,n}来限定该整体的匹配次数

反向引用

当被圆括号括住的整体被匹配时,该匹配能够被正则表达式工具记住,并由\1、\2、\3……来引用第一个、第二个、第三个……匹配。例如,本书开篇所讲的那个找出重复单词的例子,可以由如下正则表达式来匹配:

\b([A-Za-z]+)\s+\1\b

其中\b匹配单词边界,\s匹配空格、制表符、换行符等“空白分界”,\1是反向引用,引用的是圆括号括起来的整体匹配。(要点,要使用反向引用,必须要用圆括号将匹配括起来,否则正则表达式无法记住那个匹配)


这本书的第2章,开始简单地介绍了一下Perl,首先是把开篇那个“查找重复单词”问题的解决方案列了出来,一段简短的Perl代码:

00001: $/ = ".\n";00002: while (<>) {00003:     next if !s/\b([a-z]+)((?:\s|<[^>]+>)+)(\1\b)/\e[7m$1\e[m$2\e[7m$3\e[m/ig;00004:     s/^(?:[^\e]*\n)+//mg;00005:     s/^/$ARGV: /mg;00006:     print;00007: }

Perl的一些基础语法是:

  • 变量由$开头,如$celsius
  • 变量的类型可以是数值型或字符型
  • 注释由#开头(可以是单行注释,也可以是行尾注释)
  • 字串常量用双引号括起来,与其它语言(如C)不同的是,用双引号内出现的变量名(由$开头),会被变量的值替换
  • 用print输出
  • Perl命令行的可选参数-w,让Perl使用更高级别的语法检查,并打印警告信息(比如变量未被始化就使用、声明了变量却未使用等)
  • if ($foo =~ m/^\d+$/) 这样的语法是在测试“$foo这个变量的值匹配^\d+$这个正则表达式”的布尔结果。=~这个操作符既不是等于(==),也不是赋值(=),而是“是否匹配”
  • 正则表达式用两个斜杠/字符括起来,前面的m表示匹配操作(可选),如果把m换成s,则表示“替换”

本书第2章简单地介绍了一下Perl,完全任自己的猜想臆断,总结了上面几条,下面是好友Buchi Automata的指正:

严格说,是scalar variable(标量变量?)由$开头。如果是矢量变量,则由@开头。比如@arr = [1, 2, 3, 4]。如果是hash,则用%开头。比如%h = {1=>’a', 2=>’b'}。RE前面的m有它的作用。有了m,我们可以用任何配对的符号表示RE。比如/pattern/ 和 m{pattern} 和m&pattern&都一个意思。

DONEWS与CSDN的BLOG都用的是同一个程序,有评论无法显示的BUG,在首页上能看到评论,但在文章后面看不到(好象过几天就能显示了,很诡异),所以网友指正的评论我干脆贴在原文的后面了

2006年12月26日

BSWAP(Byte Swap)

对一个32位寄存器的字节序进行反转,字节0(位0~7)与字节3(位24~31)进行交换,字节1(位8~15)与字节2(位16~23)进行交换。

该指令通常用于将little-endian(低位在前)与big-endian(高位在前) 格式进行互换(按,比方说IPv4的地址通常用网络序,也就是高位在前的方式表示,但Intel x86平台上32位整型却是低位在前)。

如果要交换16位整型值的两个字节,可以使用XCHG指令,BSWAP不可于16位寄存器。

该指令仅被486及486以后的CPU所支持。

该指令不产生异常,也不影响标志寄存器。


XADD(Exchange and Add)

将第1个操作子(目标寄存器或目标内存地址)和第2个操作子(源寄存器)交换,然后将两个操作数的和值赋给目标。目标可以是寄存器或内存,源必须是寄存器。

该指令允许使用LOCK前缀

该指令仅被486及486以后的CPU所支持。

指令执行后,目标操作子中的值为和值,源寄存器中的值是目标操作子中原始值

TEMP = SRC + DESTSRC = DESTDEST = TEMP

标志寄存器中的CF, PF, AF, SF, ZF和OF标志,受加法操作影响(最终目标操作子中的值)。

注意,在保护模式下,如果对齐检查被打开,而内存操作地址并未对齐,且当前特权级是3,则引发异常

2006年12月22日

对于长期坐着工作,特别是长期让头摆在一个固定角度上的程序员来说,去驾校练练倒桩是非常有益的。最开始,倒桩可以帮助你对颈椎做一个牵引,可以让每一个初试倒库的人做引颈受戮状,并保持60秒左右,长期坚持,不但脖子可以变得修长,也会大幅度降低颈椎病的发病率。

由于倒桩的时候慢比快好,所以双脚对离合刹车的控制就尤为重要,基本上每个初次上车的人都会有不同程度的大小腿酸麻症状,长此以往,相信不比跳芭蕾对腿的锻炼力度更差。

方向盘快速转动的时候,基本上与搓麻将的动作差不多,一手推一手拉,作迅速的圆周运动。

……

在这个寒冷的冬至,中午11时50分左右,在成都市白家车管所,俺的桩考过了,感谢CCTV、感谢MTV、感谢我的BABA(三声)和MAMA(三声)……

晚上吃羊肉庆贺,阿门!

2006年12月21日

在STL中,for_each函数的第1、2个参数指定操作范围,第3个参数是一个函数对象,用于对范围中的每个由迭代器提供的对象进行操作,它通常是一个具有单个参数的函数的函数指针,或者是一个重载了括号运算符的类实例。

利用<functional>头文件中的mem_fun模板函数,可以返回mem_fun_t这个模板类的实例,从而使得迭代器提供对象的成员函数能够被for_each所用。但是,在实际应用中,往往需要让for_each可以调用任意一个类的成员函数,但STL好象并未提供,只好自己写一个:

00001: template<class C, typename R, typename T>00002: class MemberUnaryFuncT00003:     : public std::unary_function<T, R>00004: {00005: public:00006:     typedef R (C::*METHOD)(T);00007:     explicit MemberUnaryFuncT(C * instanceOfC, METHOD method)00008:         : instanceOfC_(instanceOfC), method_(method)00009:     {}00010:     inline R operator () (T t) const { return (instanceOfC_->*method_)(t); }00011: private:00012:     C       * instanceOfC_;00013:     METHOD  method_;00014: };00015: 00016: template<class C, typename R, typename T>00017: class MemberUnaryConstFuncT00018:     : public std::unary_function<T, R>00019: {00020: public:00021:     typedef R (C::*METHOD)(T) const;00022:     explicit MemberUnaryConstFuncT(C * instanceOfC, METHOD method)00023:         : instanceOfC_(instanceOfC), method_(method)00024:     {}00025:     inline R operator () (T t) const { return (instanceOfC_->*method_)(t); }00026: private:00027:     C       * instanceOfC_;00028:     METHOD  method_;00029: };00030: 00031: template<class C, typename R, typename T>00032: inline00033: MemberUnaryFuncT<C,R,T> MemberFunc(C * instanceOfC, R (C::*method)(T)) {00034:     return MemberUnaryFuncT<C,R,T>(instanceOfC, method);00035: }00036: 00037: template<class C, typename R, typename T>00038: inline00039: MemberUnaryConstFuncT<C,R,T> MemberFunc(C * instanceOfC, R (C::*method)(T) const) {00040:     return MemberUnaryConstFuncT<C,R,T>(instanceOfC, method);00041: }

使用示例

00001: class Foo {00002:     void test1(int) {}00003:     void test2(int) {}00004: public:00005:     Foo() {00006:         std::vector<int> container;00007:         std::for_each(container.begin(), container.end(), MemberFunc(this, test1));00008:         std::for_each(container.begin(), container.end(), MemberFunc(this, test2));00009:     }00010: }; 
2006年12月20日

一个完整的域名,由根域、顶级域、二级、三级……域名构成,每级域名之间用点分开,每级域名由字母、数字和减号构成(第一个字母不能是减号),不区分大小写,长度不超过63。

很显然,单独的名字可以由正则表达式[a-zA-Z0-9][-a-zA-Z0-9]{0,62}来匹配,而完整的域名至少包括两个名字(比如google.com,由google和com构成),最后可以有一个表示根域的点(在规范中,最后有一个点的才是完整域名,但一般认为包括两个以上名字的域名也是完整域名,哪怕它后面没有点)。

匹配完整域名的正则表达式:

[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?

2006年12月19日

读了几页《Mastering Regular Expression》,有心想写一个能够匹配IP字串的正则表达式,实际尝试发现远没有自己写几行代码来判断来得容易,呵呵。

一个IP字串,由四段组成,每一段是0~255的数字,段与段之间用小数点隔开,比如61.139.2.69就是一个合法的IP字串。

如果正则表达式写成\d{1,3}(\.\d{1,3}){3}无疑是不负责的,因为它可以匹配300.400.555.666这样的非法IP字串。

要匹配一个0~255之间的数,有几种匹配方式,下面是其中一种:

匹配 正则表达式 说明
0~9 \d 单个数字
10~99 [1-9]\d 两位数
100~199 1\d\d 百位为1的三位数
200~249 2[0-4]\d 三位数,百位是2,十位是0~9
250~255 25[0-5] 三位数,百位是2,十位是5,个位是0~5

写成正则表达式,即:(\d|([1-9]\d)|(1\d\d)|(2[0-4]\d)|(25[0-5])),但是这样的正则表达式在匹配254这样的字串时,会分别匹配2、5、4,得到3个匹配,达不到预期效果,正确做法是将次序颠倒为((25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]\d)|\d),因为在(xxx|yyy)这种匹配行为中,是从左向右搜索的。

完整的正则表达式是:

((25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]\d)|\d)(\.((25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]\d)|\d)){3}

按:

  • 061这样的高位为0的数是不能被匹配的。
  • 太麻烦,不如自己写一小段代码解析来得容易,呵呵

原文地址:http://mengyunhai.blog.sohu.com/25371124.html

2006年12月13日

Mastering Regular ExpressiongsMastering Regular Expressions

Jerffrey E.F.Friedl著的这本书,闻名已久。九月份从当当网邮购了一本,却一直没有时间坚持读,主要原因当然还是英文差,没有养成阅读英文的习惯和能力。

后悔呀,当初为什么不多花点时间在英语上面。

开篇说的那个可怕的、查找重复单词的需求非常生动,如果是我遇到这样的需求,肯定同样会很苦恼。

  • 检查N个文件,找到重复的单词(比如“this this”),然后报出它们在哪个文件的哪一行,还要用标准ANSI的转义序列来高度显示它们;
  • 不仅如此,还要正确处理这种情况:某行的最后一个单词,与紧跟着的下一(非空)行的第一个单词相同,也就是说要能够跨行工作。
  • 在查找过程中,还要忽略大小写的区别,并且能把单词之间的任意数量空格都等同于单个空格对待,最重要的是,两个重复单词中的某一个或两个被HTML标记包围着,那还是算重复单词!比如“…it is <B>very</B> very important…”

这样的需求听上去很讨厌,但有了正则表达式,一切就变得容易了。

下表是基本的元字符:

元字符
名称
匹配行为
备注
^ 脱字符 匹配行的起始位置  
$ 美圆符 匹配行的结束位置  
\< 反斜杠及小于符 匹配单词的起始边界 不是所有版本的的egrep都支持这个特性
\> 反斜杠及大于符 匹配单词的结束边界
. 匹配任意单个字符
[...] 字符集 匹配所有方括号中列出的字符
[^...] 字符非集 匹配所有不在方括号中列出的字符  
| 或符号 匹配或符号分开的的表达式  
(…) 圆括号 用于指定“或”符号的范围  

注:

  • 如果一个元字符出现在字符集中(被方括号括起来的字符列表),则它不再是元字符,比方,点字符在方括号以外时,它是一个元字符,代表任意字符,如果它出现在方括号里,则代表点字符本身。
  • 在字符集和字符非集中中,如果减号字符出现在第一个字符位置,则它代表减号本身,否则它表示一个范围,比如[-a-z0-9],第一个减号代表减号本身,第二个减号表示范围,与字符a和z一起表示从a至z的26个英文小写字母,第三个减号与第二个减号的意义一样。
  • 字符非集的概念需要仔细,比如,[^X]意味着“只要不是字符X就匹配”,而是“匹配一个不是X的任意字符”,前者的意义可以匹配一个空行,但[^X]并不匹配空行。
  • 某些版本的egrep支持-i参数,以执行忽略大小写的匹配操作。
2006年12月12日

殖民计划

这几天忽然怀念起一款很老的DOS游戏《殖民计划》,台湾光谱出品,在当时以640*480*256色的高品质画面引起强烈反响。游戏不复杂,再加上几个出名的BUG,过关易如反掌。

从网上下载到后,在Virtual PCVMWare Workstation下面都无法正常运行,最后找到DOSBox,才算痛痛快快玩了一把 :)

2006年12月04日

看看印度人拿多少薪水

 
月收入
美刀
人民币
(按1:8折算)
最低薪水,全日制民工
45
360
忒黑了点
懂点洋文,给老外打工的司机和仆人
100
800
也黑
刚出道没有啥经验的,基本上不能写代码但可以先搞搞测试的
275
2,200
看来国情差不多
有点点经验,颇具潜力的年轻人
633
5,066
开始有点意思了
有四年左右经验的
1,266
10,133
流口水了
七八年经验的老手
3,250
26,000
讨厌的资本主义
最好的工程
5,416
43,333
资本主义一定要灭亡
管二三十个人的主管
4,500
36,000
当官的不一定比最棒的兵拿得多
小公司的总太监
7,500
60,000
这种“小”公司搁国内就是人人挤破头的大公司
大内总管(VP,CTO)
12,500
100,000
百万年薪不是梦

资料来自Code Craft