两周过得真快,有一件事万万没想到,三周内竟然感冒两次,前所未有。各位朋友要注意自己身体咯,奋斗也要充足的休息。^_^在这里,再次警告自己,不要太晚睡!!但常常拿自己没办法,在电脑前坐一坐,半小时就不知跑哪里去了。病得厉害,今天写点读书笔记就早点睡,期待明天会迅速好起来^_^

        首先是微机原理,因为学起来比数据结构简单多。郑学坚老师的书,啃到16位微处理器的工作模式时啃不下去,一页又一页的文字讲解,我想郑老师自己都头疼。跳过,但8086的结构图和中断一定要掌握,其它的关系不大。汇编程序那章,最好每个程序都在虚拟机上敲一遍,注意各寄存器间的变化,很快就能理解。其它章节讲解都相当通俗易懂,来回翻一两遍就解决了。

        接下来就是一直看一直昏的数据结构(也许是刚感冒的原因^_^),昏的主要是那些一段又一段的代码,后来才了解,初级水平还不用深入了解这些代码,搞清原理就OK。下了几G严蔚敏老师的亲自授课录像,很可惜一集没看,主要画面太差,而且严老师也确实老了@_@不过,严老师的演示程序十分不错,就是代码不全,连接又找不到,有心的朋友自己找吧,两兆多的压缩包。里面分部演示算法的各个步骤,还可以对算法程序设断点,十分有利于对算法的分析和理解。慢慢地,翻了一遍又一遍的书后(时间约为微机的4倍,串和文件等几章跳了),再结合一些习题巩固一下就没问题。重点就是树和图两章。

        不经意,又十二点多,马上睡觉......

Tag: 读书


        很好的汇编学习资料,来自成都理工大学的一个教学软件,汇总得很好。原来的连接已经找不到,我上传到这里。还带一些小程序,和测试题。其实这个软件都放了一段时间,只不过一直没发现里头有这么好的资料。很多时候就像这样,得到一块石头又马上去寻找更多的石头,当回过头来认真查看时,才发现手上的宝贝还真不少......

                               寄存器与存储器
  1. 寄存器功能
    . 寄存器的一般用途和专用用途
    . CS:IP 控制程序执行流程
    . SS:SP 提供堆栈栈顶单元地址
    . DS:BX(SI,DI) 提供数据段内单元地址
    . SS:BP 提供堆栈内单元地址
    . ES:BX(SI,DI) 提供附加段内单元地址
    . AX,CX,BX和CX寄存器多用于运算和暂存中间计算结果,但又专用于某些指令(查阅 指令表)。
    . PSW程序状态字寄存器只能通过专用指令(LAHF,  SAHF)和堆栈(PUSHF,POPF)进行存取。

  2. 存储器分段管理
    . 解决了16位寄存器构成20位地址的问题
    . 便于程序重定位
    . 20位物理地址=段地址 * 16 + 偏移地址
    . 程序分段组织: 一般由代码段,堆栈段,数据段和附加段组成,不设置堆栈段时 则使用系统内部的堆栈。

   3. 堆栈
      . 堆栈是一种先进后出的数据结构 , 数据的存取在栈顶进行 , 数据入栈使堆栈向地址减小的方向扩展 。
      . 堆栈常用于保存子程序调用和中断响应时的断点以及暂存数据或中间计算结果 。
       . 堆栈总是以字为单位存取

                               指令系统与寻址方式

  1. 指令系统
    . 计算机提供给用户使用的机器指令集称为指令系统,大多数指令为双操作数指令。执行指令后,一般源操作数不变,目的操作数被计算结果替代。
    . 机器指令由CPU执行,完成某种运算或操作,8086/8088指令系统中的指令分为6类: 数据传送,算术运算,逻辑运算,串操作,控制转移和处理机控制。

  2. 寻址方式
    . 寻址方式确定执行指令时获得操作数地址的方法
    . 分为与数据有关的寻址方式(7种)和与转移地址有关的寻址方式(4)种。

    . 与数据有关的寻址方式的一般用途:
      (1) 立即数寻址方式--将常量赋给寄存器或存储单元
      (2) 直接寻址方式--存取单个变量
      (3) 寄存器寻址方式--访问寄存器的速度快于访问存储单元的速度
      (4) 寄存器间接寻址方式--访问数组元素
      (5) 变址寻址方式
      (6) 基址变址寻址方式
      (7) 相对基址变址寻址方式
     (5),(6),(7)都便于处理数组元素
   . 与数据有关的寻址方式中,提供地址的寄存器只能是BX,SI,DI或BP

   . 与转移地址有关的寻址方式的一般用途:
     (1) 段内直接寻址--段内直接转移或子程序调用
     (2) 段内间接寻址--段内间接转移或子程序调用
     (3) 段间直接寻址--段间直接转移或子程序调用
     (4) 段间间接寻址--段间间接转移或子程序调用


                             汇编程序和汇编语言

   1. 汇编程序
     . 汇编程序是将汇编语言源程序翻译成二进制代码程序的语言处理程序,翻译的过程称为汇编。

   2. 汇编语言
     . 汇编语言是用指令助记符,各种标识变量,地址,过程等的标识符书写程序的语言,  汇编语言指令与机器指令一 一对应。
     . 伪指令,宏指令不是由CPU执行的指令,而是由汇编程序在汇编期间处理的指令。
     . 伪指令指示汇编程序如何完成数据定义,存储空间分配,组织段等工作。
     . 宏指令可简化程序并减少程序书写量。
     . 条件汇编伪指令的功能是确定是否汇编某段源程序,而不是实现程序分支,对未汇编的程序将不产生相应的目标代码。
     . 结构作为一种数据结构可将一组类型不同但有逻辑关联的数据组织在一起,便于 整体处理数据。
     . 记录可用于提高存储单元的利用率,将若干不足一个字节或字且有逻辑关联的信 息压缩存放在一个字节或字中。
     . 指令中的表达式在汇编期间计算,并且只能对常量或地址进行计算。

                                    程序设计基础

   1. 分支程序设计
     . 程序分支由条件转移指令或无条件转移指令实现
     . 存放若干目的转移地址或跳转指令的跳转表常用于实现多路分支
     . 条件转移指令只能实现偏移量为-128至+127字节范围的转移
     . 无条件转移指令根据寻址方式可实现短转移(偏移量为-128至+127字节),段内转 移,段间转移。

   2. 循环程序设计
     . 可由循环控制指令或条件转移指令组织循环结构
     . 内层循环结构必须完全包含在外层循环结构内,并不能发生从循环结构外向循环 结构内的转移。

   3. 子程序设计
     . 子程序中应保护寄存器内容,并正确使用堆栈, 成对执行PUSH和POP指令,保证执行RET指令时堆栈栈顶为返回地址。
     . 主程序可通过寄存器,参数表,或堆栈传递参数给子程序  

   4. EXE文件和COM文件
     . 二者都是可执行文件
     . COM文件源程序的特点是: 第一条可执行指令的起始存放地址必须是100H,不能 分段,不用定义堆栈,所有过程为NEAR类型,直接用INT 20H 指令返回DOS。

   5. DOS功能调用与BIOS中断调用
     . 二者都是完成DOS系统提供给用户的输入/输出等常用功能,通过执行软中断指令 完成一次软中断服务。
     . DOS功能调用的中断服务程序是操作系统的一部分,存于RAM中; 而BIOS中断调用的中断服务程序存放在ROM中。

                            输入/输出与中断系统

   1. 输入/输出的方式
     . 程序直接I/O方式: 用IN和OUT指令直接在端口级上进行I/O操作,数据传送方式 分为无条件传送方式和查询传送方式。
     . 中断传送方式: 由CPU响应中断请求完成中断服务。
     . DMA传送方式: 直接在存储器与外设之间传送数据。

   2. 有关中断的概念
     . 中断、中断源、中断请求、中断服务、中断向量、中断向量表、中断响应过程、 中断指令、开中断、关中断、内部中断、外部中断、可屏蔽中断、非屏蔽中断。

   3. 键盘I/O、显示器I/O操作
     . 键盘的输入操作用BIOS的16H中断调用控制,也可直接访问60H端口(数据端口), 61H端口(状态端口)检测键盘的按键操作。
     . 对于特殊键(如Shift , Ctrl , Alt , NumLock , ScrollLock等键)的按动情况,可以直接从来40:17H单元取得有关信息。
     . 显示器的图形显示可以用BIOS的10H中断调用实现,另一种速度更快的方法是直 接读写视频缓冲区。

   4. 打印机I/O操作由 INT   17H中断调用实现, 串行通讯口操作由 INT  14H中断调用实现。

Tag: 汇编


       6K,不多也不少,本以为要到毕业才能还清,呵呵,世事难料,有些事说变就变。说起这笔债,真要感谢堂哥,18岁的小P孩,6k说借就借,有这样的大哥算我走运^_^ 我可帮他修不少电脑......

        那时年少气盛,抱着对电脑的一腔热情,看多了电脑报后萌生写稿赚Money的想法,因为,不够钱和MM逛街。刚买来电脑时确实写了篇稿,收了百多RMB,欣喜若狂,算第一次自己赚钱。可惜,最终迫于高考的压力没用继续。再后来,Money也不缺了........

        这学期,赚了前所未有的Money,高达数K(有Money的大哥不要笑,汗水不是白流的),学业也小有所成,可惜,已没有MM陪我逛街,或者,是我没时间陪MM逛街了...

Tag: 琐事


        放假以来,路由(华为的MT800)总是时不时罢工(断线),接着便是楼上租客的热心询问,房东!为什么上不了网呀!原本猜测是天气过热的问题,摸一下确实发烫。经测试后排除此因素,吃饭时开了空调还是会断......

        经一番搜索,在路由的配置界面里发现一大堆的报警信号:Sun Jul 16 19:47:48 2006 : WARNING : ATM VC Congested : Interface - aal5-1, PortId=7, Vpi=8, Vci=35

        问题就在这里ATM VC Congested ,是在emule下载时产生的,当连接数过大时,路由的保护性断线,修改路由的maxipsess可以暂时解决问题。为什么这样说呢?因为原来的maxipsess为192,已是这个路由所达到最适值,超过此值时,路由就算超负荷工作,发热量加大,迟早出问题。不过,暂时应付一下还是可以的。具体修改如下:首先在运行里输入telnet 192.168.1.1,然后输入用户名,密码,依次键入

(1)$modify nbsize maxipsess 256;(2)$commit;(3)$reboot

红色部分为修改值,不怕的话,可以试试512...^_^

Tag: 路由


也是来自不知名大哥的总结,先谢了。这一篇解析比较详细,很多书上没有介绍的指令都有说明。而且,排版还相当不错^_^

一、数据传送指令
1.通用数据传送指令
MOV(Move)传送
PUSH(Push onto the stack)进栈
POP(Pop from the stack)出栈
XCHG(Exchange)交换

.MOV指令
格式为: MOV DST,SRC
执行的操作:(DST)<-(SRC)
.PUSH进栈指令
格式为:PUSH SRC
执行的操作:(SP)<-(SP)-2
((SP)+1,(SP))<-(SRC)
.POP出栈指令
格式为:POP DST
执行的操作:(DST)<-((SP+1),(SP))
(SP)<-(SP)+2
.XCHG 交换指令
格式为:XCHG OPR1,OPR2
执行的操作:(OPR1)<-->(OPR2)

2.累加器专用传送指令
IN(Input) 输入
OUT(Output) 输出
XLAT(Translate) 换码
这组指令只限于使用累加器AX或AL传送信息.

.IN 输入指令
长格式为: IN AL,PORT(字节)
IN AX,PORT(字)
执行的操作: (AL)<-(PORT)(字节)
(AX)<-(PORT+1,PORT)(字)
短格式为: IN AL,DX(字节)
IN AX,DX(字)
执行的操作: AL<-((DX))(字节)
AX<-((DX)+1,DX)(字)
.OUT 输出指令
长格式为: OUT PORT,AL(字节)
OUT PORT,AX(字)
执行的操作: (PORT)<-(AL)(字节)
(PORT+1,PORT)<-(AX)(字)
短格式为: OUT DX,AL(字节)
OUT DX,AX(字)
执行的操作: ((DX))<-(AL)(字节)
((DX)+1,(DX))<-AX(字)
在IBM-PC机里,外部设备最多可有65536个I/O端口,

端口(即外设的端口地址)为0000~FFFFH.其中前256个端
口(0~FFH)可以直接在指令中指定,这就是长格式中的PORT,
此时机器指令用二个字节表示,第二个字节就是端口号.所以
用长格式时可以在指定中直接指定端口号,但只限于前256个
端口.当端口号>=256时,只能使用短格式,此时,必须先把端
口号放到DX寄存器中(端口号可以从0000到0FFFFH),然后
再用IN或OUT指令来 传送信息.
.XLAT 换码指令
格式为: XLAT OPR
或: XLAT
执行的操作:(AL)<-((BX)+(AL))

3.有效地址送寄存器指令
LEA(Load effective address)有效地址送寄存器
LDS(Load DS with Pointer)指针送寄存器和DS
LES(Load ES with Pointer)指针送寄存器和ES
.LEA 有效地址送寄存器
格式为: LEA REG,SRC
执行的操作:(REG)<-SRC
指令把源操作数的有效地址送到指定的寄存器中.
.LDS 指针送寄存器和DS指令
格式为: LDS REG,SRC
执行的操作:(REG)<-(SRC)
(DS)<-(SRC+2)
把源操作数指定的4个相继字节送到由指令指定的寄存器

及DS寄存器中.该指令常指定SI寄存器.
.LES 指针送寄存器和ES指令
格式为: LES REG,SRC
执行的操作: (REG)<-(SRC)
(ES)<-(SRC+2)
把源操作数指定的4个相继字节送到由指令指定的寄存器

及ES寄存器中.该指令常指定DI寄存器.

4.标志寄存器传送指令
LAHF(Load AH with flags)标志送AH
SAHF(store AH into flags)AH送标志寄存器
PUSHF(push the flags) 标志进栈
POPF(pop the flags) 标志出栈
.LAHF 标志送AH
格式为: LAHF
执行的操作:(AH)<-(PWS的低字节)

.SAHF AH送标志寄存器
格式为: SAHF
执行的操作:(PWS的低字节)<-(AH)
.PUSHF 标志进栈
格式为: PUSHF
执行的操作:(SP)<-(SP)-2
((SP)+1,(SP))<-(PSW)
.POPF 标志出栈
格式为: POPF
执行的操作:(PWS)<-((SP)+1,(SP))
(SP)<-(SP+2)


二、算术指令
1.加法指令
ADD(add)加法
ADC(add with carry)带进位加法
INC(increment)加1

.ADD 加法指令
格式: ADD DST,SRC
执行的操作:(DST)<-(SRC)+(DST)
.ADC 带进位加法指令
格式: ADC DST,SRC
执行的操作:(DST)<-(SRC)+(DST)+CF
.ADD 加1指令
格式: INC OPR
执行的操作:(OPR)<-(OPR)+1

2.减法指令
SUB(subtract)减法
SBB(subtract with borrow)带借位减法
DEC(Decrement)减1
NEG(Negate)求补
CMP(Compare)比较

.SUB 减法指令
格式: SUB DST,SRC
执行的操作:(DST)<-(DST)-(SRC)
.SBB 带借位减法指令
格式: SBB DST,SRC
执行的操作:(DST)<-(DST)-(SRC)-CF
.DEC 减1指令
格式: DEC OPR
执行的操作:(OPR)<-(OPR)-1
.NEG 求补指令
格式: NEG OPR
执行的操作:(OPR)<- -(OPR)
.CMP 比较指令
格式: CMP OPR1,OPR2
执行的操作:(OPR1)-(OPR2)
该指令与SUB指令一样执行减法操作,但不保存结果,

只是根据结果设置条件标志西半球.

3.乘法指令
MUL(Unsigned Multiple)无符号数乘法
IMUL(Signed Multiple)带符号数乘法

.MUL 无符号数乘法指令
格式: MUL SRC
执行的操作:
字节操作数:(AX)<-(AL)*(SRC)
字操作数:(DX,AX)<-(AX)*(SRC)
.IMUL 带符号数乘法指令
格式: IMUL SRC
执行的操作:与MUL相同,但必须是带符号数,而MUL是无符号数.

4.除法指令
DIV(Unsigned divide)无符号数除法
IDIV(Signed divide)带符号数除法
CBW(Convert byte to word)字节转换为字
CWD(Contert word to double word)字转换为双字

.DIV 无符号数除法指令
格式: DIV SRC
执行的操作:

 字节操作:(AL)<-(AX)/(SRC)的商
(AH)<-(AX)/(SRC)的余数
字操作: (AX)<-(DX,AX)/(SRC)的商
(AX)<-(DX,AX)/(SRC)的余数
.IDIV 带符号数除法指令
格式: DIV SRC
执行的操作:与DIV相同,但操作数必须是带符号数,商和余数

也均为带符号数,且余数的符号与被除数的符号相同.
.CBW 字节转换为字指令
格式: CBW
执行的操作:AL的内容符号扩展到AH.即如果(AL)的最高有效

位为0,则(AH)=00;如(AL)的最高有效位为1,则(AH)=0FFH
.CWD 字转换为双字指令
格式: CWD
执行的操作:AX的内容符号扩展到DX.即如(AX)的最高有效位

为0,则(DX)=0;否则(DX)=0FFFFH.
这两条指令都不影响条件码.


三、逻辑指令
1.逻辑运算指令
AND(and) 逻辑与
OR(or) 逻辑或
NOT(not) 逻辑非
XOR(exclusive or)异或
TEST(test) 测试
.AND 逻辑与指令
格式: AND DST,SRC
执行的操作:(DST)<-(DST)^(SRC)
.OR 逻辑或指令
格式: OR DST,SRC
执行的操作:(DST)<-(DST)V(SRC)
.NOT 逻辑非指令
格式: NOT OPR
执行的操作:(OPR)<-(OPR)
.XOR 异或指令
格式: XOR DST,SRC
执行的操作:(DST)<-(DST)V(SRC)
.TEST 测试指令
格式: TEST OPR1,OPR2
执行的操作:(DST)^(SRC)
两个操作数相
的结果不保存,只根据其特征置条件码

2.移位指令
SHL(shift logical left) 逻辑左移
SAL(shift arithmetic left) 算术左移
SHR(shift logical right) 逻辑右移
SAR(shift arithmetic right) 算术右移
ROL(Rotate left) 循环左移
ROR(Rotate right) 循环右移
RCL(Rotate left through carry) 带进位循环左移
RCR(Rotate right through carry) 带进位循环右移
格式: SHL OPR,CNT(其余的类似)
其中OPR可以是除立即数以外的任何寻址方式.移位次数由CNT决定,

CNT可以是1CL.循环移位指令可以改变操作数中所有位的位置;移
位指令则常常用来做乘以2除以2操作.其中算术移位指令适用于带符
号数运算,SAL用来乘2,SAR用来除以2;而逻辑移位指令则用来无符
号数运算,SHL用来乘2,SHR用来除以2.


四、串处理指令
1.与REP相配合工作的MOVS,STOS和LODS指令
.REP重复串操作直到(CX)=0为上
格式: REP string primitive
其中String Primitive可为MOVS,LODS或STOS指令
执行的操作:
1)如(CX)=0则退出REP,否则往下执行.
2)(CX)<-(CX)-1
3)执行其中的串操作
4)重复1)~3)
.MOVS 串传送指令
格式:可有三种
MOVS DST,SRC
MOVSB(字节)
MOVSW(字)

其中第二、三种格式明确地注明是传送字节或字,第一种格式则应
在操作数中表明是字还是字节操作,例如:
MOVS ES:BYTE PTR[DI],DS:[SI]
执行的操作:
1)((DI))<-((SI))
2)字节操作:
(SI)<-(SI)+(或-)1,(DI)<-(DI)+(或-)1
当方向标志DF=0时用+,当方向标志DF=1时用-
3)字操作:
(SI)<-(SI)+(或-)2,(DI)<-(DI)+(或-)2
当方向标志DF=0时用+,当方向标志DF=1时用-
该指令不影响条件码.
.CLD(Clear direction flag)该指令使DF=0,在执行串操作
指令时可使地址自动增量;
.STD(Set direction flag)该指令使DF=1,在执行串操作指

令时可使地址自动减量.
.STOS 存入串指令
格式: STOS DST
STOSB(字节)
STOSW(字)
执行的操作:
字节操作:((DI))<-(AL),(DI)<-(DI)+-1
字操作: ((DI))<-(AX),(DI)<-(DI)+-2
该指令把AL或AX的内容存入由(DI)指定的附加段的某单元中,并根

据DF的值及数据类型修改DI的内容,当它与REP联用时,可把AL或AX
的内容存入一个长度为(CX)的缓冲区中.
.LODS 从串取指令
格式: LODS SRC
LODSB
LODSW
执行的操作:
字节操作:(AL)<-((SI)),(SI)<-(SI)+-1
字操作: (AX)<-((SI)),(SI)<-(SI)+-2
该指令把由(SI)指定的数据段中某单元的内容送到AL或AX中,并根据

方向标志及数据类型修改SI的内容.指令允许使用段跨越前缀来指定非
数据段的存储区.该指令也不影响条件码.一般说来,该指令不和REP联
用.有时缓冲区中的一串字符需要逐次取出来测试时,可使用本指令.

2.与REPE/REPZ和REPNZ/REPNE联合工作的CMPS和SCAS指令
.REPE/REPZ 当相等/为零时重复串操作
格式: REPE(或REPZ) String Primitive
其中String Primitive可为CMPS或SCAS指令.
执行的操作:
1)如(CX)=0或ZF=0(即某次比较的结果两个操作数不等)时退出,
否则往下执行
2)(CX)<-(CX)-1
3)执行其后的串指令
4)重复1)~3)
.REPNE/REPNZ 当不相等/不为零时重复串操作
格式: REPNE(或REPNZ) String Primitive
其中String Primitive可为CMPS或SCAS指令
执行的操作:
除退出条件(CX=0)或ZF=1外,其他操作与REPE完全相同.
.CMPS 串比较指令
格式: CMP SRC,DST
CMPSB
CMPSW
执行的操作:
1)((SI))-((DI))
2)字节操作:(SI)<-(SI)+-1,(DI)<-(DI)+-1
字操作: (SI)<-(SI)+-2,(DI)<-(DI)+-2
指令把由(SI)指向的数据段中的一个字(或字节)与由(DI)指向的
附加段中的一个字(或字节)相减,但不保存结果,只根据结果设置条
件码,指令的其它特性和MOVS指令的规定相同.
.SCAS 串扫描指令
格式: SCAS DST
SCASB
SCASW
执行的操作:
字节操作:(AL)-((DI)),(DI)<-(DI)+-1

字操作: (AL)-((DI)),(DI)<-(DI)+-2
该指令把AL(或AX)的内容与由(DI)指定的在附加段中的一个字节(或字)
进行比较,并不保存结果,只根据结果置条件码.指令的其他特性和MOVS的
规定相同. 

五、控制转移指令
1.无条件转移指令
.JMP(jmp) 跳转指令
1)段内直接短转移
格式:JMP SHORT OPR
执行的操作:(IP)<-(IP)+8位位移量

2)段内直接近转移
格式:JMP NEAR PTR OPR
执行的操作:(IP)<-(IP)+16位位移量

3)段内间接转移
格式:JMP WORD PTR OPR
执行的操作:(IP)<-(EA)

4)段间直接(远)转移
格式:JMP FAR PTR OPR
执行的操作:(IP)<-OPR的段内偏移地址
(CS)<-OPR所在段的段地址

5)段间间接转移

格式:JMP DWORD PTR OPR
执行的操作:(IP)<-(EA)
(CS)<-(EA+2)

2.条件转移指令
1)根据单个条件标志的设置情况转移
.JZ(或JE)(Jump if zero,or equal) 结果为零(或相等)则转移
格式:JE(或JZ) OPR
测试条件:ZF=1

.JNZ(或JNE)(Jump if not zero,or not equal) 结果不为零
(或不相等)则转移
格式:JNZ(或JNE) OPR
测试条件:ZF=0

.JS(Jump if sign) 结果为负则转移
格式: JS OPR
测试条件:SF=1

.JNS(Jump if not sign) 结果为正则转移
格式:JNS OPR
测试条件:SF=0

.JO(Jump if overflow) 溢出则转移
格式: JO OPR
测试条件:OF=1

.JNO(Jump if not overflow)
不溢出则转移
格式: JNO OPR
测试条件:OF=0

.JP(或JPE)(Jump if parity,or parity even)
奇偶位为1则转移
格式: JP OPR
测试条件:PF=1

.JNP(或JPO)(Jump if not parity,or parity odd)
奇偶位为0则转移
格式: JNP(或JPO) OPR
测试条件:PF=0

.JB(或JNAE,JC)(Jump if below,or not above or equal,or carry)
低于,或者不高于或等于,或进位位为1则转移
格式:JB(或JNAE,JC) OPR
测试条件:CF=1

.JNB(或JAE,JNC)(Jump if not below,or above or equal,or not carry)
不低于,或者高于或者等于,或进位位为0则转移
格式:JNB(或JAE,JNC) OPR
测试条件:CF=0

2)比较两个无符号数,并根据比较的结果转移
.JB(或JNAE,JC)
格式:同上
.JNB(或JAE,JNC)
格式:同上
.JBE(或JNA)(Jump if below or equal,or not above)
低于或等于,或不高于则转移
格式:JBE(或JNA) OPR
测试条件:CFVZF=1

.JNBE(或JA)(Jump if not below or equal,or above)
不低于或等于,或者高于则转移
格式:JNBE(或JA) OPR
测试条件:CFVZF=0

3)比较两个带符号数,并根据比较的结果转移

.JL(或LNGE)(Jump if less,or not greater or equal)
小于,或者不大于或者等于则转移
格式:JL(或JNGE) OPR
测试条件:SFVOF=1

.JNL(或JGE)(Jump if not less,or greater or equal)
不小于,或者大于或者等于则转移
格式:JNL(或JGE) OPR
测试条件:SFVOF=0

.JLE(或JNG)(Jump if less or equal,or not greater)
小于或等于,或者不大于则转移
格式:JLE(或JNG) OPR
测试条件:(SFVOF)VZF=1

.JNLE(或JG)(Jump if not less or equal,or greater)
不小于或等于,或者大于则转移
格式:JNLE(或JG) OPR
测试条件:(SFVOF)VZF=0

4)测试CX的值为0则转移指令
.JCXZ(Jump if CX register is zero)
CX寄存器的内容为零则转移
格式:JCXZ OPR
测试条件:(CX)=0
注:条件转移全为8位短跳!

3.循环指令
.LOOP 循环指令
格式: LOOP OPR
测试条件:(CX)<>0

.LOOPZ/LOOPE 当为零或相等时循环指令
格式: LOOPZ(或LOOPE) OPR
测试条件:(CX)<>0且ZF=1

.LOOPNZ/LOOPNE 当不为零或不相等时循环指令
格式: LOOPNZ(或LOOPNE) OPR
测试条件:(CX)<>0且ZF=0
这三条指令的步骤是:
1)(CX)<-(CX)-1
2)检查是否满足测试条件,如满足则(IP)<-(IP)+D8的符号扩充.

4.子程序
.CALL调用指令
.RET返回指令

5.中断

.INT指令
格式: INT TYPE
或 INT
执行的操作:(SP)<-(SP)-2
((SP)+1,(SP))<-(PSW)
(SP)<-(SP)-2
((SP)+1,(SP))<-(CS)
(SP)<-(SP)-2
((SP)+1,(SP))<-(IP)
(IP)<-(TYPE*4)
(CS)<-(TYPE*4+2)
.INTO 若溢出则中断
执行的操作:若OF=1则:
(SP)<-(SP)-2
((SP)+1,(SP))<-(PSW)
(SP)<-(SP)-2
((SP)+1,(SP))<-(CS)
(SP)<-(SP)-2
((SP)+1,(SP))<-(IP)
(IP)<-(10H)
(CS)<-(12H)
.IRET 从中断返回指令
格式: IRET
执行的操作:(IP)<-((SP)+1,(SP))
(SP)<-(SP)+2
(CS)<-((SP)+1,(SP))
(SP)<-(SP)+2
(PSW)<-((SP)+1,(SP))
(SP)<-(SP)+2

六、处理机控制指令
1.标志处理指令
.CLC进位位置0指令(Clear carry)CF<-0
.CMC进位位求反指令(Complement carry)CF<-CF

.STC进位位置1指令(Set carry)CF<-1
.CLD方向标志置0指令(Clear direction)DF<-0

.STD方向标志置1指令(Set direction)DF<-1
.CLI中断标志置0指令(Clear interrupt)IF<-0
.STI中断标志置1指令(Set interrupt)IF<-0
2.其他处理机控制指令
NOP(No Opreation) 无操作
HLT(Halt) 停机
WAIT(Wait) 等待
ESC(Escape) 换码
LOCK(Lock) 封锁
这些指令可以控制处理机状态.这们都不影响条件码.
.NOP 无操作指令
该指令不执行任何操作,其机器码占有一个字节,在调试程序时往往
用这条指令占有一定的存储单元,以便在正式运行时用其他指令取代.
.HLT停机指令
该指令可使机器暂停工作,使处理机处于停机状态以便等待一次外部

中断到来,中断结束后可继续执行下面的程序.
.WAIT等待指令
该指令使处理机处于空转状态,它也可以用来等待外部中断的发生,

中断结束后仍返回WAIT指令继续德行.
.ESC换码指令
格式ESC mem
其中mem指出一个存储单元,ESC指令把该存储单元的内容送到数据总线去.

当然ESC指令不允许使用立即数和寄存器寻址方式.这条指令在使用协处理
机(Coprocessor)执行某些操作时,可从存储器指得指令或操作数.协处
理机(如8087)则是为了提高速度而可以选配的硬件.
.LOCK封锁指令
该指令是一种前缀,它可与其他指令联合,用来维持总线的锁存信号直

到与其联合的指令执行完为止.当CPU与其他处理机协同工作时,该指令可避
免破坏有用信息.
Tag: 汇编


        不知哪位大哥总结的,先借来用一下,免得老是翻书^_^ 
附一个汇编的在线学习网站

数据传输指令
───────────────────────────────────────
它们在存贮器和寄存器、寄存器和输入输出端口之间传送数据.
1. 通用数据传送指令.
MOV 传送字或字节.
MOVSX 先符号扩展,再传送.
MOVZX 先零扩展,再传送.
PUSH 把字压入堆栈.
POP 把字弹出堆栈.
PUSHA 把AX,CX,DX,BX,SP,BP,SI,DI依次压入堆栈.
POPA 把DI,SI,BP,SP,BX,DX,CX,AX依次弹出堆栈.
PUSHAD 把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次压入堆栈.
POPAD 把EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX依次弹出堆栈.
BSWAP 交换32位寄存器里字节的顺序
XCHG 交换字或字节.( 至少有一个操作数为寄存器,段寄存器不可作为操作数)
CMPXCHG 比较并交换操作数.( 第二个操作数必须为累加器AL/AX/EAX )
XADD 先交换再累加.( 结果在第一个操作数里 )
XLAT 字节查表转换.
── BX 指向一张 256 字节的表的起点, AL 为表的索引值 (0-255,即
0-FFH); 返回 AL 为查表结果. ( [BX+AL]->AL )
2. 输入输出端口传送指令.
IN I/O端口输入. ( 语法: IN 累加器, {端口号│DX} )
OUT I/O端口输出. ( 语法: OUT {端口号│DX},累加器 )
输入输出端口由立即方式指定时, 其范围是 0-255; 由寄存器 DX 指定时,
其范围是 0-65535.
3. 目的地址传送指令.
LEA 装入有效地址.
例: LEA DX,string ;把偏移地址存到DX.
LDS 传送目标指针,把指针内容装入DS.
例: LDS SI,string ;把段地址:偏移地址存到DS:SI.
LES 传送目标指针,把指针内容装入ES.
例: LES DI,string ;把段地址:偏移地址存到ES:DI.
LFS 传送目标指针,把指针内容装入FS.
例: LFS DI,string ;把段地址:偏移地址存到FS:DI.
LGS 传送目标指针,把指针内容装入GS.
例: LGS DI,string ;把段地址:偏移地址存到GS:DI.
LSS 传送目标指针,把指针内容装入SS.
例: LSS DI,string ;把段地址:偏移地址存到SS:DI.
4. 标志传送指令.
LAHF 标志寄存器传送,把标志装入AH.
SAHF 标志寄存器传送,把AH内容装入标志寄存器.
PUSHF 标志入栈.
POPF 标志出栈.
PUSHD 32位标志入栈.
POPD 32位标志出栈.

二、算术运算指令
───────────────────────────────────────
ADD 加法.
ADC 带进位加法.
INC 加 1.
AAA 加法的ASCII码调整.
DAA 加法的十进制调整.
SUB 减法.
SBB 带借位减法.
DEC 减 1.
NEC 求反(以 0 减之).
CMP 比较.(两操作数作减法,仅修改标志位,不回送结果).
AAS 减法的ASCII码调整.
DAS 减法的十进制调整.
MUL 无符号乘法.
IMUL 整数乘法.
以上两条,结果回送AH和AL(字节运算),或DX和AX(字运算),
AAM 乘法的ASCII码调整.
DIV 无符号除法.
IDIV 整数除法.
以上两条,结果回送:
商回送AL,余数回送AH, (字节运算);
或 商回送AX,余数回送DX, (字运算).
AAD 除法的ASCII码调整.
CBW 字节转换为字. (把AL中字节的符号扩展到AH中去)
CWD 字转换为双字. (把AX中的字的符号扩展到DX中去)
CWDE 字转换为双字. (把AX中的字符号扩展到EAX中去)
CDQ 双字扩展. (把EAX中的字的符号扩展到EDX中去)

三、逻辑运算指令
───────────────────────────────────────
AND 与运算.
OR 或运算.
XOR 异或运算.
NOT 取反.
TEST 测试.(两操作数作与运算,仅修改标志位,不回送结果).
SHL 逻辑左移.
SAL 算术左移.(=SHL)
SHR 逻辑右移.
SAR 算术右移.(=SHR)  当值为负时,高位补 1 ;当值为正时,高位补 0
ROL 循环左移.
ROR 循环右移.
RCL 通过进位的循环左移.
RCR 通过进位的循环右移.
以上八种移位指令,其移位次数可达255次.
移位一次时, 可直接用操作码. 如 SHL AX,1.
移位>1次时, 则由寄存器CL给出移位次数.
如 MOV CL,04
SHL AX,CL

四、串指令
───────────────────────────────────────
DS:SI 源串段寄存器 :源串变址.
ES:DI 目标串段寄存器:目标串变址.
CX 重复次数计数器.
AL/AX 扫描值.
D标志 0表示重复操作中SI和DI应自动增量; 1表示应自动减量.
Z标志 用来控制扫描或比较操作的结束.
MOVS 串传送.
( MOVSB 传送字符. MOVSW 传送字. MOVSD 传送双字. )
CMPS 串比较.
( CMPSB 比较字符. CMPSW 比较字. )
SCAS 串扫描.
把AL或AX的内容与目标串作比较,比较结果反映在标志位.
LODS 装入串.
把源串中的元素(字或字节)逐一装入AL或AX中.
( LODSB 传送字符. LODSW 传送字. LODSD 传送双字. )
STOS 保存串.
是LODS的逆过程.
REP 当CX/ECX<>0时重复.
REPE/REPZ 当ZF=1或比较结果相等,且CX/ECX<>0时重复.
REPNE/REPNZ 当ZF=0或比较结果不相等,且CX/ECX<>0时重复.
REPC 当CF=1且CX/ECX<>0时重复.
REPNC 当CF=0且CX/ECX<>0时重复.

五、程序转移指令
───────────────────────────────────────
1>无条件转移指令 (长转移)
JMP 无条件转移指令
CALL 过程调用
RET/RETF过程返回.
2>条件转移指令 (短转移,-128到+127的距离内)
( 当且仅当(SF XOR OF)=1时,OP1 JA/JNBE 不小于或不等于时转移.
JAE/JNB 大于或等于转移.
JB/JNAE 小于转移.
JBE/JNA 小于或等于转移.
以上四条,测试无符号整数运算的结果(标志C和Z).
JG/JNLE 大于转移.
JGE/JNL 大于或等于转移.
JL/JNGE 小于转移.
JLE/JNG 小于或等于转移.
以上四条,测试带符号整数运算的结果(标志S,O和Z).
JE/JZ 等于转移.
JNE/JNZ 不等于时转移.
JC 有进位时转移.
JNC 无进位时转移.
JNO 不溢出时转移.
JNP/JPO 奇偶性为奇数时转移.
JNS 符号位为 "0" 时转移.
JO 溢出转移.
JP/JPE 奇偶性为偶数时转移.
JS 符号位为 "1" 时转移.
3>循环控制指令(短转移)
LOOP CX不为零时循环.
LOOPE/LOOPZ CX不为零且标志Z=1时循环.
LOOPNE/LOOPNZ CX不为零且标志Z=0时循环.
JCXZ CX为零时转移.
JECXZ ECX为零时转移.
4>中断指令
INT 中断指令
INTO 溢出中断
IRET 中断返回
5>处理器控制指令
HLT 处理器暂停, 直到出现中断或复位信号才继续.
WAIT 当芯片引线TEST为高电平时使CPU进入等待状态.
ESC 转换到外处理器.
LOCK 封锁总线.
NOP 空操作.
STC 置进位标志位.
CLC 清进位标志位.
CMC 进位标志取反.
STD 置方向标志位.
CLD 清方向标志位.
STI 置中断允许位.
CLI 清中断允许位.

六、伪指令
─────────────────────────────────────
DW 定义字(2字节).
PROC 定义过程.
ENDP 过程结束.
SEGMENT 定义段.
ASSUME 建立段寄存器寻址.
ENDS 段结束.
END 程序结束.

Tag: 汇编


        微机原理(汇编)的书看完了,想写些代码熟熟手,一般用的都是命令行的masm,这个现在用起来不太方便,如果有IDE之类的工具就好(方便编写,因为IDE一般都有颜色加亮及debug等设计)。试了几个都不尽人意,VisualASM,RedASM,不太会弄,压根就编译不了,还不如masm+editplus。直到emu8086的出现(不到1天^_^),才解决这个入门的难题。Microprocessor Emulator 8086的模拟器,语句几乎是一句一句的执行(可以设每步的迟延时间),还有单步运行,各个寄存器的变化一幕了然......一大堆功能

下面是emu8086网站上的两张图片2

1

当然,代码可以汇编成exe,com文件在真实环境下运行,example文件夹下还带有不少例子...哈哈,汇编准备上路啦



正则表达式30分钟入门教程

作者:deerchao 来源: unibetter大学生社区

下面是重点摘要,详细请看原文

入门

在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。例如,\d+就是一个简洁的代码,代表着规则1位或更多位数字2008就符合这个规则,而A3则不符合(它包含了不是数字的字符)。

学习正则表达式的最好方法是从例子开始,理解例子之后再自己对例子进行修改,实验。下面给出了不少简单的例子,并对它们作了详细的说明。

假设你在一篇英文小说里查找hi,你可以使用正则正则表达式hi

这是最简单的正则表达式了,它可以精确匹配这样的字符串:由两个字符组成,前一个字符是h,后一个是i。通常,处理正则表达式的工具会提供一个忽略大小写的选项,如果选中了这个选项,它可以匹配hi,HI,Hi,hI

不幸的是,很多单词里包含hi这两个连续的字符,比如him,history,high等等。用hi来查找的话,这里边的hi也会被找出来。如果要精确地查找hi这个单词的话,我们应该使用\bhi\b

\b是正则表达式规定的一个特殊代码,代表着单词的开头或结尾。虽然通常英文的单词是由空格或标点符号或换行为分隔的,但是\b并不代表这些单词分隔符中的任何一个,只代表一个位置

假如你要找的是hi后面不远处跟着一个Lucy,你应该用\bhi\b.*\bLucy\b

这里,.是另一个特殊代码,代表除了换行符以外的任意字符*同样是特殊的代码,不过它代表的不是字符,也不是位置,而是数量--它指定*前边的内容可以重复任意次以使整个表达式得到匹配。因此,.*连在一起就意味着任意数量的不包含换行的字符。现在\bhi\b.*\bLucy\b的意思就很明显了:先是一个单词hi,然后是任意个任意字符(但不能是换行),最后是Lucy这个单词

如果同时使用其它的一些特殊代码,我们就能构造出功能更强大的正则表达式。比如下面这个例子:

0\d\d-\d\d\d\d\d\d\d\d代表着这样的字符串:以0开头,然后是两个数字,然后是一个连字号“-”,最后是8个数字(也就是中国的电话号码,当然,这个例子只能匹配区号为3位的情形,想同时匹配区号为4位的话,请在教程的下面寻找答案)。

这里的\d是一个新的特殊代码,代表任意的数字(0,或1,或2,或。。。)-不是特殊代码,只代表它本身--连字号。

为了避免那么多烦人的重复,我们也可以这样写这个表达式:0\d{2}-\d{8}

这里\d后面的{2}({8})指定的是前面\d必须连续重复出现2次(8次)

特殊代码

现在你已经知道几个具有特殊意义的代码了,如\b,.,*,还有\d.事实上还有更多的特殊代码,比如\s代表任意的空白符,包括空格,制表符(Tab),换行符\w代表着字母或数字

下面来试试更多的例子:

\ba\w*\b匹配以字母a开头的单词-先是某个单词开始处(\b),然后是字母a,然后是任意数量的字母或数字(\w*),最后是单词结束处(\b)

\d+匹配1个或更多连续的数字。这里的+是和*类似的特殊代码,不同的是*代表重复任意次(可能是0次),而+则代表重复1次或更多次

\b\w{6}\b 匹配刚好6个字母/数字的单词

表1.常用的特殊代码
代码/语法说明
.匹配除换行符以外的任意字符
\w匹配字母或数字
\s匹配任意的空白符
\d匹配数字
\b匹配单词的开始或结束
^匹配字符串的开始
$匹配字符串的结束

特殊代码^以及$\b有点类似,都匹配一个位置。^匹配你要用来查找的字符串的开头,$匹配结尾。这两个代码在验证输入的内容时非常有用,比如一个网站如果要求你填写的QQ号必须为5位到12位数字时,可以使用:^\d{5,12}$

这里的{5,12}和前面介绍过的{2}是类似的,只不过{2}代表只能不多不少重复2次{5,12}则是必须重复最少5次,最多12次,否则都不匹配。

因为使用了^$,所以输入的整个字符串都要用来和\d{5,12}来匹配,也就是说整个输入必须是5到12个数字,因此如果输入的QQ号能匹配这个正则表达式的话,那就符合要求了。

和忽略大小写的选项类似,有些正则表达式处理工具还有一个处理多行的选项。如果选中了这个选项,^$的意义就变成了匹配行的开始处和结束处

字符转义

如果你想查找特殊代码本身的话,比如你查找.,或者*,就出现了问题:你没法指定它们,因为它们会被解释成其它的意思。这时你就必须使用\来取消这些字符的特殊意义。因此,你应该使用\.\*。当然,要查找\本身,你也得用\\.

例如:www\.unibetter\.com匹配www.unibetter.comc:\\windows匹配c:\windows,2\^8匹配2^8(通常这是2的8次方的书写方式)。

重复

你已经看过了前面的*,+,{2},{5,12}这几个代表重复的方式了。下面是正则表达式中所有指定重复的方式:

表2.常用的量词
代码/语法说明
*重复零次或更多次
+重复一次或更多次
?重复零次或一次
{n}重复n次
{n,}重复n次或更多次
{n,m}重复n到m次

下面是一些使用重复的例子:

Windows\d+匹配Windows后面跟1个或更多数字

13\d{9}匹配以13后面跟9个数字(中国的手机号)

^\w+匹配一行的第一个单词(或整个字符串的第一个单词,具体代表哪个意思得看选项设置)

字符类

要想查找数字,字母或数字,空白是很简单的,因为已经有了对应这些字符集的特殊代码,但是如果你想匹配没有预定义特殊代码的字符集比如元音字母(a,e,i,o,u),怎么办?

很简单,你只需要在中括号里列出它们就行了,像[aeiou]就匹配任何一个元音字母[.?!]匹配标点符号(.或?或!)(英文语句通常只以这三个标点结束)。要注意的是,在中括号中,特殊代码不会被解释成其它意义,所以我们不需要写成[\.\?!](事实上这样写会出错,因为出现了两次\)。

我们也可以轻松地指定一个字符范围,像[0-9]代表的含意与\d就是完全一致的:一位数字,同理[a-z0-9A-Z]也完全等同于\w。

下面是一个更复杂的表达式:\(?0\d{2}[) -]?\d{8}

这个表达式可以匹配几种格式的电话号码,像(010)88886666,或022-22334455,或02912345678等。我们对它进行一些分析吧:首先是一个转义字符\(,它能出现0次或1次(?),然后是一个0,后面跟着2个数字({2}),然后是)-空格中的一个,它出现1次或不出现(?),最后是8个数字(\d{8})。不幸的是,它也能匹配010)12345678(022-87654321这样的“不正确”的格式。要解决这个问题,请在本教程的下面查找答案。

反义

有时需要查找不属于某个简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义

表3.常用的反义代码
代码/语法说明
\W匹配任意不是字母和数字的字符
\S匹配任意不是空白符的字符
\D匹配任意非数字的字符
\B匹配不是单词开头或结束的位置
[^x]匹配除了x以外的任意字符
[^aeiou]匹配除了aeiou这几个字母以外的任意字符

例子:\S+代表不包含空白符的字符串

]+>代表用尖括号括起来的以a开头的字符串

替换

好了,现在终于到了解决3位或4位区号问题的时间了。正则表达式里的替换指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。听不明白?没关系,看例子:

0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)

\(0\d{2}\)[- ]?\d{8}|0\d{2}[- ]?\d{8}这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。你可以试试用替换|把这个表达式扩展成也支持4位区号的。

\d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题:使用替换时,顺序是很重要的。如果你把它改成\d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配替换时,将会从左到右地测试每个条件,如果满足了某个条件的话,就不会去管其它的替换条件了。

Windows98|Windows2000|WindosXP这个例子是为了告诉你替换不仅仅能用于两种规则,也能用于更多种规则。

分组

我们已经提到了怎么重复单个字符;但如果想要重复一个字符串又该怎么办?你可以用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了,你也可以对子表达式进行其它一些操作(教程后面会有介绍)。

(\d{1,3}\.){3}\d{1,3}是一个简单的IP地址匹配表达式。要理解这个表达式,请按下列顺序分析它:\d{1,3}代表1到3位的数字(\d{1,3}\.}{3}代表三位数字加上一个英文句号(这个整体也就是这个分组)重复3次,最后再加上一个一到三位的数字(\d{1,3})。

不幸的是,它也将匹配256.300.888.999这种不可能存在的IP地址(IP地址中每个数字都不能大于255)。如果能使用算术比较的话,或许能简单地解决这个问题,但是正则表达式中并不提供关于数学的任何功能,所以只能使用冗长的分组,选择,字符类来描述一个正确的IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

理解这个表达式的关键是理解2[0-4]\d|25[0-5]|[01]?\d\d?,这里我就不细说了,你自己应该能分析得出来它的意义。

后向引用

使用小括号指定一个子表达式后,匹配这个子表达式的文本可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:以分组的左括号为标志,从左向右,第一个分组的组号为1,第二个为2,以此类推。

后向引用用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本。难以理解?请看示例:

\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, kitty kitty。首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字(\b(\w+)\b),然后是1个或几个空白符(\s+,最后是前面匹配的那个单词(\1)。

你也可以自己指定子表达式的组号或组名。要指定一个子表达式的组名,请使用这样的语法:(?\w+),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,你可以使用\k,所以上一个例子也可以写成这样:\b(?\w+)\b\s*\k\b

使用小括号的时候,还有很多特定用途的语法。下面列出了最常用的一些:

表4.分组语法
捕获
(exp)匹配exp,并捕获文本到自动命名的组里
(?exp)匹配exp,并捕获文本到名称为name的组里
(?:exp)匹配exp,不捕获匹配的文本
位置指定
(?=exp)匹配exp前面的位置
(?<=exp)匹配exp后面的位置
(?!exp)匹配后面跟的不是exp的位置
(?匹配前面不是exp的位置
注释
(?#comment)这种类型的组不对正则表达式的处理产生任何影响,只是为了提供让人阅读注释

我们已经讨论了前两种语法。第三个(?:exp)不会改变正则表达式的处理方式,只是这样的组匹配的内容不会像前两种那样被捕获到某个组里面

位置指定

接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们用于指定一个位置,就像\b,^,$那样,因此它们也被称为零宽断言。最好还是拿例子来说明吧:

(?=exp)也叫零宽先行断言,它匹配文本中的某些位置,这些位置的后面能匹配给定的后缀exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如果在查找I'm singing while you're dancing.时,它会匹配singdanc

(?<=exp)也叫零宽后行断言,它匹配文本中的某些位置,这些位置的前面能给定的前缀匹配exp。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading

假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?<=\d)\d{3})*\b。请仔细分析这个表达式,它可能不像你第一眼看出来的那么简单。

下面这个例子同时使用了前缀和后缀:(?<=\s)\d+(?=\s)匹配以空白符间隔的数字(再次强调,不包括这些空白符)

负向位置指定

前面我们提到过怎么查找不是某个字符或不在某个字符类里的字符的方法(反义)。但是如果我们只是想要确保某个字符没有出现,但并不想去匹配它时怎么办?例如,如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样:

\b\w*q[^u]\w*\b匹配包含后面不是字母u的字母q的单词。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为[^u]总是匹配一个字符,所以如果q是单词的最后一个字符的话,后面的[^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的\w+\b将会匹配下一个单词,于是\b\w*q[^u]\w*\b就能匹配整个Iraq fighting负向位置指定能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:\b\w*q(?!u)\w*\b

零宽负向先行断言(?!exp),只会匹配后缀exp不存在的位置\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字

同理,我们可以用(?,零宽负向后行断言来查找前缀exp不存在的位置(?匹配前面不是小写字母的七位数字(实验时发现错误?注意你的“区分大小写”先项是否选中)。

一个更复杂的例子:(?<=<(\w+)>).*(?=<\/\1>)匹配不包含属性的简单HTML标签内里的内容()指定了这样的前缀:被尖括号括起来的单词(比如可能是),然后是.*(任意的字符串),最后是一个后缀(?=<\/\1>)。注意后缀里的\/,它用到了前面提过的字符转义;\1则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)匹配的内容,这样如果前缀实际上是的话,后缀就是了。整个表达式匹配的是之间的内容(再次提醒,不包括前缀和后缀本身)。

贪婪与懒惰

当正则表达式中包含能接受重复的量词(指定数量的代码,例如*,{5,12}等)时,通常的行为是匹配尽可能多的字符。考虑这个表达式:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。

有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的量词都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:

a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aabab

表5.懒惰量词
*?重复任意次,但尽可能少重复
+?重复1次或更多次,但尽可能少重复
??重复0次或1次,但尽可能少重复
{n,m}?重复n到m次,但尽可能少重复
{n,}?重复n次以上,但尽可能少重复

表6.尚未讨论的语法
\a报警字符(打印它的效果是电脑嘀一声)
\b通常是单词分界位置,但如果在字符类里使用代表退格
\t制表符,Tab
\r回车
\v竖向制表符
\f换页符
\n换行符
\eEscape
nnASCII代码中八进制代码为nn的字符
\xnnASCII代码中十六进制代码为nn的字符
\unnnnUnicode代码中十六进制代码为nnnn的字符
\cNASCII控制字符。比如\cC代表Ctrl+C
\A字符串开头(类似^,但不受处理多行选项的影响)
\Z字符串结尾或行尾(不受处理多行选项的影响)
\z字符串结尾(类似$,但不受处理多行选项的影响)
\G当前搜索的开头
\p{name}Unicode中命名为name的字符类,例如\p{IsGreek}
(?>exp)贪婪子表达式
(?-exp)平衡组
(?-exp)平衡组
(?im-nsx:exp)在子表达式exp中改变处理选项
(?im-nsx)为表达式后面的部分改变处理选项
(?(exp)yes|no)把exp当作零宽正向先行断言,如果在这个位置能匹配,使用yes作为此组的表达式;否则使用no
(?(exp)yes)同上,只是使用空表达式作为no
(?(name)yes|no)如果命名为name的组捕获到了内容,使用yes作为表达式;否则使用no
(?(name)yes)同上,只是使用空表达式作为no



        转眼间一个月已过去,从认证系统的重新规划到现在即将完工,学了很多东西,php,js,ajax,css,mysql,ide...虽然大部分都是一些简单应用,不过总算掌握了入门的技巧。还得多谢网上的朋友,他们在我困难时的指点,比那些所谓的导师强多了。

        离开学不到三周,要看两门课,时间确实十分紧迫。记得大一看谭浩强老师那本C时,用了足足两个星期。虽然C那本书比较厚,(加起来比微机原理和数据结构这两门还厚,当然,微机只学汇编那部分。)作为基础课也算比较简单。数据结构考四级的时候大致了解了些概念,但从今天看书的效果来看,效果不太好(可能跟感冒有关^_^)。特别是刚才看的栈那章最后一个银行模拟的例子,根本没法搞清程序的思路。也许累了......

        这个星期将数据结构搞定,下个星期将汇编搞定,或者两本一起看,累了就换一本^-^。最后一星期再来一个大复习,时间应该还可以。最麻烦的是,还要搞一份三千字的实习报告,和一份公司盖章的实习表。说起实习报告还真奇怪,竟然限定内容,写什么三农之类的冬冬。我去实习程序员,写这些干嘛?

Tag: 琐事


        fleaphp 原来的分页查询比较简单,只能根据传入的$conditions进行单表的where查询,而复杂的多表查询只能自己写SQL语句,可惜现在的fleaphp还没提供这个接口。根据雷哥的提示,努力奋斗到昨晚一点多(还感冒啊!)终于搞定。写出来让大家指点一下:

fleaphp原来分页类的构造函数头如下,


    function FLEA_Helper_Pager(& $table, $currentPage,

$pageSize = 20, $conditions = null, $sortby = null)


 我新建一个超类,STUDENT_Helper_Pager extends FLEA_Helper_Pager,构造函数为


    function STUDENT_Helper_Pager(& $table, $currentPage,

$pageSize = 20,  $conditions = null, $sortby = null, $sql = null)

 


在最后传入SQL语句,因为fleaphp的分页构造函数里有这一句$this->count = $this->_table->findCount($conditions);计算满足当前查询条件的数量,后面一大窜计算各分页项的语句都以此值为基础,所以写复杂接口时要覆盖FLEA_Helper_Pager的构造函数,根据当前的SQL语句获取满足当前查询条件的数量$this->count。

修改$this->count = $this->findCount($sql);
在STUDENT_Helper_Pager里加入下面两个接口:


    function findCount($sql) {
        $sql = str_replace('*', 'count(*)', $sql);
        return (int)$this->_table->dbo->getOne($sql);
    }

    function & findBySql($sql) {
   $rs = $this->_table->dbo->selectLimit($sql,$this->pageSize,

$this->currentPage * $this->pageSize);
   $rowset = $this->_table->dbo->getAll($rs);
        return $rowset;
    }



第一个就是计算$this->count的值,第二个就是根据SQL语句作具体查询。还算比较简单吧...

        当然STUDENT_Helper_Pager要根据是否传入SQL语句判断是否进行复杂查询,是的话就覆盖FLEA_Helper_Pager的构造函数,重新计算$this->count的值,否则,直接将参数传入FLEA_Helper_Pager。下面是小弟的陋作:

function STUDENT_Helper_Pager(& $table, $currentPage, $pageSize = 20,$conditions = null, $sortby = null, $sql = null) {
  if($sql) {
        $this->_table =& $table;
        $this->sortby = $sortby;
        $this->pageSize = $pageSize;
        $this->count = $this->findCount($sql);
        $this->totalCount = $this->_table->findCount();
        $this->pageCount = ceil($this->count / $this->pageSize);
        $this->firstPage = 0;
        $this->lastPage = $this->pageCount - 1;
        if ($this->lastPage < 0) { $this->lastPage = 0; }
        if ($currentPage >= $this->pageCount) { $currentPage = $this->lastPage; }
        if ($currentPage < 0) { $currentPage = $this->firstPage; }
        $this->currentPage = $currentPage;
        if ($this->currentPage >= $this->pageCount) {
            $this->currentPage = $this->pageCount - 1;
        }
        if ($this->currentPage < 0) {
            $this->currentPage = 0;
        }
        if ($this->currentPage < $this->lastPage - 1) {
            $this->nextPage = $this->currentPage + 1;
        } else {
            $this->nextPage = $this->lastPage;
        }
        if ($this->currentPage > 0) {
            $this->prevPage = $this->currentPage - 1;
        } else {
            $this->prevPage = 0;
        }        $this->firstPageNumber = $this->firstPage + 1;
        $this->lastPageNumber = $this->lastPage + 1;
        $this->nextPageNumber = $this->nextPage + 1;
        $this->prevPageNumber = $this->prevPage + 1;
        $this->currentPageNumber = $this->currentPage + 1;  } else {
   parent::FLEA_Helper_Pager($table, $currentPage, $pageSize, $conditions, $sortby);
  }
}
Tag: FleaPHP PHP

分页共4页 1 2 3 4 下一页 最后一页