狗年来了

 心情随笔  1条评论 »
282006
 

时光飞逝,又一年就要过去了,同去年一样,我依旧留守在公司里,坚持到最后一刻,虽然连 User 都已经不在了,虽然 Office 里只剩下不到 20 个人。如果不是父母强烈要求,我想这个年我可能就留在公司宿舍里一个人过了,还有半个小时,打车,回家。

猛然想起偶的红内裤找不到了,还想穿着它迎接本命年的了,只能新年里再出去买了。。。

昨天萝卜打电话来:“你在外面?小心点,现在治安乱的很”

跟瓜条打电话,他说:“初五咱们聚一下吧,下午打麻将,吃个饭,洗个澡,K哥,泡吧……”

我想起了前天做的梦,我梦见花花坐在我边上,帮我倒酒,可是都倒了杯子外面,我马上用手去擦,发现我手接触到的是自己的泪水。。。

养爱情

 心情随笔  2 条评论 »
252006
 

如果有一天,你再也看不到我

□…  是否
  
  你会怪我将思念如此轻易放逐?
  
  在你转身的时候
  
  悄悄地 悄悄地从你身后逃离
  
  就此消失在苍茫的尘世间再也没有任何的消息与提示

□…  而当那一天终于无可避免时
  
  是否
  
  你会将自己的心情重新调整
  
  将记忆默默的收藏起来
  
  就在一个旁人无法触及的角落里
  
  你已经将我深深的藏好了
  
  从此不再让任问人问起你我的过往

□…  不断的徘徊在取舍之间
  
  不停的奔波在思念边缘
  
  直到你我都能清晰感觉到
  
  那份疲惫与乏累悄悄逼近
  
  正在逐渐吞噬着我岌岌可危的爱情

□…  或许
  
  在所有的心情平静以后
  
  你和我之间
  
  再也无法维系那一份残缺
  
  再也无法去守望那一段无痕的岁月
  
  终于
  
  终于让一切矛盾都划下了句号
  
  天空中再也没有眼泪

□…  如果真的有那么一天
  
  你再也找到不到我时
  
  那么
  
  请你一定要好好的保重自己
  
  因为你的幸福
  
  仍是我今生最大的心愿
  
  虽然你和我之间只是情深缘浅

正则表达式系统教程(一)

 技术学习  1条评论 »
252006
 

前言

  正则表达式是烦琐的,但是强大的,学会之后的应用会让你除了提高效率外,会给你带来绝对的成就感。只要认真去阅读这些资料,加上应用的时候进行一定的参考,掌握正则表达式不是问题。

索引

1. 引子

  目前,正则表达式已经在很多软件中得到广泛的应用,包括*nix(Linux, Unix等),HP等操作系统,PHP,C#,Java等开发环境,以及很多的应用软件中,都可以看到正则表达式的影子。

  正则表达式的使用,可以通过简单的办法来实现强大的功能。为了简单有效而又不失强大,造成了正则表达式代码的难度较大,学习起来也不是很容易,所以需要付出一些努力才行,入门之后参照一定的参考,使用起来还是比较简单有效的。

  例子: ^.+@.+\\..+$

  这样的代码曾经多次把我自己给吓退过。可能很多人也是被这样的代码给吓跑的吧。继续阅读本文将让你也可以自由应用这样的代码。

  注意:这里的第7部分跟前面的内容看起来似乎有些重复,目的是把前面表格里的部分重新描述了一次,目的是让这些内容更容易理解。

2. 正则表达式的历史

  正则表达式的“祖先”可以一直上溯至对人类神经系统如何工作的早期研究。Warren McCulloch 和 Walter Pitts 这两位神经生理学家研究出一种数学方式来描述这些神经网络。

   1956 年, 一位叫 Stephen Kleene 的数学家在 McCulloch 和 Pitts 早期工作的基础上,发表了一篇标题为“神经网事件的表示法”的论文,引入了正则表达式的概念。正则表达式就是用来描述他称为“正则集的代数”的表达式,因 此采用“正则表达式”这个术语。

  随后,发现可以将这一工作应用于使用 Ken Thompson 的计算搜索算法的一些早期研究,Ken Thompson 是 Unix 的主要发明人。正则表达式的第一个实用应用程序就是 Unix 中的 qed 编辑器。

  如他们所说,剩下的就是众所周知的历史了。从那时起直至现在正则表达式都是基于文本的编辑器和搜索工具中的一个重要部分。

3. 正则表达式定义

  正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。

  列目录时, dir *.txt或ls *.txt中的*.txt就不是一个正则表达式,因为这里*与正则式的*的含义是不同的。

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

  3.1 普通字符

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

  3.2 非打印字符

字符 含义
\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。

 

  3.3 特殊字符

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

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

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

 

  3.4 限定符

  限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有*或+或?或{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?’。请注意在逗号和两个数之间不能有空格。

落幕前的感謝

 心情随笔  没有评论 »
162006
 

Dear all EBs members:

下星一01/16 將是我帶各位最後的一天, 從星期二01/17開始, 這個重擔將落在 Johnny 身上, 請各位務必協助他讓組織的運作如常, 甚或更好. 有事記得多跟他討論.

時間過的真的很快, 三年的光陰如浮光掠影般的眨眼即過. 我們曾經一起面對許多困難、瓶頸, 甚或是流言蜚語, 當然, 也一起同歡共樂, 共品美食. 人生就是這樣, 酸甜苦辣鹹各有其味, 但總有許多的事值得回味. 這三年內, 我們組的運作可說是最順暢的了; 換版零失誤, 完善先進的系統規劃如恆星及每日C 讓系統穩定性最佳, 另外也成功建立客戶服務的形象, 這些都有賴於各位的用心努力才能達成. 這邊我要謝謝各位的支持與配合. 你們的付出與委曲、壓力, 甚或是喜怒哀樂, 我都看在眼裡, 也落實在對你們的規劃上. 也許難以事事盡如人意, 但捫心自問, 倒也盡力而為了. 我們組內氣紛融洽, 自我要求也高, 我們才能如此建立EB 組的特色與運作, 這是值得欣慰的事, 也讓我更加的不捨.

各位在今年仍有諸多挑戰要克服, “勤於思考, 勉於所行” 是送給各位的話. 當然, 也再一次老生常談那句話: “儘量去豐富你的生活, 拓展你的視野, 深耕自己的興趣, 明瞭自己的人生價值”. 各位都還年輕, 還有時間來思考這些, 但可別讓韶華虛度了. 還有, EB 組的特色各位要牢牢的維持住, 內向的人要朝開朗樂觀邁進, 開朗的人要朝嚴謹與創意努力. 事在人為, 相信有努力者, 明年的你自己會發現自己的進步的. 雖然只剩一個多月時間與各位相處, 但我相信大家會時常保持聯絡的. 各位若工作上遇到瓶頸, 感情上遇到茫然, 人生遇到不如意, 都歡迎找我聊, 我們一直是朋友勝於從屬的關係, 不是嗎? 我的主場落幕了, 我即將自這個舞台退場, 但各位的好戲即將上場, 你們將是最重要的角色, 好好堅持自己的理想、把握自己的方向吧! 祝各位事業、感情、生活美滿健康!

志銘 寫於蘇州 2006-01-13

纪念逝去的祖母

 心情随笔  没有评论 »
152006
 

你在天国过的还好么?

两年前的今天,我在BENQ面试的时候你走了,今天,我在HeJian的宿舍追忆您老人家。

没有香烛,我用香烟代替。

天堂里有没有上上下下

 心情随笔  4 条评论 »
152006
 

仅以此文献给我相识18年的挚友,杨青

2006年1月14日14:15分,医生的几句话,让久久守侯在门外的亲人朋友们失去了最后的一丝希望,一个年轻的生命就这样消失了,没有留下一句话。我以为只有在电视里小说里能感受到这样的场景,我知道我错了。

天下着雨,没有风,雨滴很小,可打在身上感到特别的冷,冰红茶象是加了许多冰块,而且没有一点甜味,烟让我的肺隐隐作痛……

这一天你们不是说好去上海拍结婚照的么?
你不是说过完年就要准备结婚,说邀请我做你的伴郎么?
你现在知道我们小学经常走的那条路上两边长的到底是广玉兰还是白玉兰了么?
你那时候为什么扔标枪的时候一直会往两边歪?
那次足球掉河里,我去捡球的时候,你干什么突然之间松开手,害我掉下水?
喝了那么多次酒,为什么每次你都不会醉?

你说你不会做作业,我就把我的给你抄
我说我不会游泳,你就钻到水底拉我的脚,害我呛了好多水
我走路上学的时候,你有自行车,于是带我
我骑车出去的时候,你有摩托车,又带我
你说买了汽车以后,我要是回家就可以来接我了
……

小鸭蛋拉着我说:“奶瓶,以后没有人陪你打麻将了”
我打一次输一次,可以后连输的机会都没有了
以后再也没机会坐车牌号ML093的摩托车了
以后吃完夜宵,没有人陪我走那条路一起回家了

元旦萝卜订婚那次,居然是我们最后一次见面,也是18年来喝最多酒的一次

花花,对不起,我写不下去了,好乱

你放心吧,天堂里不用加班,没有电梯,你大胆一点吧。

把MSN关了吧,我胆小,你这样开着大家看到会害怕,有事托梦给我好了。

记得:下辈子,我们依旧做兄弟。

醒过来吧

 心情随笔  1条评论 »
142006
 

兄弟,醒过来吧,大家都在等你

EveryoneIsHappye

 心情随笔  2 条评论 »
072006
 

boolean EveryIsHappy;
if (EveryIsHappy == true){
I will be happy;
}
In such lovely tonight , I drunk so much, any way ,I'am not lost my mind.
Open the computer ,enter the username and password, click the enter
Listening the music which chinese name is called 《飘雪》,a well listened song
thinging and thinking ……
It is really cold outside ,I get the answer when I walked around the whole round of our part.
Someone told me that he or her don't satisfy with her or his life,meybe no one is happy after drinking so much.
“hey ,the man ,shut up, u the son of bitch”
heard from the movie, may be i need to sleep,just deep sleep,make a perfect dream.
every thing is OK when I wake up.
Good Night everyon

I believe that:
Statis void publis class Happy(){
EveryIsHappy = true;
if (u r sad){
pls let me know;
}
}

Java源码分析:深入探讨Iterator模式

 技术学习  没有评论 »
042006
 

作者简介

廖雪峰,软件工程师,现从事J2EE开发,您可以通过asklxf@163.com与他联系。

正文

java.util包中包含了一系列重要的集合类。本文将从分析源码入手,深入研究一个集合类的内部结构,以及遍历集合的迭代模式的源码实现内幕。

下面我们先简单讨论一个根接口Collection,然后分析一个抽象类AbstractList和它的对应Iterator接口,并仔细研究迭代子模式的实现原理。

本文讨论的源代码版本是JDK 1.4.2,因为JDK 1.5在java.util中使用了很多泛型代码,为了简化问题,所以我们还是讨论1.4版本的代码。

集合类的根接口Collection

Collection接口是所有集合类的根类型。它的一个主要的接口方法是:

    boolean add(Object c)
            

add()方法将添加一个新元素。注意这个方法会返回一个boolean,但是返回值不是表示添加成功与否。仔细阅读doc可以看到,Collection规定:如果一个集合拒绝添加这个元素,无论任何原因,都必须抛出异常。这个返回值表示的意义是add()方法执行后,集合的内容是否改变了(就是元素有无数量,位置等变化),这是由具体类实现的。即:如果方法出错,总会抛出异常;返回值仅仅表示该方法执行后这个Collection的内容有无变化。

类似的还有:

    boolean addAll(Collection c);
            boolean remove(Object o);
            boolean removeAll(Collection c);
            boolean remainAll(Collection c);
            

Object[] toArray()方法很简单,把集合转换成数组返回。Object[] toArray(Object[] a)方法就有点复杂了,首先,返回的Object[]仍然是把集合的所有元素变成的数组,但是类型和参数a的类型是相同的,比如执行:

    String[] o = (String[])c.toArray(new String[0]);
            

得到的o实际类型是String[]。

其次,如果参数a的大小装不下集合的所有元素,返回的将是一个新的数组。如果参数a的大小能装下集合的所有元素,则返回的还是a,但a的内容用集合的元素来填充。尤其要注意的是,如果a的大小比集合元素的个数还多,a后面的部分全部被置为null。

最后一个最重要的方法是iterator(),返回一个Iterator(迭代子),用于遍历集合的所有元素。

用Iterator模式实现遍历集合

Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。

例如,如果没有使用Iterator,遍历一个数组的方法是使用索引:

    for(int i=0; i<array.size(); i++) { ... get(i) ... }
            

而访问一个链表(LinkedList)又必须使用while循环:

    while((e=e.next())!=null) { ... e.data() ... }
            

以上两种方法客户端都必须事先知道集合的内部结构,访问代码和集合本身是紧耦合,无法将访问逻辑从集合类和客户端代码中分离出来,每一种集合对应一种遍历方法,客户端代码无法复用。

更恐怖的是,如果以后需要把ArrayList更换为LinkedList,则原来的客户端代码必须全部重写。

为解决以上问题,Iterator模式总是用同一种逻辑来遍历集合:

    for(Iterator it = c.iterater(); it.hasNext(); ) { ... }
            

奥秘在于客户端自身不维护遍历集合的"指针",所有的内部状态(如当前元素位置,是否有下一个元素)都由Iterator来维护,而这个Iterator由集合类通过工厂方法生成,因此,它知道如何遍历整个集合。

客户端从不直接和集合类打交道,它总是控制Iterator,向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。

首先看看java.util.Iterator接口的定义:

    public interface Iterator {
            boolean hasNext();
            Object next();
            void remove();
            }
            

依赖前两个方法就能完成遍历,典型的代码如下:

    for(Iterator it = c.iterator(); it.hasNext(); ) {
            Object o = it.next();
            // 对o的操作...
            }
            

在JDK1.5中,还对上面的代码在语法上作了简化:

    // Type是具体的类型,如String。
            for(Type t : c) {
            // 对t的操作...
            }
            

每一种集合类返回的Iterator具体类型可能不同,Array可能返回ArrayIterator,Set可能返回SetIterator,Tree可能返回TreeIterator,但是它们都实现了Iterator接口,因此,客户端不关心到底是哪种Iterator,它只需要获得这个Iterator接口即可,这就是面向对象的威力。

Iterator源码剖析

让我们来看看AbstracyList如何创建Iterator。首先AbstractList定义了一个内部类(inner class):

    private class Itr implements Iterator {
            ...
            }
            

而iterator()方法的定义是:

    public Iterator iterator() {
            return new Itr();
            }
            

因此客户端不知道它通过Iterator it = a.iterator();所获得的Iterator的真正类型。

现在我们关心的是这个申明为private的Itr类是如何实现遍历AbstractList的:

    private class Itr implements Iterator {
            int cursor = 0;
            int lastRet = -1;
            int expectedModCount = modCount;
            }
            

Itr类依靠3个int变量(还有一个隐含的AbstractList的引用)来实现遍历,cursor是下一次next()调用时元素的位置,第一次调用next()将返回索引为0的元素。lastRet记录上一次游标所在位置,因此它总是比cursor少1。

变量cursor和集合的元素个数决定hasNext():

    public boolean hasNext() {
            return cursor != size();
            }
            

方法next()返回的是索引为cursor的元素,然后修改cursor和lastRet的值:

    public Object next() {
            checkForComodification();
            try {
            Object next = get(cursor);
            lastRet = cursor++;
            return next;
            } catch(IndexOutOfBoundsException e) {
            checkForComodification();
            throw new NoSuchElementException();
            }
            }
            

expectedModCount表示期待的modCount值,用来判断在遍历过程中集合是否被修改过。AbstractList包含一个modCount变量,它的初始值是0,当集合每被修改一次时(调用add,remove等方法),modCount加1。因此,modCount如果不变,表示集合内容未被修改。

Itr初始化时用expectedModCount记录集合的modCount变量,此后在必要的地方它会检测modCount的值:

    final void checkForComodification() {
            if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
            }
            

如果modCount与一开始记录在expectedModeCount中的值不等,说明集合内容被修改过,此时会抛出ConcurrentModificationException。

这个ConcurrentModificationException是RuntimeException,不要在客户端捕获它。如果发生此异常,说明程序代码的编写有问题,应该仔细检查代码而不是在catch中忽略它。

但是调用Iterator自身的remove()方法删除当前元素是完全没有问题的,因为在这个方法中会自动同步expectedModCount和modCount的值:

    public void remove() {
            ...
            AbstractList.this.remove(lastRet);
            ...
            // 在调用了集合的remove()方法之后重新设置了expectedModCount:
            expectedModCount = modCount;
            ...
            }
            

要确保遍历过程顺利完成,必须保证遍历过程中不更改集合的内容(Iterator的remove()方法除外),因此,确保遍历可靠的原则是只在一个线程中使用这个集合,或者在多线程中对遍历代码进行同步。

最后给个完整的示例:

    Collection c = new ArrayList();
            c.add("abc");
            c.add("xyz");
            for(Iterator it = c.iterator(); it.hasNext(); ) {
            String s = (String)it.next();
            System.out.println(s);
            }
            

如果你把第一行代码的ArrayList换成LinkedList或Vector,剩下的代码不用改动一行就能编译,而且功能不变,这就是针对抽象编程的原则:对具体类的依赖性最小。

Powered by WordPress 3.3.1 CopyRight 2004~2012, Sonic Tang

虚拟主机赞助商:海波,苏ICP备11082989号

Suffusion theme by Sayontan Sinha