第7节里提到过的问题,实际上在《把时间当作朋友》一书中出现过,作为反驳“成功学谬误”的例子:
除了“以偏概全”、“单向成立”之外,“成功学”书籍里甚至不乏赤裸裸的、厚颜无耻逻辑混乱。最令我印象深刻的赤裸裸地逻辑混乱的“成功学”例子是关于“态度改变一切”的一个例子。我知道,也相信“有些时候,仅仅态度上的改变就真的可以带来不同的结果”。然而,我认为用以下的逻辑让我接受,或者让任何人接受,都不仅是不可能的,甚至是不道德的。
如果将字母 A 到 Z 分别编上 1 到 26 的分数,(A=1,B=2…,Z=26) ,那么:
- 你的知识(KNOWLEDGE)得到 96 分(11+14+15+23+12+5+4+7+5=96)
- 你的努力(HARDWORK)也只得到 98 分(8+1+18+4+23+15+18+11=98)
- 你的态度(ATTITUDE)才是左右你生命的全部,因为1+20+20+9+20+21+4+5=100
拜托,有点基础逻辑好不好呢?事实上,用这种方法计算,结果等于100的单词多的去了:
alienation (疏远)
apoplectic (中风患者)
boycott (联合抵制)
cacophony (杂音、刺耳的音调)
chimpanzee (黑猩猩)
connivance (纵容)
coyness (羞怯)
flurry (慌张)
frisson (颤抖)
impotence (阳痿)
inflation (通货膨胀)
pussy (小猫<俚>女阴/阴户)
socialism (社会主义)
status (身份、地位)
stress (压力)
surcharge (超载, 追加罚款, 额外费)
syndicate (财团)
tuppence (微不足道的东西)
turkey (火鸡,无用的东西)
Wednesday (星期三)
wholesale (批发)以上罗列的只是我在BNC英文词汇表中找到的一千多个中的一小部分名词而已。对了,形容词useless如果按照这种算法,结果也等于100。补记:刚刚写完,顺手在GOOGLE上搜索了一下 “KNOWLEDGE 11+14+15+23+12+5+4+7+5=96″。得到的结果特别值得回味:前150项几乎都来自中文网站。搜索结果的第16页才开始陆续有一些英文网站提到这个莫名其妙的算法,在GOOGLE搜索结果的第151项 看到这么一篇:指出 bullshit = 103,于是接着说,“So, it stands to reason that hard work and knowledge will get you close, attitude will get you there, but bullshit will put you over the top.” 还有更逗的,作者又接着指出另外一个词:asskissing=127 !
当时我就想,要是有很多莫名其妙的词按这种算法加起来也等于100呢?我猜肯定有的!只不过,用手工计算是(几乎)不可能的事情。还好,我有工具[1] 和技能,所以,就可以去验证,而后“精彩而又直接地”驳斥这种荒谬的说法。
有些时候我们非常依赖工具和技能。在心存狐疑之时,拥有工具掌握技能的人,可以去验证;而没有工具没有技能的人,只能“心有余力不足”。事实上,大多数“力不足”的人“心并无余”,他们甚至不会“心存狐疑”,而是直接“被震惊”、“被惊喜”,“被打动”……直接被这种说法带到坑里去了……
问题是:“有哪些词按这种算法也等于100?”──而解决方案倒也简单:
- 找一个词表(如有必要,就把它转换为文本文件,便于程序阅读)
- 逐一计算
- 把那些按这种算法计算等于100的词挑出来
刚开始的时候,其实没必要一定要先去找个词表,我只新建了名称为一个“wordlist.txt”的文件,其中只有以下几行内容:
Hardwork
Attitude
Knowledge
Success
Anything
而后我们就可以写这样的代码处理这个文本文件中的每一行:
$file = FileOpen("wordlist.txt", 0) While 1 $line = FileReadLine($file) If @error = -1 Then ExitLoop ; test if sum of character values in this word equals to 100, if so, print it to the output... WEnd FileClose($file)
注意,在AutoIt代码中,分号“;”后面的内容是“注释”,是给代码阅读者看的,AutoIt在执行代码的时候,忽略一切“;”和它后面的内容。注释的写法有若干种,请参阅帮助文档。
现在的问题是,如何才能计算出一个单词按这种算法等于多少呢?我到AutoIt的帮助文件里翻了翻与字符串(String)相关的函数,看看有没有能够用得上的……当然有,我找到了个StringSplit()。它会把一个字符串按照指定的“分隔符”拆分成若干段,而后把这些拆分后的片段按顺序保存在一个数组之中返回……如果分隔符是空字符(即,“”),那么它就把一个字符串拆分成一个字母一个片段……就是它了!
大致看了一下帮助文档,而后写了个代码片段测试这个函数:
#Include _ArrayDisplay(StringSplit("Success", ""))
结果竟然出错了……仔细看了看出错提示,才发现_ArrayDisplay()这个函数第一个参数标明了是ByRef的,即,只接受变量作为参数,不接受表达式或函数调用。所以,改了改测试代码:
#Include $a = StringSplit("Success", "") _ArrayDisplay($a)
运行结果如下:

看懂了,原来StringSplit()返回的是一个这样的数组:$a[0]之中保存的是“分割后片段的个数”(即,Success这个字符串总计7个字母),而后的元素则为每一个字母……
现在的问题是,如何让a=1,b=2… c=26呢?
在AutoIt帮助文件的Variables and Conversion章节中,找到一个函数Asc()。这个函数返回一个字符对应的ASCII代码。例如:
Asc(“0″) == 48, Asc(“9″) == 57, Asc(“A”) == 65, Asc(“Z”) == 90, Asc(“a”) == 97, Asc(“z”) == 122
所以,Asc(“a”) == 97 、 Asc(“b”) == 98 … 于是,只要用这个函数的返回值再减去96就可以得到1、2、…26这些数值了。不过,还有个问题,大小写字母的值不一样,Asc(“A”) == 65,而Asc(“a”) == 97……再去看看跟String相关的函数,找到一个StringLower()──我们可以先用它把一个词中的字符全部转换为小写,而后再进行计算……
现在我们可以写出(或起码能够完全理解)以下的代码了:
$file = FileOpen("wordlist.txt", 0) While 1 $line = FileReadLine($file) If @error = -1 Then ExitLoop ; test if sum of character values in this word equals to 100, if so, print it to the output... $wordLowerCase = StringLower($line) $Characters = StringSplit($wordLowerCase, "") $sum = 0 For $i = 1 To $characters[0] $sum = $sum + Asc($characters[$i]) - 96 Next MsgBox(0, $line, $sum) WEnd

仔细看看,就会发现“计算总和”的过程是可以被独立出来的,那还不如把它写成一个函数,将来可以随意调用呢:
$file = FileOpen("wordlist.txt", 0) While 1 $line = FileReadLine($file) If @error = -1 Then ExitLoop ; test if sum of character values in this word equals to 100, if so, print it to the output... $sum = AddUpCharactersInWordAsNumber($line) MsgBox(0, $line, $sum) WEnd Func AddUpCharactersInWordAsNumber($word) $wordLowerCase = StringLower($word) $Characters = StringSplit($wordLowerCase, "") $count = 0 For $i = 1 To $Characters[0] $count = $count + Asc($Characters[$i]) - 96 Next Return $count EndFunc
如此这般之后,我们可以去找一个很全的英文词汇表去测试了。我到网上Google了一下“BNC Frequency Word List”,很快在kilgarriff.co.uk这个网站上找到一个词汇表,“lemma.al”。网站上有这个词表的格式说明:
The format for the list is:
sort-order, frequency, word, word-classand a sample from the top of the alphabetically-ordered list is:
5 2186369 a det 2107 4249 abandon v 5204 1110 abbey n 966 10468 ability n 321 30454 able a
这个比较好办,就用我们刚刚用过的StringSplit()函数,用一个空格(” “)作为分隔符,就能把每一行中的“word”提取出来,然后在调用我们刚写过的AddUpCharactersInWordAsNumber()函数就可以算出数值……
然后,程序就变成了这个样子:
InetGet("http://www.kilgarriff.co.uk/BNClists/lemma.al", "lemma.al", 0) $file = FileOpen("lemma.al", 0) While 1 $line = FileReadLine($file) If @error = -1 Then ExitLoop $lineElements = StringSplit($line, " ") If AddUpCharactersInWordAsNumber($lineElements[3]) == 100 Then ConsoleWrite($lineElements[3] & @CRLF) EndIf WEnd FileClose($file) MsgBox(0, "", "Finished!") Func AddUpCharactersInWordAsNumber($word) $wordLowerCase = StringLower($word) $Characters = StringSplit($wordLowerCase, "") $count = 0 For $i = 1 To $Characters[0] $count = $count + Asc($Characters[$i]) - 96 Next Return $count EndFunc
如果你想把结果都写到一个文本文件之中,可以把第9行的
ConsoleWrite($lineElements[3] & @CRLF)
改成
FileWriteLine("result.txt", $lineElements[3])
而FileWriteLine()这个函数的用法,当然要参见帮助文档。
作业:
- 把程序里的StringLower()函数换成StringUpper(),并修改其它相应的部分,使其得出正常结果。
- 这里有个更长的词表:http://www.kilgarriff.co.uk/BNClists/all.al.gz,下载后解压缩,看看这个词表中有哪些词按这种算法等于100?
- 这里还有一个词表:http://www.bckelk.ukfsn.org/words/wlist.zip,下载后解压缩,看看这个词表中有哪些词按这种算法等于100?
- 回顾一下之前的所有文章,确保每一行代码都读得懂……
Footnotes:
- 当时我用的是Python,现在是在讲解AutoIt,所以当然得用AutoIt重写一遍。 [↩]



{ 19 comments… read them below or add one }
BEGIN {
for (i=0;i<255;++i) a[sprintf("%c",i)]=i
}
{
$3 = tolower($3)
c = 0
for (i = 1; i <= length($3) ; ++i) c+=a[substr($3,i,1)] – a["a"] + 1
if (c == 100) print $3
}
Awk代码,见效了
TAT,应该是见笑了..输入法
这段代码让我想起了貌似是和菜头说的笑话,“这段代码1年前只有我和上帝能看懂,现在只有上帝能看懂。”
笑来的变量名起得通俗易懂。变量名不怕起长了,就怕乱起看起来特痛苦。
嘛,我只写过OI的程序..so,悲剧
oi是什么?话说$3这种命名方式让我想起汇编里的地址“立即数”。最常见的就是入栈 subl $4 %esp
不过我是学越南语的文科生,不懂的……
OI是指计算机奥林匹克竞赛,经常是大约100行左右的程序,因此没有什么变量命名的限制。至于$3这个变量名,是指文件按行读入,以空格分界的第三个域。awk中自动做Split 详细的见http://www.linux.gov.cn/shell/awk.htm
我说我猜了一个早上都看不懂那个 =100是代表什么类型的单词呢.原来有典故。
不过一次性读取效率应该更高些,I/O的操作是挺贵的。比如说用python的时候喜欢用readerlines代替readerline逐次读取,然后再遍历readerlines集合。输出的时候也是如此,喜欢组成个hashtable然后一次性输出。
看了下帮助好像autoit没有类似的函数库?
话说回来,脚本开发真的能提高很多开发效率。
UDF里有个_FileReadToArray()
另,我认识个高手,叫韩磊……韩总大学的时候好像也是文科生学越南语的……
恩,几年前在某篇孟岩和韩磊谈面向对象的文章就已知道有此高手。
我也foxpro入门的,毕业后干了一年多越南语翻译。后来辞职在家边学英语边学编程。开始学了些c#皮毛,接着很认真的研究了javascript一段时间,近来倒着回去夯实基础,由C语言作为媒介,离散数学,数据结构,x0x86汇编。现在再看其他语言已经有了不同理解,csapp真的是一本很好的教材。
外语和编程有很多的共通点。
外语是文科,大学期间的外语专业应该不上数学课了吧,编程可是理工科的东西,你怎么应付的过来呢?
我也是文科专业毕业的,可是对编程有兴趣,发现有人走过这条路,不禁发问,但愿能从你那里得到稍许经验。
笑来老师是怎么查字典的?我怀疑我会成为您说的一辈子不会查字典的人。我一般读完文章,记下不认识的,再一个个查,带入文中匹配词意,然后在小本子记下词义,有经典例句的话再记下,没事讼读。我还把词分成三类,第一类是考试词汇,第二类是我觉得词义很反常的词汇,第三类是平时少见词汇。
你这样已经是很仔细的了,加油!
偶像,绝对的偶像!笑来!
我一般都用python的,不过看了老师这个,感觉AutoIt也很强大的啊。
If AddUpCharactersInWordAsNumber($lineElements[3]) == 100
这个地方为什么传过去的参数是$lineElements[3]),而不是$lineElements[1]呢??
看的时候也疑惑了一下,仔细看看,恍然。原来李老师程序中使用 Stringspilt时候 分隔参照是“ ”(空格) 即使用空格分隔网上得到的“单词词频表”。所以第三个分隔出来的元素就是单词。
oxjn drvaz lobstertube awjexu u vx c egi
jcqu axbvj [URL=http://www.zackspornlinks.com – porno[/URL – nysjes p pr b wei