C中的字符判断函数(ctype.h)

6月 26th, 2008

isalnum 判断一个字符是否是字符类的数字或者字母
isalpha 判断一个字符是否是字母
isblank 判断一个字符是空白字符(空格和水平制表符Tab)
iscntrl 判断一个控制符(ascii码0-31之间的字符)
isdigit 判断一个字符是否是字符类的数字
isgraph 判断一个字符是否是可打印字符(ascii码33-126之间的字符)
islower 判断一个字符是否是小写字母
isprint 判断一个字符是否是包含空格在内的可打印字符(ascii码32-126之间的字符)
ispunct 判断一个字符是否是除空格,字母,数字外的标点符号
isspace 判断一个字符是空白字符(空格,换行符(\n),走纸符(\f),回车符(\r),垂直制表符(\v),水平制表符(\t))
isupper 判断一个字符是否是大写字母
isxdigit 判断一个字符是否是一个十六进制的数字
tolower 将大些字符转换为小写
toupper 将小写字符转换为大写

isalnum()函数的作用是判断一个字符是否是字符类的数字或者字母:

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    if(isalnum('a'))
        printf("It's True"); // 显示 It's True
    if(isalnum(4))
        printf("It's True"); // 显示 ''
    if(isalnum('4'))
        printf("It's True"); // 显示 It's True
    return 0;
}

isalpha()函数的作用是判断一个字符是否是字母:

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    if(isalpha('a'))
        printf("It's True"); // 显示 It's True
    if(isalpha(4))
        printf("It's True"); // 显示 ''
    if(isalpha('4'))
        printf("It's True"); // 显示 ''
    return 0;
}

isblank()函数的作用是判断一个字符是空白字符(空格和水平制表符Tab),isspace()函数和isblank()函数类似,但是还包含空格,换行符(\n),走纸符(\f),回车符(\r),垂直制表符(\v),水平制表符(\t):

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    if(isblank(' ')) // 空格
        printf("It's True"); // 显示 It's True
    if(isblank('\t')) // Tab
        printf("It's True"); // 显示 It's True
    if(isblank('\n')) // 换行
        printf("It's True"); // 显示 ''
    if(isblank('\r')) // 回车
        printf("It's True"); // 显示 ''
    if(isspace(' ')) // 空格
        printf("It's True"); // 显示 It's True
    if(isspace('\t')) // Tab
        printf("It's True"); // 显示 It's True
    if(isspace('\n')) // 换行
        printf("It's True"); // 显示 It's True
    if(isspace('\r')) // 回车
        printf("It's True"); // 显示 It's True
    return 0;
}

iscntrl()函数的作用是判断一个控制符(ascii码0-31之间的字符):

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    if(isblank(' ')) // 空格
        printf("It's True"); // 显示 ''
    if(isblank('\t')) // Tab
        printf("It's True"); // 显示 It's True
    if(isblank('\n')) // 换行
        printf("It's True"); // 显示 It's True
    if(isblank('\r')) // 回车
        printf("It's True"); // 显示 It's True
    return 0;
}

isdigit()函数的作用是判断一个字符是否是字符类的数字:

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    if(isdigit('4'))
        printf("It's True"); // 显示 It's True
    if(isdigit(4))
        printf("It's True"); // 显示 ''
    if(isdigit('a'))
        printf("It's True"); // 显示 ''
    return 0;
}

isgraph()函数的作用是判断一个字符是否是可打印字符(ascii码33-126之间的字符),isprint()函数功能和isgraph()函数类似,区别是isprint()函数包含空格在内(ascii码32-126之间的字符):

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    if(isgraph('a'))
        printf("It's True"); // 显示 It's True
    if(isgraph('.'))
        printf("It's True"); // 显示 It's True
    if(isgraph(' ')) // 空格
        printf("It's True"); // 显示 ''
    if(isprint('a'))
        printf("It's True"); // 显示 It's True
    if(isprint('.'))
        printf("It's True"); // 显示 It's True
    if(isprint(' ')) // 空格
        printf("It's True"); // 显示 It's True
    return 0;
}

islower()函数的作用是判断一个字符是否是小写字母,isupper()函数的作用是判断一个字符是否是大写字母:

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    if(islower('a'))
        printf("It's True"); // 显示 It's True
    if(islower('A'))
        printf("It's True"); // 显示 ''
    if(isupper('a'))
        printf("It's True"); // 显示 ''
    if(isupper('A'))
        printf("It's True"); // 显示 It's True
    return 0;
}

ispunct()函数的作用是判断一个字符是否是除空格,字母,数字外的标点符号:

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    if(ispunct('a'))
        printf("It's True"); // 显示 ''
    if(ispunct('.'))
        printf("It's True"); // 显示 It's True
    if(ispunct('<'))
        printf("It's True"); // 显示 It's True
    return 0;
}

isxdigit()函数的作用是判断一个字符是否是一个十六进制的数字:

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    if(isxdigit('4'))
        printf("It's True"); // 显示 It's True
    if(isxdigit('xE'))
        printf("It's True"); // 显示 It's True
    if(isxdigit('xF'))
        printf("It's True"); // 显示 ''
    return 0;
}

tolower()函数的作用是将大些字符转换为小写,toupper()函数的作用是将小写字符转换为大写:

#include <stdio.h>
#include <ctype.h>

int main(void)
{
char n,m,i,j;

n = tolower('A');
m = tolower('a');
i = toupper('a');
j = toupper('.');
        printf("%c %c %c %c", n, m, i, j); // 显示 a a A .

    return 0;
}

《新话的原则》

6月 25th, 2008

  新话是大洋国的官方语言,它的发明是为了满足英社(英国社会主义)的意识形态的需要。在一九八四年,无论口头还是书面,还没有人能够把新话作为他惟一的交流工具。虽然《泰晤士报》上的社论都是用新话写成,但这种技艺只有专家才能掌握。预计到二○五○年,新话会最终取代老话,也就是我们说的标准英语。与此同时,它稳步发展,全部的党员在他们的日常会话中都会越来越多地使用新话的单词和语法结构。一九八四年使用的这个版本,我们可以在《新话词典》第九和第十版中找到,它只是一个临时版本,里面的许多多余的词汇和过时的结构,以后一定会淘汰。这里我们关注的,只是它最新的、也是最完备的一个版本,它可见于《新话词典》第十一版。

  新话的目的,不仅是要为英社的支持者提供一种适合于他们的世界观和智力习惯的表达手段,而且是要消除所有其他的思考模式。这样在新话被采用、老话被遗忘之后,异端思想、也就是有违于英社原则的思想,就根本是不可思想的了,至少只要思想还依赖文字,那就会这样。它在造词的时候,使党员希望正确表达的每一种意思都可以确切地、而且往往是微妙地表达出来;至于其它的意思,甚至用间接手段获得这些含义的机会,都完全不存在。之所以能够做到这一点,部分是由于发明了新词,但更主要地,是取消了那些让人讨厌的词汇,清除那些还带有非正统含义的词汇,可能的话,还要消除那些含义不统一的词汇。举个简单的例子,新话中也有"free"(自由)一词,但它只能用在 "This dog is free from lice"(这条狗身上没有虱子), "This field is free from weeds"(这块地没有杂草)一类的陈述中,从前 "politically free"(政治自由),"intellectually free"(思想自由)这种意义上的自由现在不能再用,因为政治自由和思想自由即使作为概念也已经不再存在,因此必定没有名称了。减少词汇远不止是要取缔确实是异端的词语,据认为它本身就是目的,凡是能够略掉的词汇就都不用。新话的发明不是要拓宽、而是要缩小思想所及的范围,而把词汇减少到最低程度间接地促成了这个结果。

  新话以我们今天使用的英语作为基础,虽然新话中有许多句子,即使没有新造的词汇,叫今天使用英语的人也几乎认不出来。新话中词汇有ABC三类,其中B类又称复合词。三类词分开讨论比较方便一些,而语法上的特点我们放在A类词中一起讨论,因为三类词都遵循同样的规则。

  A类词。

  组成A类词的,是日常事务中必须使用的那些词,比如饮食、工作、穿衣、上楼、下楼、驾车、种花、烹饪等等。它几乎全部都是我们已经使用过的那些词,如打、跑、狗、树、糖、房屋、田野等等,但与今天我们所用的英语相比,它的数目非常之小,而意义又受到严格得多的限定。凡是意思上模棱两可、有细微差别的地方,都一概删除。倘若这样,那么一个A类词就只是一种独立的喉音,表示我们都明白知道的一个概念。这样,想把A类词用到文学上,用到政治和哲学的讨论中,就完全不可能了。它所要表达的,只是简单、有明确意图的思想,通常都是涉及具体物体或者身体的动作。

  新话的语法有两大特点。第一是不同词性的词几乎可以完全混用。它的任意一个词,既可以用作动词,也可以用作名词、形容词或者副词,从原则来说,即使像"if"(如果)"when"(当……的时候)这样非常抽象的名词也不例外。词根相同的词,它的动词形式和名词形式没有任何不同,这条规则把很多古代的形式都废除了。例如,新话中没有"thought"(名词"思想")这个词,代替它的是"think"(动词形式的"思想"),它既可以做名词,又可以做动词。这里没有什么词源学的原则,有时它保留原来的名词形式,有时又保留动词形式。很多时候,如果一个动词和一个名词词义相同,即使它们的词源没有任何关系,也会把某一个废弃不用。比如,像"cut"("割")这个词就没有了,它的含义完全包含在动词兼名词的"knife"("刀")里面。形容词的构成就是在动词兼名词的词后面加后缀"ful"("的"),副词加"wise"("地")。这样,比方说,"speedful"就表示"迅速的"(代替了"rapid"),"speedwise"就表示"迅速地"(代替了"quickly")。我们现在用的一些形容词,像"好的"、"强的"、"大的"、"黑的"、"软的",也保留下来,但总数很少。它们没有多少存在的必要,因为只要给那些动词兼名词的词加上"ful"就可以表示形容词的意思了。现在我们使用的副词,除了极少数本来是"wise"结尾的,其余一概不用;词尾"wise"是不变的。比如像"well"就改成了"goodwise"。

  此外,每个词只要加上前缀"un"就可以表示否定,加上前缀"plus"就表示强调,进一步强调就加"doubleplus",原则上新话每一个词都是这样。比如,"uncold"("不冷")表示"warm"("暖和"),"pluscold"表示"非常冷","doublepluscold"则表示"非常非常冷"。新话也可以像现代英语一样,加上介词前缀比如"ante"、"post"、"up"、"down"等就可以改变差不多每一个词的词义。这样它就可以大大减少词汇量了。比如,有了"good"(" 好")这个词,"bad"这个词就没有必要了,因为用"ungood"("不好")一词就可以表达我们希望的意思,而且表达得同样之好,–事实上是更好。凡是有两个词天然就组成反义词的时候,就必须加以取舍。比如,可以用"unlight"("不光明")一词代替"dark"("黑暗"),也可以用"undark"("不黑暗")一词代替"light"("光明"),视喜好而定。

  新话语法的第二个显著特征是它的规则性。除了下面提到的少数几个例外,所有词形的变化都遵循同样的规则。这样,每个动词的过去式和过去分词就都是以"ed"结尾,"steal"的过去式就成了"stealed","think"的过去式是"thinked",新话中其他的词也是一样,而 "swan","gave","brought","spoke""taken"等等这些形式就都废除了。所有的复数都加"s"或"es",这视情况而定。这样,"man","ox","life"的复数就变成了"mans","oxes","lifes"。形容词的比较级就都加"er"、"est" (比如"good,gooder,goodest"),不规则形式以及用"more"、"most"表示的形式全部取消。

  惟一允许可以做不规则变化的词是代词、关系代词、指示形容词和副词。这些词都和从前的用法一样,只有"whom"由于被认为多余而去掉了;用"shall"、"should"表示的时态都不再使用,它们的用法包含在"will"和"would"之中。为了快速简练的演讲需要,也有一些词形存在不规则变化。一个不容易念或者容易听错的词,就可以说是个坏词。因此,有时出于听觉的考虑,会在一些词中插入一些字母,或者保留从前的形态。但这主要是B类词。为什么发音简便这么重要,后文便可分晓。

  B类词。

  B类词都是为了政治目的而有意造出来的,这就是说,这些词不仅有政治的含义,而且是要给使用者具有它所希望的思想态度。如果不充分了解英社的原则,就不能正确使用这些词。有些时候它们也能够转化为老话,或者转化成A类词,但这往往需要加上长长的注释,而且总免不了失去一些言外之意。B类词是一种口头速记法,它常常把一整套思想塞进几个音节中,但同时却比普通语言更加精练。

  B类词都是复合词。它们由两个或两个以上的词,或者从几个词中抽取一部分组成,它的结合的方式很方便口语。这些新词一般都是动词兼名词,它们的变形遵守一般的规则。举个简单的例子,"goodthink"("好思想")一词大致就表示"orthodoxy"("正统"),如果把它当作动词,就表示"用正统的方式思想"。它的形态变化如下:动词兼名词"goodthink",过去式和过去分词"goodthinked",现在分词"goodthinking",形容词"goodthinkful",副词"goodthinkwise",动名词"goodthinker"。

  B类词的构造没有任何词源学的统一方案。它们构成的词,可以充当句子的每一种成分,可以任意颠倒、删改,只要便于发音同时又表示了词的来源。比如"crimethink"("犯罪思想")里,"think"("思想")在后;在"thinkpol"("思想警察")里它又放在前面,而这个词中"police"("警察")的后一个音节就丢掉了。要保证发音悦耳动听,这很难办到,所以B类词中不规则形式比A类词更常见。比如, "Minitrue"("真部"),"Minipax"("和部"), "Miniluv"("爱部")的形容词形式分别是"Minitruthful", "Minipeaceful", "Miniloveful",原因是如果发音发成 "trueful", "paxful", "loveful"就有点不太自然。但原则上B类词的词形都可以变化,而且变化的方式也几乎相同。

  B类词中,有一些词含义非常微妙,没有吃透这门语言的人是根本看不出来的。比如,举一个《泰晤士报》社论中很典型的句子, "Oldthinkers unbellyfeel Ingsoc",换成老话,最简短的说法是,"思想形成于革命之前的人无法对英国社会主义的原则有充分感情上的理解",但这么翻译并不完整。首先,要完全理解这句新话的全部含义,我们就要明白"Ingsoc(英社)"是什么意思;此外,只有精通英社的人才能品味出"bellyfeel"的整个力量所在,它指的是一种我们今天难以想象的盲目热烈的接受;还有"oldthink"一词,里面就夹杂有邪恶腐朽的意思。但是,包括"oldthink"在内,新话中有些词有特殊的功能,它们与其说是要表达某种含义,不如说是取缔某种含义。这些词为数不多,但它们的含义可以一直引申,最后我们原来用一组词来表示的含义,都由这一个词概括了,而这一组词现在也就可以从记忆中抹去了。《新话词典》的编撰者遇到的最大困难不是要发明新词,这些词已经造出来了,他们的最大困难是要弄清这些词的确切含义,也就是弄清被它们取代的那一组词。

  正如前面"free"所揭示的那样,有些曾经有过异端含义的词,为了方便也保留了下来,但除去了其中不合适的含义。其它有许多词,比如"荣誉","正义","道德","国际主义","民主","科学","宗教"等等,都停止使用。这些词,由另外一些词掩盖住它们,而这种掩盖实质就是取消。比如,所有与自由和平等概念相关的词,都由"crimethink"("犯罪思想")这个简单的词来遮盖,而与客观、理性有关的词都由"oldthink"("旧思想")一词包括进去。过分的精确会带来危险,党员所要求做到的,是具有一种类似于古希伯来人的观念:他知道得不多,只知道除自己以外,其它民族崇拜的都是 "伪神"。他无须知道这些"伪神"叫什么名称。或许他知道得越少,越有助于他的正统。他知道耶和华和耶和华的戒律,由此又知道其它名字、其它属性的神都是"伪神"。党员的情况与之近似。他们知道什么行为正确,也含糊笼统地知道有哪些行为背离了正道。比如,他的性生活受到两个词的管制,"sexcrime"("性犯罪")和"goodsex"("性正常")。性犯罪包括所有性方面的不良行为,乱伦、通奸、同性恋以及其它性变态都是性犯罪,而且,正常的性行为,如果它是以性生活本身为目的,也属于性犯罪。没有必要把它们分开列举,因为它们都同样是犯罪,按原则都要处以死刑。对于C类词,它都是科学技术的词汇,也许还需要给某些不检点的行为规定专门的名称,但普通公民并不需要。一个普通公民知道什么是"性正常",它就是夫妻之间为了生育进行的性交,而且女方是没有快感的;别的就都是"性犯罪"。在新话中,人们对异端思想的了解,除了知道它是异端以外,就不能再进一步了,因为根本就没有更进一步的词汇。

  B类词在意识形态上都不是中立的,大量存在的是一些委婉的说法,比如"幸福院"其实是指强劳营,"和平部"实际是战争部,字面的意思和实际的所指几乎正好相对。另有一些词则表现了对大洋国社会真实本质的一种坦率而蔑视的看法,比如,"prolefeed"指的是党施舍给群众的那种廉价娱乐和虚假消息。还有一些词具有双重的色彩,如果形容党就表示肯定,形容敌人就表示否定。此外还有大量的词,它们初看起来只是一些缩略语,它的意识形态色彩不是来自它的含义,而是来自结构。

  凡是有可能,任何政治上略有影响、或可能有影响的事物都放到了B类词里。一切组织、团体、学说、国家、机构、公共建筑,它们的名字总要经过删削,以一种常见的形式出现,也就是音节要尽可能少,要便于发音,同时又保留词的最初来源。比如真理部下属的记录总局,也就是温斯顿·史密斯工作的地方,就叫"记总",小说总局叫"说总",电讯总局叫"电总",诸如此类。这不只是为了节省时间。早在世纪之初,政治语言的一个特点就是使用经过压缩的词和词组;而且已经发现,使用这种缩略语的现象最显著的是在极权主义的国家和组织,像"纳粹"、"盖世太保"、"共产国际"这些词就是例子。这种做法一开始只是本能,但新话却是有意识地加以运用。人们发现一个名字像这么缩减以后,附着在上面的许多联想就都消失了,它的含义因而受到限制,并且有了微妙的变化。比如像"共产主义者的国际性组织",让人联想到的是一幅由人类友爱、红旗、街垒、卡尔·马克思和巴黎公社组成的画面,而"共产国际" 暗示人们的却是一个严密的组织、一种明确的教义,指代的像是某种椅子、桌子一样容易辨认、用途有限的东西。一个人说"共产国际"的时候几乎可以不用思考,而碰到"共产主义者的国际性组织",他必定免不了一丝踌躇。同样,像"Minitrue"这样的词激起的联想就比"Ministry of Truth"要少得多,可控制得多。这就可以解释,为什么一有可能,人们就喜欢用简称;还可以解释,为什么人们小心翼翼力求每个词都易于发音,简直到了不合时宜的程度。

  在新话里面,除了词义的准确以外,声音的悦耳最为重要,必要时语法的规则也要服从于它。这也合该如此,因为出于政治的考虑正要求有含义准确无误、发音短促清楚的词汇,使发言者能够吐字迅速,但心里几乎没有任何余响。B类词中,几乎个个相似,这使得它更加显出力量。这些词,比如 "goodthink", "Minipax", "prolefeed", "sexcrime", "joycamp", "Ingsoc", "bellyfeel", "thinkpol",以及其它无数的词,音节都只有两、三个,首末的音节同样重读。使用这些词有助于养成急促简练的说话风格,顿挫有力而又单调乏味,而这正是党所希望的。党的意图正是要使得言谈、尤其是意识形态并非中性的问题上的谈话尽可能脱离人的意识。日常生活中有时无疑需要思索之后再发言,但党员响应号召对政治或伦理问题的表态,就应当能够脱口说出正确的意见,犹如机枪发射子弹一样全然是自动地进行。他受到的训练使他能够适应这种要求,语言本身又给了他几乎万无一失的工具,而词的构成,再辅之以急促、不堪入耳的发音,–这与英社精神是相吻合的,–更有利他的发挥了。

  另一点也有很大的帮助,那就是供选择的词语非常之有限。相比我们所用的词汇,新话的词汇量很少,而且还不断地发明新方法减少词汇。事实上,新话的与众不同之处正在于它的词汇每年不是递增,而是递减。每减少一次,它的成果就增加一分,因为选择余地越少,思想的诱惑越小。最终党所希望的是,一个人说话的时候只有喉咙在发声,而没有更高等的神经中枢的参与。新话中有一个词"duckspeak"就很直率地表明了党的这种用意,它的意思是"像鸭子一样嘎嘎叫"。"duckspeak"与其它许多B类词一样,含义也是模糊的:倘若嘎嘎叫出的都是正统的观点,这个词就只是表示赞扬;像《泰晤士报》用"doubleplusgood duckspeaker"来称呼党的某位演说家的时候,那就是在高度地、热烈地恭维。

  C类词。

  C类词只是其它两类词的补充,里面全是科技术语,类似于今天我们使用的术语,词根也相同,不过仍与平时一样,很小心翼翼地对它们做了严格的限定,删除那些不愉快的含义。它的语法规则与A、B两类词完全相同。C类词几乎都是不见于日常的谈话或者政治的演说的。一个科技工作者,在为他的专业提供的目录上,就可以发现他需要的全部词汇;而对其它领域的词汇,他就几乎一无所知。只有极少的词才是各个领域共同的,我们也找不到什么词汇能够无视科学的具体分支,把科学的功能表述为一种思想习惯,或者一种思考方式,事实上表示"科学"的词都是没有的,它可能具有的全部含义现在都由"英社"一词整个包含了。

  从上面的讨论可以看出,要用新话来表达异端的思想,几乎毫无可能,除非只是在一种很低的水平上。要说一些很拙劣的异端思想,说一些谩骂亵渎的话,自然也是可能的,例如可以说"老大哥不好"。但在一只正统的耳朵听来,这说的不过是一种不证自明的谬误;由于找不到必需的词汇,它也无法用理性的论证来为自己辩护。反对英社的思想只能是一些含糊的、非语言状态的东西,而且只能用一些很笼统的词汇加以命名:这些词汇堆放在一起,对异端思想只做总体的鞭挞而从来没有明确的说明。实际上一个人要抱了非正统的目的使用新话,那只有秘密地把它的词汇转而翻译成老话。例如,新话中可以说"人人都是平等的",但这与老话中说"人人都是红头发的"没有什么区别。它没有语法错误,但它表示人人都有同样的身高,同样的体重和力气,显而易见是一个错句。政治平等的概念已经消失,这一种衍生的平等含义已经从"平等"这个词中删除了。在一九八四年,由于老话仍是一种正常的交流工具,使用新话的时候存在一个理论的危险,那就是人们可能联想到词的原始含义。但实践当中,一个精于双重思想的人是不难克服这一点的,而再过两三代人,这种可能性就彻底消除了。一个伴随着新话长大、始终只是使用新话的人,不会知道"平等"一词曾经有过"政治平等"这一种衍生的含义,也不会知道"自由"曾经有"思想自由"的意思,这就类似于一个不知象棋为何物的人,不会知道"王后"和"车"还有其它的含义一样。有很多的罪行、错误,他是没有能力去做的,原因只是在于,这些罪行、错误全没有名字,也就无法想象。可以预见,随着时间的流逝,新话的一个显著特征,词汇越来越少,词义越来越严格,滥用的可能性越来越小,也会变得越来越明显。

  一旦老话被完全取代,与旧世界的联系就完全割断。历史已经做了改头换面的书写,但从前的文献会有断片留存,逃避检查,如果还懂得老话便能够阅读。在将来,这样的断片即使侥幸留存,也无法辨认、无法译读了。老话里,除非指的是某种技术过程,某种简单的日常行为,或者本身的倾向就已经很正统(新话叫做"goodthinkful"),它的所有段落都是无法翻译成新话的。实践中这就表示,凡是大约一九六○年以前写作的书,总体上都属不可翻译的了。革命前文献的翻译,只能是一种意识形态的翻译,不仅语言、而且含义都要做变化。这里以《独立宣言》中著名的一段话为例:

  我们认为下述的真理是不证自明的:人人生而平等,他们由造物主赋予而享有不可剥夺的权利,其中包括生命、自由和追求幸福的权利。为了确保这些权利,政府在人群之上建立,它的权力来自被治者的同意。凡任何时候、任何政府有害于这些目的,人民有权利改变它,废除它,建立新政府。

  这一段要译成新话而不失去原意几乎不能做到。最可能的,无非是用一个简单的词"犯罪思想"概括整个段落。要完全译出,那只能是一种意识形态的翻译,把杰弗逊的话译作对绝对政府的颂词。

  事实上,过去的文献都大量作了这一类的改造。出于声望的考虑保留对某些历史人物的记忆当然是有利的,但与此同时他们的成就必须符合英社的哲学。因而,像莎士比亚、弥尔顿、斯威夫特、拜伦、狄更斯等等,这些作者都属于正被翻译的行列;一旦翻译完成,他们原始的作品,各种残存的历史文献,都要被销毁。翻译是一项缓慢而艰难的事业,预计要到二十一世纪的前十年或二十年才能完成。还有大量纯粹功用目的的文献,比如少不得的技术手册一类的东西,也会如法炮制。而所以最终全部采用新话的时间会订得那么晚,要到二○五○年,主要就是为了有充裕的时间完成初步的翻译工作。

选自奥威尔《1984》

C中的字符串函数(string.h)

6月 23rd, 2008

void *memcpy(void *dest, const void *src, size_t n); copies n bytes between two memory areas, which must not overlap
void *memmove(void *dest, const void *src, size_t n); copies n bytes between two memory areas; unlike with memcpy the areas may overlap
void *memchr(const void *s, int c, size_t n); 返回字符串的前N个字符中第一次匹配某个字符的指针。
int memcmp(const void *s1, const void *s2, size_t n); 比较内存地址中的前N个字符。
void *memset(void *, int, size_t); 用指定的字符替换字符串的前N个字符
char *strcat(char *dest, const char *src); 将一个字符串添加到另一个字符串的后面
char *strncat(char *, const char *, size_t); 将一个指定长度的字符串添加到另一个字符串的后面
char *strchr(const char *, int); 从前往后检索,返回某一个字符第一次在字符串中出现的指针
char *strrchr(const char *, int); 从后往前检索,返回某一个字符第一次在字符串中出现的指针
int strcmp(const char *, const char *); 比较两个字符串的大小
int strncmp(const char *, const char *, size_t); 比较两个字符串前n个字符的大小
int strcoll(const char *, const char *); 使用本地排序策略比较两个字符串的大小
char *strcpy(char *toHere, const char *fromHere); 字符串的拷贝
char *strncpy(char *toHere, const char *fromHere, size_t); 拷贝指定数目的字符
char *strerror(int); returns the string representation of an error number e.g. errno (not thread-safe)
size_t strlen(const char *); 获取字符串长度
size_t strspn(const char *s, const char *accept); 返回第一个参数出现在第二个参数中字符串的最大长度
size_t strcspn(const char *s, const char *reject); 返回第一个参数不出现在第二个参数中字符串的最大长度
char *strpbrk(const char *s, const char *accept); finds the first occurrence of any character in accept in s
char *strstr(const char *haystack, const char *needle); 返回某字符在字符串中出现位置的指针
char *strtok(char *, const char *); parses a string into a sequence of tokens; non-thread safe in the spec, non-reentrant
size_t strxfrm(char *dest, const char *src, size_t n); transforms src into a collating form, such that the numerical sort order of the transformed string is equivalent to the collating order of src.

strlen() 函数的作用是返回字符串的长度。

#include <stdio.h>
#include <string.h>

int main(void)
{
    size_t n;
    
    n = strlen("how are you!");
    printf("%d", n); // 显示12
    return 0;
}

strspn()函数的作用是返回第一个参数出现在第二个参数中字符串的最大长度。strcspn()函数的作用是返回第一个参数不出现在第二个参数中字符串的最大长度。

#include <stdio.h>
#include <string.h>

int main(void)
{
    size_t n, m;
    
    n = strspn("aowt", "how are you!");
    printf("%d", n); // 显示3
    m = strcspn("tdfna", "how are you!");
    printf("%d", m); // 显示4
    return 0;
}

strcmp()函数的作用是比较两个字符串的大小,只有三种结果,-1,0和1。strncmp()函数的作用和strcmp()函数类似,但是仅对前n个字符进行比较。strcoll()函数的作用是和strcmp()函数类似,但是会使用本地化的字符串排序策略。

#include <stdio.h>
#include <string.h>

int main(void)
{
    int n, m, i, j;
    
    n = strcmp("how about y", "how about z");
    printf("%d", n); // 显示-1
    m = strcmp("how about y", "how about x");
    printf("%d", m); // 显示1
    i = strncmp("how about y", "how about x", 6);
    printf("%d", i); // 显示0
    j = strcoll("how about y", "how about x");
    printf("%d", j); // 显示1
    return 0;
}

strcpy()函数的作用是实现字符串的拷贝。strncpy()函数的作用和strcpy()函数类似,但是只拷贝指定数目的字符。

#include <stdio.h>
#include <string.h>

int main(void)
{
    char n[40], m[10];
    
    strcpy(n, "how are you!");
    printf(n); // 显示how are you!
    
    strncpy(m, "how are you!", 10);
    printf(m); // 显示how are yo
    return 0;
}

strstr()函数的作用是返回某字符在字符串中出现位置的指针

#include <stdio.h>
#include <string.h>

int main(void)
{
    char *n;
    
    n = strstr("how are you!", "are");
    printf(n); // 显示are you!
    return 0;
}

strcat()函数的作用是将一个字符串添加到另一个字符串的后面。strncat()函数的作用和strcat()函数类似,但是可以控制添加字符串的长度。

#include <stdio.h>
#include <string.h>

int main(void)
{
    char n[30] = "how are ";
    char m[30] = "how are ";
    char i[30] = "you!";
    strcat(n, i);
    puts(n); // 显示how are you!
    
    strncat(m, i, 2);
    puts(m); // 显示how are yo
    return 0;
}

strchr()函数的作用是从前往后检索,返回某一个字符第一次在字符串中出现的指针。strrchr()函数的作用是从后往前检索,返回某一个字符第一次在字符串中出现的指针。

#include <stdio.h>
#include <string.h>

int main(void)
{
    char n[30] = "how are you!";
    char *i, *j;
    i = strchr(n, 'a');
    puts(i); // 显示are you!
    
    j = strrchr(n, 'o');
    puts(j); // 显示ou!
    return 0;
}

memchr()函数的作用是

#include <stdio.h>
#include <string.h>

int main(void)
{
    char n[30] = "how are you!";
    char *i;
    i = strchr(n, 'a');
    puts(i); // 显示are you!
    return 0;
}

memset()函数的作用是用指定的字符替换字符串的前N个字符。

#include <stdio.h>
#include <string.h>

int main(void)
{
    char n[30] = "how about you!";
    memset(n, '*', 3);
    printf("%s", n); // 显示*** about you!
    return 0;
}

memcmp()函数的作用是比较内存地址中的前N个字符。

#include <stdio.h>
#include <string.h>

int main(void)
{
    int i;

    i = strncmp("how about y", "how about x", 11);
    printf("%d", i); // 显示1
    return 0;
}

2008.6.20-30

6月 20th, 2008

关于CPU,寄存器,内存和多线程

传统的CPU在某一时间只能处理一个指令序列,通常我们把它称为一个线程。在线程处理的过程中CPU的处理单元需要不断调入指令与数据进行处理。随着 CPU技术的发展,CPU的主频与性能不断提高,需要调入指令和数据的速度不断提高。但不幸的是内存技术的发展并没有跟上CPU发展的速度,内存通常无法提供足够的指令和数据给CPU进行处理。

为了解决这个问题,业界通常采用多级缓存的方式。CPU处理单元中的寄存器是最快的,通常一个CPU中有一、两百个寄存器,它可以在一个时钟周期内提供指令和数据。其次是一级缓存,他的大小通常为几十KB,它需要几个时钟周期的访问时间。再下面是二级缓存,他的大小通常为几MB,它需要十几个时钟周期的访问时间。然后是内存,从内存中取得数据需要几十个个时钟周期。而最慢的是硬盘,通常需要几千甚至几万个时钟周期的访问时间。

当CPU需要处理下一条指令时,他通常按照寄存器、一级缓存、二级缓存、内存、硬盘这一顺序去查找。但如果在内存中仍然找不到需要的指令或数据时。系统会进行Context Switch,终止此线程在CPU上的运行,使其处于等待状态,而让其他的线程运行,当此线程需要的数据被调入内存后,此线程处于就绪状态,可以被调度到 CPU上运行。线程间的Context Switch需要几十个时钟周期。

由此可见当CPU需要从内存中取数据时,处理单元需要空转几十个时钟周期,有关统计显示当前CPU处理单元的平均利用率不足25%。为了提高CPU处理单元的利用率,设计者采用了线程级的并行技术,即在CPU的核心中执行一个以上的指令序列。对于操作系统来说,一个物理的处理器相当于两个逻辑的处理器,当前有三种不同的方式,实现多线程技术。

粗粒度的多线程,在任一时刻只有一个线程执行,当线程遇到一个长延迟事件时,如二级缓存不命中,则系统调度另一个线程执行,而不是让系统资源空转等待此线程。这一机制可以提高整个系统的利用率。这两个线程共享许多系统资源,如CPU的寄存器和缓存等,因此这两个线程的切换比Context Switch要快得多,只需要几个时钟周期。IBM在使用PowerPC RS64 IV处理器的pSeries 680和pSeries 660-6M1上使用过这种粗粒度的多线程技术。

另一种与粗粒度的多线程技术相对的是细粒度多线程技术,采用这种多线程的系统循环的执行两个线程的指令,这就需要在处理器的设计上增加许多冗余的部件。如果一个线程遇到个长延迟事件时,对应这一线程执行的时钟周期仍然没有被利用。

第三种多线程技术是同步多线程技术(SMT),与其他的多线程技术一样,同步多线程能够从多个线程中取出指令来运行,它能够同时执行不同线程的指令。通过同步多线程技术,系统能够动态调整系统环境,如有可能同时执行不同线程的指令。当一个线程遇到长延迟事件时,允许另一个线程使用所用的处理单元。

parameter 和 argument

parameter 中文多翻译为形参,在函数声明的时候定义的,比如:
int abc(int d,int e);//此时d和e 就是parameter

argument就是实参,是在调用这个函数时传递给函数的相匹配的参数。比如:
int h=abc(23,32);//23和32就是argument

REST

概述

REST是英文Representational State Transfer的缩写,中文翻译:表述性状态转移。

他是由Roy Thomas Fielding博士在他的论文 《Architectural Styles and the Design of Network-based Software Architectures》中提出的一个术语。

REST本身只是为分布式超媒体系统设计的一种架构风格,而不是标准。

基于Web的架构,实际上就是各种规范的集合,这些规范共同组成了Web架构。比如Http协议,比如客户端服务器模式,这些都是规范。每当我们在原有规范的基础上增加新的规范, 就会形成新的架构。而REST正是这样一种架构,他结合了一系列的规范,而形成了一种新的基于Web的架构风格。
传统的Web应用大都是B/S架构,它包括了如下一些规范:

1. 客户-服务器

这种规范的提出,改善了用户接口跨多个平台的可移植性,并且通过简化服务器组件,改善了系统的可伸缩性。最为关键的是通过分离用户接口和数据存储这两个关注点,使得不同用户终端享受相同数据成为了可能。

2. 无状态性

无状态性是在客户-服务器约束的基础上添加的又一层规范。他要求通信必须在本质上是无状态的,即从客户到服务器的每个request都必须包含理解该 request所必须的所有信息。这个规范改善了系统的可见性(无状态性使得客户端和服务器端不必保存对方的详细信息,服务器只需要处理当前 request,而不必了解所有的request历史),可靠性(无状态性减少了服务器从局部错误中恢复的任务量),可伸缩性(无状态性使得服务器端可以很容易的释放资源,因为服务器端不必在多个request中保存状态)。同时,这种规范的缺点也是显而易见得,由于不能将状态数据保存在服务器上的共享上下文中,因此增加了在一系列request中发送重复数据的开销,严重的降低了效率。

3.缓存

为了改善无状态性带来的网络的低效性,我们填加了缓存约束。缓存约束允许隐式或显式地标记一个response中的数据,这样就赋予了客户端缓存 response数据的功能,这样就可以为以后的request共用缓存的数据,部分或全部的消除一部分交互,增加了网络的效率。但是用于客户端缓存了信息,也就同时增加了客户端与服务器数据不一致的可能,从而降低了可靠性。

B/S架构的优点是其部署非常方便,但在用户体验方面却不是很理想。为了改善这种情况,我们引入了REST。

REST在原有的架构上增加了三个新规范:统一接口,分层系统和按需代码。

1.统一接口

REST 架构风格的核心特征就是强调组件之间有一个统一的接口,这表现在REST世界里,网络上所有的事物都被抽象为资源,而REST就是通过通用的链接器接口对资源进行操作。这样设计的好处是保证系统提供的服务都是解耦的,极大的简化了系统,从而改善了系统的交互性和可重用性。并且REST针对Web的常见情况做了优化,使得REST接口被设计为可以高效的转移大粒度的超媒体数据,这也就导致了REST接口对其它的架构并不是最优的。

2.分层系统

分层系统规则的加入提高了各种层次之间的独立性,为整个系统的复杂性设置了边界,通过封装遗留的服务,使新的服务器免受遗留客户端的影响,这也就提高了系统的可伸缩性。

3.按需代码

REST允许对客户端功能进行扩展。比如,通过下载并执行applet或脚本形式的代码,来扩展客户端功能。但这在改善系统可扩展性的同时,也降低了可见性。所以它只是REST的一个可选的约束。

REST的设计准则

REST架构是针对Web应用而设计的,其目的是为了降低开发的复杂性,提高系统的可伸缩性。REST提出了如下设计准则:

1. 网络上的所有事物都被抽象为资源(resource);
2. 每个资源对应一个唯一的资源标识符(resource identifier);
3.通过通用的连接器接口(generic connector interface)对资源进行操作;
4. 对资源的各种操作不会改变资源标识符;
5. 所有的操作都是无状态的(stateless)。

REST中的资源所指的不是数据,而是数据和表现形式的组合,比如“最新访问的10位会员”和“最活跃的10为会员”在数据上可能有重叠或者完全相同,而由于他们的表现形式不同,所以被归为不同的资源,这也就是为什么REST的全名是Representational State Transfer的原因。资源标识符就是URI(Uniform Resource Identifier),不管是图片,Word还是视频文件,甚至只是一种虚拟的服务,也不管你是xml格式,txt文件格式还是其它文件格式,全部通过 URI对资源进行唯一的标识。

REST是基于Http协议的,任何对资源的操作行为都是通过Http协议来实现。以往的Web开发大多数用的都是Http协议中的GET和 POST方法,对其他方法很少使用,这实际上是因为对Http协议认识片面的理解造成的。Http不仅仅是一个简单的运载数据的协议,而是一个具有丰富内涵的网络软件的协议。他不仅仅能对互联网资源进行唯一定位,而且还能告诉我们如何对该资源进行操作。Http把对一个资源的操作限制在4个方法以内: GET, POST,PUT和DELETE,这正是对资源CRUD操作的实现。由于资源和URI是一一对应的,执行这些操作的时候URI是没有变化的,这和以往的 Web开发有很大的区别。正由于这一点,极大的简化了Web开发,也使得URI可以被设计成更为直观的反映资源的结构,这种URI的设计被称作 RESTful的URI。这位开发人员引入了一种新的思维方式:通过URL来设计系统结构。当然了,这种设计方式对一些特定情况也是不适用的,也就是说不是所有的URI都可以RESTful的。

REST 之所以可以提高系统的可伸缩性,就是因为它要求所有的操作都是无状态的。由于没有了上下文(Context)的约束,做分布式和集群的时候就更为简单,也可以让系统更为有效的利用缓冲池(Pool)。并且由于服务器端不需要记录客户端的一系列访问,也减少了服务器端的性能。

使用REST架构

对于开发人员来说,关心的是如何使用REST架构,这里我们来简单谈谈这个问题。REST不仅仅是一种崭新的架构,它带来的更是一种全新的Web开发过程中的思维方式:通过URL来设计系统结构。在REST中,所有的URL都对应着资源,只要URL的设计是良好的,那么其呈现的系统结构也就是良好的。这点和 TDD (Test Driven Development)很相似,他是通过测试用例来设计系统的接口,每一个测试用例都表示一系列用户的需求。开发人员不需要一开始就编写功能,而只需要把需要实现的功能通过测试用例的形式表现出来即可。这个和REST中通过URL设计系统结构的方式类似,我们只需要根据需求设计出合理地URL,这些 URL不一定非要链接到指定的页面或者完成一些行为,只要它们能够直观的表现出系统的用户接口。根据这些URL,我们就可以方便的设计系统结构。从 REST架构的概念上来看,所有能够被抽象成资源的东西都可以被指定为一个URL,而开发人员所需要做的工作就是如何能把用户需求抽象为资源,以及如何抽象的精确。因为对资源抽象的越为精确,对REST的应用来说就越好。这个和传统MVC开发模式中基于Action的思想差别就非常大。设计良好的URL,不但对于开发人员来说可以更明确的认识系统结构,对使用者来说也方便记忆和识别资源,因为URL足够简单和有意义。按照以往的设计模式,很多URL后面都是一堆参数,对于使用者来说也是很不方便的。

既然REST这么好用,那么是不是所有的Web应用都能采取此种架构呢?答案是否定的。我们知道,直到现在为止,MVC(Model-View- Controller) 模式依然是Web开发最普遍的模式,绝大多数的公司和开发人员都采取此种架构来开发Web应用,并且其思维方式也停留于此。MVC模式由数据,视图和控制器构成,通过事件(Event)触发Controller来改变Model和View。加上Webwork,Struts等开源框架的加入,MVC开发模式已经相当成熟,其思想根本就是基于Action来驱动。从开发人员角度上来说,贸然接受一个新的架构会带来风险,其中的不确定因素太多。并且REST新的思维方式是把所有用户需求抽象为资源,这在实际开发中是比较难做到的,因为并不是所有的用户需求都能被抽象为资源,这样也就是说不是整个系统的结构都能通过REST的来表现。所以在开发中,我们需要根据以上2点来在REST和MVC中做出选择。我们认为比较好的办法是混用REST和MVC,因为这适合绝大多数的Web应用开发,开发人员只需要对比较容易能够抽象为资源的用户需求采取REST的开发模式,而对其它需求采取MVC开发即可。这里需要提到的就是ROR(Ruby on Rails)框架,这是一个基于Ruby语言的越来越流行的Web开发框架,它极大的提高了Web开发的速度。更为重要的是,ROR(从1.2版本起)框架是第一个引入REST做为核心思想的Web开发框架,它提供了对REST最好的支持,也是当今最成功的应用REST的Web开发框架。实际上,ROR的 REST实现就是REST和MVC混用,开发人员采用ROR框架,可以更快更好的构建Web应用。

对开发人员来说,REST不仅仅在Web开发上贡献了自己的力量,同时也让我们学到了如何把软件工程原则系统地应用于对一个真实软件的设计和评估上。

面向对象技术具有三个基本的特性

1.封装

在程序设计中,封装是指将一个数据和与这个数据有关的操作集合在一起,形成一个能动的实体——对象,用户不必知道对象行为的实现细节,只需根据对象提供的外部接口访问对象即可。因此,从用户的观点来看,这些对象的行为就像包含在一个“黑匣子”里,是隐蔽的、看不见的。

封装有两个基本前提:一是对象必须是完备的,即必须能够表示整个概念,描述整个问题的各个方面;二是私有性。大多数对象都需要对其内部的数据和过程限制处理权限。私有性不但可以保证对对象的正确操作,而且有利于查错,使一些对象的成员函数私有化,减少它们被处理的机会,于是在追踪时许多地方都可以不必去查。

封装不是面向对象语言所独有的特性,但这种在单一实体中把数据结构和行为捆绑在一起的能力,使封装比传统的把数据结构和行为分离的语言更加清晰、更强有力。

2.继承

继承表明类之间的关系。类不仅仅说明一组对象上的约束,还说明与其他类之间的关系。两个类型可以有共同的特性和行为,但是,一个类型可能包括比另一个类型更多的特性,也可以处理更多的消息。继承表示了基类和派生类之间的相似性。一个基类具有所有由它派生出来的类所共有的特性和行为,而派生类则通过继承重用了基类的特性和行为。

抽象基类提供了公共接口,当希望通过公共接口操作一组(派生)类时就创建抽象基类。

3.多态

多态的含义是相同的行为(在基类中定义)在不同的类中有着不同的实现(在子类中实现),或者更彻底的说,多态性就是以相同的指令唤起不同的函数。

当处理类型层次结构时,程序员常常希望不把对象看作是某一特殊类型的成员,而把它看作基本类型的成员,这样就可以编写不依耐于特殊类型的代码,在添加新的子类后也不影响原来的代码,这是扩展面向对象程序以处理新情况的最普通的方法——通过派生新的子类来扩展程序功能,这个能力极大地减少了软件维护的花费(所谓“软件危机”正是由软件的实际花费远远超出人们的想象而产生的)。

面向对象编程基本原则

单一职责原则(SRP):

– 一个类应该仅有一个引起它变化的原因。

开放封闭原则(OCP):

– 类模块应该是可扩展的,但是不可修改(对扩展开放,对更改封闭)

Liskov 替换原则(LSP):

– 子类必须能够替换它们的基类

依赖倒置原则(DIP):

– 高层模块不应该依赖于低层模块,二者都应该依赖于抽象。

– 抽象不应该依赖于实现细节,实现细节应该依赖于抽象。

接口隔离原则(ISP):

– 不应该强迫客户程序依赖于它们不用的方法。

《Don't Make Me Think》中的故事

在瑞士日内瓦湖边,有一个隧道,隧道很长,开车穿过隧道需要把车大灯打开。在隧道的出口,是一个观景台,从这里看去,日内瓦湖的美景一览无余。于是,很多游客纷纷在这里下车观赏美景,却忘记了关掉车灯。车灯就这样一直开着,以至于车子没有电了,无法启动,游客们开始怨声载道。有人开始向旅游部门投诉:“进隧道的时候提醒我们开车灯,出隧道的时候不提醒我们关车灯。偏偏在隧道口又是这么美的景色,害得车子没电了,发动不了。”

旅游部门于是考虑在隧道出口设一个提示牌。提示牌的内容如果写“请您关灯”,那么要是晚上,出了隧道也需要开灯,不能关灯,所以不合适。如果写成“白天,出隧道时请您关灯;晚上,请您开灯”,又太罗嗦,车上的还没来得及看清楚,车早开过去了。最后,有人提议写成“您的灯开着了吗?”这样使对方对车灯的状态进行思考,各种情况都包括了,而且言简意赅。

OOA OOD OOP

"工程師修了一條隧道,隧道的一端就是美麗的風景,很多人會開車通過隧道.雖然隧道內已經有燈了,但是設計者擔心隧道可能會停電,所以在隧道的入口立了牌子,提醒駕駛員進入隧道前開燈.可是由此却使得駕駛員由於看到美麗的風景而忘記關燈的情況的發生."

OOA是Object-Oriented Analysis(面向对象分析)

分析师拿到了政府,民众,组织,社团等的需求,这里泛指所有来自客户的需求了;了解需求,分析需求,分析技术实现等,得出一个结论:要在这里修条隧道;于是分析师,系统分析师,架构设计师出现了,他们干的工作就分析出来一个方案,即项目需求吧,他们的身份就是OOA了。

OOD是Object Oriented Design(面向对象设计)

分析师们分析结果出来后,形成了最早的需求模型;可能是一个草图,一张可行性分析XX报告;设计师们拿到这个模型进行细化,模块化,定义所有的细节,也就是详图,或是详细的需求分析规格书了,在这里,可能会有隧道的位置,长度,宽度,高度,容量,光线,材料,设备,电子眼,安全等,这里就是具体的需求文档了。设计师的设计工作完成了,他们就是OOD。

OOP是Object Oriented Programming (面象对象程序设计)

OOP就是施工队了,他们按照设计图的要求完成隧道工程,包括质量,容量,安全等测试,也就是完成项目的实际操作部分,在项目里就是coding的工作和testing的工作。到此为止,隧道就完成了,駕駛員也可以说成是testing的一员,他们进行体验,体验完了,没问题,oop的工作也就结束了,我们可以收工了。

Google让我们越变越傻? 专注与沉思能力被粉碎

  《大西洋月刊》刊文剖析互联网一代大脑退化历程,认为新阅读风格使人退回中世纪

  “戴夫,停下。停下好吗?停下,戴夫。你能停下吗,戴夫?”

  这个著名的场景出现在库布里克的电影《2001:太空漫游》的片尾,乃超级电脑HAL恳求宇航员戴夫·鲍曼手下留情,放他一条生路。由于电脑故障,戴夫被送入茫茫外空,前路未卜,目的地不明,只好“视死如不归”。最后,他对HAL下了手,平静而冷酷地切断了它的内存(记忆体)电路。

  “戴夫,我的思想要没了。”HAL绝望地说。“我感觉得到。我感觉得到。”

  网络粉碎专注与沉思的能力

  当尼古拉斯·卡尔想起HAL的哀号,不由得脸皮有些酥麻,手脚略感冰凉。“我也感觉得到。”他说。

  卡尔在2008年7~8月号的《大西洋月刊》撰文,以《Google是否让我们越变越傻》为题,痛苦地剖析自己和互联网一代的大脑退化历程。“过去几年来,我老有一种不祥之感,觉得有什么人,或什么东西,一直在我脑袋里捣鼓个不停,重绘我的‘脑电图’,重写我的‘脑内存’。”他写道。“我的思想倒没跑掉 ——到目前为止我还能这么说,但它正在改变。”

  他注意到,过去读一本书或一篇长文章时,总是不费什么劲儿,脑袋瓜子就专注地跟着其中的叙述或论点,转个没完。可如今这都不灵了。“现在,往往读过了两三页,我的注意力就漂走了。”

  卡尔找到了原因。过去这十多年来,他在网上花了好多时间,在互联网的信息汪洋中冲浪、搜寻。对作家而言,网络就像个天上掉下来的聚宝盆,过去要在书堆里花上好几天做的研究,现在几分钟就齐活。Google几下,动两下鼠标,一切就都有了。“对我来说,”卡尔写道,“对别人也是如此,网络正在变成一种万有媒介,一种管道,经由它,信息流过我的眼、耳,进入我的思想。”

  信息太丰富了,我们受用不尽,也不忘感恩戴德,却往往忽视了要付出的代价。“网络似乎粉碎了我专注与沉思的能力。现如今,我的脑袋就盼着以网络提供信息的方式来获取信息:飞快的微粒运动。”

  网络新阅读方式:海量浏览

  卡尔不是唯一一个遇到此种问题的人。长期在密歇根医学院任教的布鲁斯·弗里德曼,今年早些时候也在自己的blog上写到互联网如何改变了他的思维习惯。 “现在我已几乎完全丧失了阅读稍长些文章的能力,不管是在网上,还是在纸上。”他在电话里告诉卡尔,他的思维呈现出一种“碎读”特性,源自上网快速浏览多方短文的习惯。“我再也读不了《战争与和平》了。”弗里德曼承认,“我失去了这个本事。即便是一篇blog,哪怕超过了三四段,也难以下咽。我瞅一眼就跑。”

  伦敦大学学院以5年时间做了一个网络研读习惯的研究。学者们以两个学术网站为对象——它们均提供电子期刊、电子书及其他文字信息的在线阅读,分析它们的浏览记录,结果发现,读者总是忙于一篇又一篇地浏览,且极少回看已经访问过的文章。他们打开一篇文章或一本书,通常读上一两页,便“蹦”到另一个地方去了。报告说:“很明显,用户们不是在以传统方式进行在线阅读,相反,一种新‘阅读’方式的迹象已经出现:用户们在标题、内容页和摘要之间进行着一视同仁的‘海量浏览’,以求快速得到结果。这几乎可被视为:他们上网正是为了回避传统意义上的阅读。”

  打字机让尼采的写作风格发生变化

  互联网改变的不仅是我们的阅读方式,或许还有我们的思维方式,甚至我们的自我。塔夫茨大学的心理学家、《普鲁斯特与鱿鱼:阅读思维的科学与故事》一书作者玛雅妮·沃尔夫说:“我们并非只由阅读的内容定义,我们也被我们阅读的方式所定义。”她担心,将“效率”和“直接”置于一切之上的新阅读风格,或会减低我们进行深度阅读的能力。几百年前的印刷术,令阅读长且复杂的作品成为家常之事,如今的互联网技术莫非使它退回了又短又简单的中世纪?沃尔夫说,上网阅读时,我们充其量只是一台“信息解码器”,而我们专注地进行深度阅读时所形成的那种理解文本的能力、那种丰富的精神联想(企业库 论坛),在很大程度上都流失掉了。

  沃尔夫认为,阅读并非人类与生俱来的技巧,不像说话那样融于我们的基因。我们得训练自己的大脑,让它学会如何将我们所看到的字符译解成自己可以理解的语言。

  1882年,尼采买了台打字机。此时的他,视力下降得厉害,盯着纸看的时间长了,动不动头疼得要死,他担心会被迫停止写作。但打字机救了他。他终于熟能生巧,闭着眼睛也能打字——盲打。然而,新机器也使其作品的风格发生了微妙的变化。他的一个作曲家朋友为此写信给他,还说自己写曲子时,风格经常因纸和笔的特性不同而改变。

  “您说得对,”尼采复信道,“我们的写作工具渗入了我们思想的形成。”德国媒体学者弗里德里希·基特勒则认为,改用打字机后,尼采的文风“从争辩变成了格言,从思索变成了一语双关,从繁琐论证变成了电报式的风格”。

  卡尔引用神经学家的观点,证明成年人的大脑仍然颇具可塑性,而历史上机械钟表和地图的发明,同样说明了人类如何因此改变了对时间与空间的思维。互联网正是今日的钟表与地图。

  网络影响让传统媒体也零碎化

  当人们的思维方式适应了互联网媒体的大拼盘范式后,传统媒体也会做出改变。电视节目加入了滚动字幕和不断跳出的小广告,报刊则缩短其文章的长度,引入一小块一小块的摘要,在版面上堆砌各种易于浏览的零碎信息。今年3月,《纽约时报》便决定将其第2和第3版改为内容精粹。

  Google 首席执行官埃里克·施密特说,该公司致力于将“一切系统化”。Google还宣布,其使命是“将全世界的信息组织起来,使之随处可得,并且有用。”通过开发“完美的搜索引擎,”让它能够“准确领会你的意图,并精确地回馈给你所要的东西。”问题是,它会使我们越变越蠢吗?

  “我感觉得到。”卡尔最后说,库布里克黑色预言的实质在于:当我们依赖电脑作为理解世界的媒介时,它就会成为我们自己的思想。

  上网阅读时,我们充其量只是一台“信息解码器”。

  当我们依赖电脑作为理解世界的媒介时,它就会成为我们自己的思想

symfony1.0的Criteria工具

6月 20th, 2008

Criteria 是 symfony1.0 默认的 orm 库 prepel 自带的一个 SQL 元素对象,简单的理解就是这个类包含了SQL语句的所有元素,用来辅助生成 SQL 语句,以前用数组做过一个类似的东西,Criteria 用对象实现的更为彻底。

Criteria 位于 /lib/vendor/propel/util/Criteria.php

Symfony的手册里面有非常详细的,关于 Criteria 的使用介绍《Retrieving Records with Criteria》,可以参照文章中的内容对应这个类学习他的功能。

这里看看相对复杂的 Criteria 对象的处理过程:

查看 /lib/model/om/Base*Peer.php 文件,可以看到

doCount()
doSelect()
doSelectOne()
doSelectRS()

这四个方法直接使用了 Criteria 对象作为第一个参数,而

doDelete()
doInsert()
doUpdate()

这三个方法则通过 /lib/model/om/Base*.php 文件中的 buildCriteria() 方法间接的使用 Criteria 对象。

在 /lib/vendor/propel/unit/BasePeer.php 中:

doDelete()
doInsert()
doUpdate()
doSelect()

都各自将 Criteria 对象转换为SQL,其中doSelect()最为复杂,调用的 createSelectSql() 方法足有300行,到 createSelectSql() 处理完,对所有数据库都还是一视同仁的,接下来的操作,则是使用 Creole 这个数据库抽象层(也是 propel 的一个子项目) 对应不同的数据库进行针对不同数据库的操作,包括:

1、非法字符过滤
2、setLimit()
3、setOffset()

依次调用 /lib/vendor/creole/drivers/mysql/MySQLConnection.php 中的(其他数据库也是对应这样的操作)

prepareStatement() 方法处理非法字符过滤
setLimit() 方法设置查询限制
setOffset() 方法设置查询偏移量

到这里,才真正的生成了一条SQL语句,最后再调用 Creole 的 executeQuery() 方法完成对SQL的解析。