【读书笔记】松本行弘的程序世界

原创 2013年08月11日 08:53:06
为什么开发Ruby
编程语言与效率关系太紧密。
Ruby的设计原则
简洁性:内存管理,变量和表达式的类型检查都可以在执行时自动进行
扩展性
稳定性


面向对象

面向对象与编程的关系

程序员不要沦为计算机的奴隶,要利用好计算机的告诉计算和信息处理能力。

怎样写程序:编程风格,算法,数据结构,设计模式,开发方法

多态性:(1各种数据可以统一处理,让程序知道要处理什么(what),而不是怎么去处理(how,(2)系统根据对象的不同自动选择最合适的处理办法,而程序内部则不发生冲突。(3)增强了程序扩展性,加入新数据改动较小。

数据抽象与继承

多态性、数据抽象和继承被称为面向对象的三原则。

软件研发的最大敌人是复杂性。

结构化编程的基本思想是有效的控制流,即把程序的执行顺序分为顺序、分支和循环三种,把共同的处理归结为例程。结构化编程的“限制”和“抽象化”是人类处理复杂软件的非常有效的工具。

但是,结构化编程没有保持处理和数据的一贯性面向对象编程是作为对抗数据复杂性的手段出现的。数据抽象是数据和处理方法的结合,对数据内容的处理和操作,必须通过实现定义好的方法来进行。数据和处理方法就成了一个黑盒子。

不仅是操作方法容易理解,抽象数据也能够对特定的操作产生反应的智能数据,用抽象数据可以更好的模拟现实世界中的实体。

多个相同的事物出现时,应该组合在一起,这就是DRY原则。程序的重复是一切问题的根源。为了避免重复,有两种方法:原型(使用原始对象的副本来作为新的相同的对象)、模版。

找出相似的部分来继承。把共同的部分提取出来生成父类的自底向上的办法。继承的原本目的是逐步细化。多重继承带来的三个问题:结构复杂化、优先数序模糊、功能冲突。

静态语言:规定变量和算式类型的语言。动态语言允许调用没有继承关系的方法。静态语言只能调用有继承关系的方法。静态语言的灵活性差,动态语言有没有错误只有执行了才知道,这样程序很简洁,效率也有所提高。

继承的两种含义:类都有哪些方法(规格的继承),类都用了什么数据结构和算法(实现的继承)。

Java在单一继承的前提下,使用组合模式(或委托)来调用别的类实现的共同功能,但是这样另外生成一个独立对象,每次方法调用都要传送给该对象,不合理,效率也不高。

动态语言没有继承规格,他要解决的就是多重继承的问题。

Mix-in采用以下规则来限制多继承:单一继承、第二个以及两个以上的父类必须是Mix-in的抽象类。Mix-in是具有以下特征的抽象类:不能单独生成实例、不能继承普通类。

两个误解(1)对象是现实世界中具体物体的反映,继承是对物体分类的反映。(2)多继承是不好的。

多态性是根据不同的数据类型而自动选择适当的处理。

对象的模版 类 , 利用模版的手段 继承

静态的类型不需要执行程序(编译期)就可以通过机器检测到这种人为错误。动态类型的编程语言至多只能发现程序的语法错误。静态类型也有缺点:灵活性、集中于数据类型会忽视更重要的部分。

动态类型编程语言的优点是(1)源代码简洁(2)更突出程序的本质。动态类型语言相比也要慢一些。动态类型的缺点主要有三个:执行时才能发现错误、读程序时可用线索少、运行速度慢。

元编程:对程序进行编程。比如反射。


程序块

程序块是方法调用时追加的代码块。可以把函数作为参数,构成高阶函数。高阶函数和块的本质是一样的。

C语言高阶函数的局限,传递参数两种方式:要么就明确传递参数,要么使用全局变量。

可以保存外部环境的闭包

1Ruby中,可以引用外部的局部变量。Java的匿名内部类也可以,C语言的指针也可以。

2、在块中可以引用外部局部变量的方法,这说明块不只是简单的程序代码,而且把外部环境也包含进来了,这样的块,叫做闭包。通常局部变量在方法执行完,就不存在了,但是如果被包含进了闭包,那么闭包期间,变量也存在

Ruby的块的使用方式

1、直接向函数传递代码块。也就是把这个代码块,作为参数传递给ruby

2、使用yield关键字。

块到底都干了什么

1、作为参数,传递给函数

2、在被调用的方法中可以执行传递过来的代码块,执行后程序的控制权返回给方法

3、块中最后执行的算式的值是块的值,这个值可以返回给方法。

块的其他使用的地方

1、可以用来实现新的控制结构

    2、可以在回调中使用。

导入块功能的目的就是对集合中的多个对象作循环处理,块功能和集合结合起来就能发挥更大作用。

设计模式

设计模式是程序抽象化的延伸。

设计模式原本是从面向对象的代码中总结出来的,但是现在的编程语言往往在语法级别就封装了一些常用的设计模式支持。

设计模式和具体编程语言无关,但是设计模式在各个具体语言里面的使用方法不尽相同。

面向对象的软件开发中有很多普遍存在的原则(Principle),在设计以及开发面向对象程序的时候,就应该遵循以下抽象原则:

开放-封闭原则(OCP) 

单一职责原则(SRP) 

Liskov替换原则(LSP) 

依存关系倒置原则(DIP)  

接口隔离原则(ISP) 

迪米特法则(LoD) 

合成/聚合复用原则(Composite/Aggregate Reuse Principle . CARP) 

我们的目标是使代码符合上面的这些原则,这是目的。我们如何达到这个目的呢?那就是使用设计模式,这是手段。目的比手段更抽象,也即原则比设计模式抽象程度更高。

设计模式可以分成3大类:有关生成的模式(5个),有关构造的模式(7个),有关行为的模式(11个)。

1. Singleton   单例模式 (生成) 

     说明:保证某个类的实例只有一个 

     为什么:系统全体只需要唯一一个这个对象

     如何做:

使用库的方法实现 

使用类或者模块 

把一般对象作为单例,重写new方法等等手段,这是一般语言常用的方法 

      总结:反正不管用什么手段,必须只有一个实例!必须的! 

2. Proxy 模式 (构造)

说明:为某个对象提供代理对象。 什么意思?

为什么:

不想把实现写死,调用程序只和Proxy打交道 

延迟加载具体程序,先加载Proxy 

屏蔽具体实现的复杂性,简化调用接口 

如何做:

库 

自己写代码(库其实也是别人写的代码) 

3. Iterator 模式 (行为) 

说明:提供按顺序访问集合对象中各元素的方法,即使不知道对象的内部构造

          也可以按顺序访问其中的每个元素。

为什么:为什么?

如何做:

类库只带实现,例如java里面的集合类,都是可迭代的,不过调用代码写起来比较拖沓 

语法自然实现,python里面就自然的实现,例如 for x in XXX. 

你自己写代码实现 

总结:这已经是最基本的东西了,几乎都不算是个模式了。在有闭包的语言ruby,内部迭代器。没有闭包java,外部迭代器。 

内部迭代器的缺陷:不能同时进行多个循环,也就无法实现按顺序比较2个集合元素的处理。所以返回外部迭代器也有它的优势!比较优秀的是内外部无缝集成。感觉上Ruby偏向于内部迭代,Python更偏向于语法级别的自然外部迭代。

外部迭代器的缺陷:外部迭代器的缺陷在于迭代器(光标)对象需要参照集合对象的内部信息。为了按顺序访问集合对象的各个元素,迭代器对象需要访问集合的内部构造,这就破坏了隐蔽集合内部构造的封装性原则。

4.Prototype

 (单词解释the first example of something, such as a machine or other industrial product, from which all later forms are developed

说明: 明确一个实例最为要生成对象的种类原型,通过复制该实例来生成新的对象。

          静态类型语言往往发挥不出这个模式的作用,在动态类型语言里面才能发挥它的巨大威力。

          甚至于 Prototype模式应该称之为编程范式(Paradigm)更合适。

          例如大部分编程语言从编程范式上来说都是类模式,但是JavaScript就是一种原型模式,JavaScript不直接定于类,

          然后由类来生成对象,而是直接复制对象,然后往对象上添加属性和方法变成新的对象。

为什么:自然而然

如何做:1. 编程范式级别 2.语法级

5. Template Method 模板方法 (为了编写抽象算法的模式) 

     说明:在父类的一个方法中定义算法的框架,其中几个步骤的具体内容则留给子类来实现。

     为什么:1. 可以在不改变算法构造的前提下,在子类中定义算法的一些步骤。

6. Observer 模式 (避免高度依赖)

     说明:当某个对象的状态发生变化时,依存于该状态的全部对象都自动(被动)得到通知,而且为了让他们都得到更新,定义了     对象间的一对多的依存关系。这是控制类与类之间依存关系的一种模式。

7. Strategy 模式

     说明:定义算法的集合,将各算法封装,使它们能够交换。


MVC


模型是表现窗口中表示内容的对象。模型代表的知识信息,它不能包含如何显示这些信息的信息。

视图,代表将模型中包含的信息在窗口中进行显示的对象。视图知道要表示的模型的信息,而模型一般不知道要表示自己的视图信息。

控制,从用户端接受输入,对视图和模型进行操作的对象。控制部分可以调用视图和模型,根据需要调整相应的方法,对应用程序整体进行控制。

视图可以访问模型,在窗口中显式模型的状态。视图部分能否访问控制部分要视不同应用而设定。模型没有必要设计成可以访问视图部分或控制部分。

以下来自维基百科

MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此之外,此模式通过对复杂度的简化,使程序结构更加直观。软件系统通过对自身基本部份分离的同时也赋予了各个基本部分应有的功能。专业人员可以通过自身的专长分组:

(控制器Controller负责转发请求,对请求进行处理。 

(视图View) 界面设计人员进行图形界面设计。 

(模型Model) 程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)。 


层次:模型(Model) “数据模型”(Model)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“模型”有对数据直接访问的权力,例如对数据库的访问。“模型”不依赖“视图”和“控制器”,也就是说,模型不关心它会被如何显示或是如何被操作。但是模型中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此模型的视图必须事先在此模型上注册,从而,视图可以了解在数据模型上发生的改变。(比较:观察者模式(软件设计模式))

视图(View) 视图层能够实现数据有目的的显示(理论上,这不是必需的)。在视图中一般没有程序上的逻辑。为了实现视图上的刷新功能,视图需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。

控制器(Controller) 控制器起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据模型上的改变。

评价及适用范围:MVC模式的缺点是由于它没有明确的定义,所以完全理解MVC模式并不是很容易。使用MVC模式需要精心的计划,由于它的内部原理比较复杂,所以需要花费一些时间去思考。开发一个MVC模式架构的工程,将不得不花费相当可观的时间去考虑如何将MVC模式运用到应用程序中,同时由于模型和视图要严格的分离,这样也给调试应用程序带来了一定的困难。每个构件在使用之前都需要经过彻底的测试。另外由于MVC模式将一个应用程序分成了三个部件,所以这意味着同一个工程将包含比以前更多的文件。

过去MVC模式并不适合小型甚至中等规模的应用程序,这样会带来额外的工作量,增加应用的复杂性。但现在多数软件设计框架,能直接快速提供MVC骨架,供中小型应用程序开发,此问题不再存在。对于开发存在大量用户界面,并且逻辑复杂的大型应用程序,MVC将会使软件在健壮性、代码重用和结构方面上一个新的台阶。尽管在最初构建MVC模式框架时会花费一定的工作量,但从长远的角度来看,它会大大提高后期软件开发的效率。

正则表达式学习笔记

  正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。
列目录时, dir *.txt或ls *.txt中的*.txt就
是一个正则表达式,因为这里*与正则式的*的含义是不同的。

  为便于理解和记忆,先从一些概念入手,所有特殊字符或字符组合有一个总表在后面,最后一些例子供理解相应的概念。

正则表达式

  是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。

  可以通过在一对分隔符之间放入表达式模式的各种组件来构造一个正则表达式,即/expression/

普通字符

  由所有那些未显式指定为元字符的打印和非打印字符组成。这包括所有的大写和小写字母字符,所有数字,所有标点符号以及一些符号。

非打印字符

字符 含义
\cx 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。

 

特殊字符

  所谓特殊字符,就是一些有特殊含义的字符,如上面说的"*.txt"中的*,简单的说就是表示任何字符串的意思。如果要查找文件名中有*的文件,则需要对*进行转义,即在其前加一个\。ls \*.txt。正则表达式有以下特殊字符。

特别字符 说明
$ 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符本身,请使用 \$。
( ) 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 \( 和 \)。
* 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
+ 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+。
. 匹配除换行符 \n之外的任何单字符。要匹配 .,请使用 \.。
[ 标记一个中括号表达式的开始。要匹配 [,请使用 \[。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。
\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\\' 匹配 "\",而 '\(' 则匹配 "("。
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 \^。
{ 标记限定符表达式的开始。要匹配 {,请使用 \{。
| 指明两项之间的一个选择。要匹配 |,请使用 \|。


  构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与操作符将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。

限定符

  限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有*或+或?或{n}或{n,}或{n,m}共6种。*、+和?限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配。

  正则表达式的限定符有:

字符 描述
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。

定位符

  用来描述字符串或单词的边界,^和$分别指字符串的开始与结束,\b描述单词的前或后边界,\B表示非单词边界。

不能对定位符使用限定符。

选择

  用圆括号将所有选择项括起来,相邻的选择项之间用|分隔。但用圆括号会有一个副作用,是相关的匹配会被缓存,此时可用?:放在第一个选项前来消除这种副作用。

  其中?:是非捕获元之一,还有两个非捕获元是?=和?!,这两个还有更多的含义,前者为正向预查,在任何开始匹配圆括号内的正则表达式模式的位置来匹配搜索字符串,后者为负向预查,在任何开始不匹配该正则表达式模式的位置来匹配搜索字符串。

后向引用

  对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左至右所遇到的 内容存储。存储子匹配的缓冲区编号从 1 开始,连续编号直至最大 99 个子表达式。每个缓冲区都可以使用 '\n' 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。

  可以使用非捕获元字符 '?:', '?=', or '?!' 来忽略对相关匹配的保存。

各种操作符的运算优先级

  相同优先级的从左到右进行运算,不同优先级的运算先高后低。各种操作符的优先级从高到低如下:

操作符 描述
\ 转义符
(), (?:), (?=), [] 圆括号和方括号
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $, \anymetacharacter 位置和顺序
| “或”操作

全部符号解释

字符 描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。
^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
? 当 该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。
. 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
(pattern) 匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。
(?:pattern) 匹 配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。
(?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern) 负 向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始
x|y 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。
[xyz] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
[^xyz] 负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\cx 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\d 匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。
\w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
\W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。
\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,'\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。.
\num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。
\n 标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
\nm 标 识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。
\nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。
\un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。

部分例子

正则表达式 说明
/\b([a-z]+) \1\b/gi 一个单词连续出现的位置
/(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/ 将一个URL解析为协议、域、端口及相对路径
/^(?:Chapter|Section) [1-9][0-9]{0,1}$/ 定位章节的位置
/[-a-z]/ A至z共26个字母再加一个-号。
/ter\b/ 可匹配chapter,而不能terminal
/\Bapt/ 可匹配chapter,而不能aptitude
/Windows(?=95 |98 |NT )/ 可匹配Windows95或Windows98或WindowsNT,当找到一个匹配后,从Windows后面开始进行下一次的检索匹配。


匹配中文字符的正则表达式: [\u4e00-\u9fa5]

匹配双字节字符(包括汉字在内):[^\x00-\xff]

应用:计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)

String.prototype.len=function(){return this.replace([^\x00-\xff]/g,"aa").length;}

匹配空行的正则表达式:\n[\s| ]*\r

匹配HTML标记的正则表达式:/<(.*)>.*<\/\1>|<(.*) \/>/

匹配首尾空格的正则表达式:(^\s*)|(\s*$)

应用:javascript中没有像vbscript那样的trim函数,我们就可以利用这个表达式来实现,如下:

String.prototype.trim = function()
{
return this.replace(/(^\s*)|(\s*$)/g, "");
}

利用正则表达式分解和转换IP地址:

下面是利用正则表达式匹配IP地址,并将IP地址转换成对应数值的Javascript程序:

function IP2V(ip)
{
re=/(\d+)\.(\d+)\.(\d+)\.(\d+)/g //匹配IP地址的正则表达式
if(re.test(ip))
{
return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1
}
else
{
throw new Error("Not a valid IP address!")
}
}

不过上面的程序如果不用正则表达式,而直接用split函数来分解可能更简单,程序如下:

var ip="10.100.20.168"
ip=ip.split(".")
alert("IP值是:"+(ip[0]*255*255*255+ip[1]*255*255+ip[2]*255+ip[3]*1))

匹配Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

匹配网址URL的正则表达式:http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?


整数和浮点小数

整数是有范围的。而C语言如果运算超出了规定的位数,不会报错,溢出的位仅仅被忽视了。

基本的位运算:取出特定位的状态、特定位置位、特定位清零、特定位反转。

表示负数的方法:(1)开头以为用作符号位(2)将整数的各位反转(1的补数)但负数一般用2的补数:正数反转,末位+1

小数编码成二进制:(1)抬高小数进行整数化(2)使用科学计数法。

小数不能完全表示,浮点数是有限的,且有误差,不满足结合律。

浮点数的比较也是有误差的,而且计算的误差也会累计的。

计算误差:舍入误差,最大值溢出和最小值溢出,信息丢失(两个数的指数部分相差很大),位数脱落(两个差别极大的数相加),截止误差。浮点数运算的陷阱可归结为:表示精度有限、以二进制表示。


高速执行和并行处理

程序在必要的时间内执行完毕就足够了,不要一味的追求高速。

通过数据为基础来判断系统性能优化的客观性:用户消费时间与系统消费时间的比率。但是,要避免测量太短的时间,反复测定。

改善系统调用。

只需要对瓶颈进行性能调优。

选择合适的算法,这是性能改善的第一考虑要素。

高速执行的悲哀:瓶颈无关的地方优化是徒劳无益的,改良绊住了手脚,算法选择的全套。

过早的优化是万恶之源,别做优化,对于专家而言,先不要做优化。

高速优化技巧:

发现瓶颈

削减对象:减少对象、减少方法调用。

利用立即值:小的整数,真假值,null和符号名等。

利用C语言

采用合适的数据结构

以空间换时间

并行编程

信息公有所产生的问题:数据整合性的丧失,死锁。

解决方法:锁、二级互斥、用队列协调线程。

Actor,是仅通过消息进行通信的实体。三种支持Actor Model的编程技术:Erlang, Revactor, Dramatis


程序安全性

4种软件漏洞:DOS攻击、信息泄漏、权限夺取,权限升格。

安全问题产生的根源在于运行软件的人和利用软件的人是不同的。安全问题有3种情况(1)恶意软件 (2setuid/setgid3)服务器

多样化的攻击手段:(1)缓冲区溢出(2)整数溢出(3)跨站点脚本攻击(4SQL注入(5)跨站点伪造请求

用异常进行错误处理:制作新的异常:名称、父类、生成方法。


函数式编程

以函数为中心内的函数式编程语言的特征:

函数本身也作为数据来处理

以函数为参数的高阶函数

参数相同即可保证结果相同的引用透明度

为实现引用透明性,进制产生副作用的处理

函数式编程的最大优点在于,程序可以按照数学的形式以及声明的形式来编写。


内存管理和垃圾收集

内存管理的困难

悬挂指针

内存泄漏

二重释放

评价垃圾收集的两个指标:吞吐量,暂停时间。

垃圾收集算法:引用计数算法,标记和清除算法,标记和紧缩算法,复制算法。

垃圾收集算法:分代垃圾收集,保守垃圾收集,增量垃圾手机,并行垃圾收集,位图标志。



相关文章推荐

《松本行弘的程序世界》读书笔记

半个月之前买了这本书,还是经园子里的一位网友推荐的。到现在看了一半多,基础的都看完了,剩下的几章可做高级部分来看。这本书看到现在,可以说感触很深,必须做一次读书笔记! 关于这本书,不了解的可以去网上...

读书笔记《松本行弘的程序世界》

松本行弘 是 Ruby语言的作者, 我没有学习Ruby语言, 只是特别崇拜他! 类是对象的模板,相当于对象的雏形。在具有类功能的面向对象编程语言5中,对象都是由作为雏形的类来生成的,对象的性质也是...

#读书笔记#松本行弘的程序设计·第一章

本章介绍了Matz创作Ruby的缘由。Matz从高中时候就开始编程。但他自认为自己是个“怪才”,因为别的程序猿普遍关注程序可以做什么,而他却更关注我们如何有效的和机器进行交流。驱使他完成Ruby创作的...
  • leorowe
  • leorowe
  • 2013年01月17日 07:10
  • 475

读《松本行弘的程序世界》

边读边记录,文章会很长,所以一次没办法写完面向对象: 该如何考虑在2.3.8提到的:只有包含继承关系的类才会具有多态性? 在编程时往往要求到的扩展性,实现扩展性的一个重要方法是抽象...
  • HEL_WOR
  • HEL_WOR
  • 2016年02月29日 20:38
  • 546

Ruby中的设计模式——《松本行弘的程序世界》

MicrosoftInternetExplorer402DocumentNotSpecified7.8Normal0    《设计模式》一书是用C++和Smalltalk介绍模式实例的。看了那些例子,...

《松本行弘的程序世界》中文版原作者序

  从年轻的时候开始,我就一直对编程语言有着极为浓厚的兴趣。比起“使用计算机去干什么?”这一问题,我总是一门心思在想着“如何将自己的意图传达给计算机?”。从这个意义上说,我认为自己是个“怪人”。但是,...

《松本行弘的程序世界》精彩书摘

《松本行弘的程序世界》精彩书摘 Posted on September 6, 2011 by lowerthan60 以下是2011年4月份在复审《松本行弘的程序世界》期间,随手摘录发...

多重继承不好的观点是错误的 — 小评<松本行弘的程序世界>

首先得说, 一般某种语言的发明人写的关于自己语言的东西都是非常值得阅读的, 从别的牛人那里你也许能学会很多奇技淫巧, 但从语言发明人那里你能学到语言发明人本身设计的初衷, 以及设计时的一些抉择. 这种...
  • vagrxie
  • vagrxie
  • 2013年01月08日 01:35
  • 16831

松本行弘的程序世界(二)

编程和面向对象的关系 颠倒的构造 1.      有一个有趣的例子,叫做“阿尔法法则”。机器是人的奴隶,还是人沦为机器的奴隶。这个我有不同于作者的观点。人机是交互的,或者说是对等的。人和计算机打交...
  • viekie
  • viekie
  • 2012年04月18日 20:18
  • 655

动态类型静态类型的优缺点--《松本行弘的程序世界》

偶然今天看到了《松本行弘的程序世界》一书,作者对静态类型和动态类型的优缺点做了详细的解释: 静态类型的优点:         1, IDE聪明的提示,因为静态类型的语言的类型是确定的,所以...
  • KimboQi
  • KimboQi
  • 2012年05月08日 18:51
  • 879
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【读书笔记】松本行弘的程序世界
举报原因:
原因补充:

(最多只允许输入30个字)