工作中有一个中文字库表,是前辈从其他地方导入的。最近使用的时候发现有些词,比如“清白”,明明只有两个字,却只能用LIKE ‘%清白%’查出,直接=’清白’找不到。
第一反应,前后可能有空格。于是在PHPMyadmin中用MySQL的trim函数过滤了一下
update 字库 set Vocabulary = trim(Vocabulary)
但返回的affected rows数居然是0
可以肯定不知道是哪个UTF8不可见字符混了进去,直接看又看不见,想个办法让它显型。于是用到了MySQL的hex函数,把字符串的hex输出来对比一下:
select hex('清白'), hex(Vocabulary), Vocabulary from 字库 where Vocabulary like '%清白%'
这下一眼就看出正常字符串前多了个hex为“EFBBBF”的字符,将这个十六进制数扔到windows自带的计算器中换成十进制为15711167,真凶确定,删之:
update 字库 set Vocabulary = REPLACE(Vocabulary, char(15711167),'')
affected rows居然有3000多,怪不得感觉老有些常用词检索不出来呢……
保险起见,再用了一次trim
update 字库 set Vocabulary = trim(Vocabulary)
又冒出3个affected rows。
工作继续。
昨天被老师叫去给一个系统擦屁股,看到了一段实在是让我很无语的程序。不批一下难解我心头之不爽。
其实就是一个非常简单的功能:从数据库中读出一段时间内的流水,起始时间:(ayear, amonth, aday),结束时间:(byear, bmonth, bday)——变量的命名已经反映了这段程序的质量。
因为要从两张表里读数据,此仁兄居然写出了如此“高技术含量”的代码,大体如下:
for(int i=ayear;i< =byear;i++)
{
if(i-ayear>0)
{
amonth=1;
}
for(int j=amonth;j< =12;j++)
{
if((i-byear==0)&&j>bmonth)
break;
for(day=1;day< =31;day++)
{
sql="select * from lxd where jzrq ='"+String.valueOf(i)+"-"+String.valueOf(j)+"-"+String.valueOf(day)+"' and qymc='"+qymc+"' and qyzh='"+qyzh+"' and xhflag is null";
// 略去中间输出用代码
sql="select * from dwls where sj = '"+String.valueOf(i)+"-"+String.valueOf(j)+"-"+String.valueOf(day)+"' and dwmc='"+qymc+"' and qyzh='"+qyzh+"' and del is null "+order;
// 略去中间输出用代码
}
}
}
真不知此仁兄的数据库原理一课是怎么学的,为了把两张表的数据凑在一起居然写出了这么一陀代码。试问有哪本讲SQL的书中会不教联合查询。上面这陀东西不就是实现了这么点功能吗?
select * from lxd inner join dwls on lxd.jzrq=dwls.sj where lxd.jzrq between A and B
一个是查N天的数据生成2*N条SQL语句,另一个则不管查多少天一条搞定。
早就听说过一个说法,一个好的程序员和一个差的程序员写出来的代码效率会有上千倍的差距。此话果然不假。
今天很高兴成功写出了生平第一个汇编程序,程序很简单:从键盘读入一个数字,判断正负,正数输出1,负数输出-1,0时输出0。
因为汇编不是高级语言,所有的分枝都得靠跳转指令。于是老老实实地用流程图画了一下,别看就这么点功能,但输入的数字得一个一个地接收、判断(想起有穷状 态自动机来了,不知道这能不能算它的一种实现)。输出的时候也要根据正负、是否为0判断。最终这么一个小程序居然用了6处判断跳转!用C写2个if就可以 搞定的东东嘛……呵呵。
按照《代码大全(Code Complete)》上建议的方法,先把程序思路用注释全部写到源文件中去,然后一条条展开成代码,最终经过调试得到了以下可以成功运行的代码:
CODE SEGMENT
ASSUME CS:CODE
START: ;init
XOR AX ,AX
MOV BX ,0030H ;bh-negative flag, bl non-zero flag
XOR CX ,CX ;input flag
INPUT: ;input a charactor
MOV AH,01
INT 21H
CMP AL,1BH
JE RETURN ;press ESC to exit
CMP AL,0DH
JE OUTPUT ;if it's x0d, jump to OUTPUT
TEST CL,01H
JNE COMMON ;if it's not the first charactor, jump to COMMON
MOV CL,01H ;set input flag
CMP AL,'-'
JNZ COMMON ;if it's not '-', jump to COMMON
MOV BH,01H ;set negative flag
JMP INPUT ;jump to INPUT
COMMON:
CMP AL,'0'
JE INPUT ;if it's '0', jump to INPUT
MOV BL,31H ;set non-zero flag
JMP INPUT ;jump to INPUT
OUTPUT:
MOV AH,02H
MOV DL,0AH
INT 21H ;start a new line
CMP BL,'0'
JE NZ ;if it's 0, '-' is of no use
CMP BH,01H
JNE NZ ;if negative flag is false, jump to NZ
MOV DL,'-'
INT 21H ;print '-'
NZ: MOV DL,BL
INT 21H ;print the non-zero flag
MOV DL,0AH
INT 21H
MOV DL,0DH
INT 21H ;move cursor to a new line
JMP START ;get the next number
RETURN: RET
CODE ENDS
END START
PS:期间犯了两个错误,记录一下
1.忘记了 ASSUME CS:CODE 这一句,没了代码段,造成了所有的跳转语句都报:“ Near jump or call to different CS”错误。没指定自己的代码段在哪里,一跳可不是to different CS嘛!
2.代码最后没有加RET,一接收完输入就报莫名其妙的错误。汇编毕竟是汇编,最后的CODE ENDS和END START只是给编译器看的。程序执行完毕,返回操作系统的指令也得写明。
搞定之后小研究了一个EXE文件的结构,找到一篇不错的文章: com和exe文件结构
一学期的课程结束了,这周我们开始了本学期的第三个实验性课程——计算机组成原理实验。
实验课这种东西只要认真去做,确实能学到相当多的东西。EDA让我理解了电路的设计、系统软件分析与设计让我大概看明白了一个操作系统的内核是怎么写的,这一次的软件分析与设计则真的让我明白了计算机到底是怎么工作的。
自打接触计算机那时起,接受的教育都是:计算机是由程序控制执行的。程序是用编程语言写出来的。编程语言分为高级语言、汇编语言、机器语言。机器语言是2进制写的,在计算机底层直接控制计算机的执行——得出的结论是计算机完全是由机器语言控制运行的。
但是机器语言为什么能控制计算机运行呢?在本周以前,这对我就是一个黑盒问题。经过这两天的实验,这个黑盒被打开了。原来盒子里还有一个更底层的东西在控制着计算机,那就是微控制器中的微指令(计组课上老师讲过,但直到现在才搞明白-_-b)。计算机也无非就是一个大的EDA电路。运算器、内存、寄存器、输入设备、输出设备等无非都是连在系统总线上的一个个模块,每个模块都有使能端、总线开关等开关控制着它们的工作。
真正控制计算机工作是微控制器中的微代码,计算机的执行最根本上执行的是微代码,由微代码控制各个门的开关,决定数据从哪个模板流到哪个模块,各个模块应该做什么工作。而机器语言不过是微代码执行时查看的参数,微代码读取内存中的机器语言,根据机器语言决定下一步该执行什么,执行完毕后再读取下一条机器语言。
之所以一直说机器语言是控制计算机的执行,是因为在绝大多数计算机中,微代码是固定不变且不可改写的。一旦CPU的设计确定了,这台计算机的所有微代码就完全确定了(微代码存储在CPU的控制器中,固化在CPU的内部)。我们就只能在机器语言的层面上控制计算机了。
不过高校的实验就是高校的实验,我们的实验室中给的实验箱是一台自己连接各个模块,自己编写微代码的计算机。
实验指导书上给了一套可以实现加减法和基本逻辑运算的机器码及对应的微代码实验。不过我和我的搭挡晓亮决定做一个直接支持乘法指令的计算机。从今天下午开始到晚上十点多终于把所有的微代码设计出来了(直接写2进制控制各个模块的使能端确实不是件容易的事……)。明天去调试,期待能够成功。:)
最近Gmail升级频繁,又增加了很多非常cool的功能。今天用Firefox登录居然发现那帮geek们把AIM的聊天功能也加入到在线版的Gtalk中了。再加上前些天的群聊、表情图片,Gmail中单单一个聊天组件都快成miranda这样的专业IM软件了。
再看看整个Gmail,邮件内容预读取、更人性化的操作提示,对附件中各种文档在线查看、编辑的支持……基于Ajax的Gmail在很多方面甚至超过了我用的DreamMail的功能。不得不承认,Google把Ajax玩到了一种极致。
但不得不说的是,在使用完Gmail关闭我的Firefox的时,我已经遇到了多次Firefox崩溃的现象。这使我不怀疑难道Ajax的极限到了?
Ajax的核心JavaScript毕竟只是一门基于浏览器的解释型语言,执行效率上本来就相当不怎么样。而浏览器经过这十几年的发展也已经变成了一个超级复杂的软件系统,本身就有很多bug。在bug多上跑效率低……
不过看来众多软件厂商早已注意到这个问题Flash、SliverLight、JavaFX都在争抢着下一代RIA开发者的眼球。
解决问题总是好的,只是希望新的方案能解决浏览器之间的兼容性问题,不要让我们再头痛于JavaScript那样的浏览器hack之中。
robots.txt基本介绍
robots.txt是一个纯文本文件,在这个文件中网站管理者可以声明该网站中不想被robots访问的部分,或者指定搜索引擎只收录指定的内容。
当一个搜索机器人(有的叫搜索蜘蛛)访问一个站点时,它会首先检查该站点根目录下是否存在robots.txt,如果存在,搜索机器人就会按照该文件中的内容来确定访问的范围;如果该文件不存在,那么搜索机器人就沿着链接抓取。
另外,robots.txt必须放置在一个站点的根目录下,而且文件名必须全部小写。
完整原文:
http://homepage.yesky.com/304/7669304.shtml
- 看不见的之流量流量统计
- 看不见的之“希望泉录入系统”(本篇)
- 看的见的之读者评论系统
- 看的见的之侧边浮动导航
之前希望泉一直是编辑部将稿件以Word文件的形式编辑好,提交给技术部,技术部统一用DreamWeaver将其转换为网页格式。但由于Word文档和网页之间的差异,转换过程中总会出现些小问题,尤其是段首缩进和一些特殊字符。这样技术部后期制作相当大一部分时间都是用在修正这些细节错误上了。
于是我在WordPress(一款著名的blog系统)基础上制作了一个“希望泉录入系统”。借助于WordPress本身很强大的后台编辑功能,在系统后台可直接完成文章的编辑功能,而前台可直接获取文章的html代码。再加上WordPress本身自带的文章评论功能,文章录入时有什么问题还可以很方便地进行反馈。
这套系统相对于原始版本的WordPress主要修改了两点
1.在数据库及文章结构上增加了一个“文章编辑”的属性。以适应《希望泉》文章的实际需要。
2.修改前台模板,使其能显示文章编辑。并且增加了一些“复制”按钮,可以直接将对应的文字复制到剪切版中。以节约后期编辑的时间。
另外不得不提的是,由于WordPress是一套基于UTF-8编码的系统,输出的文本信息也都是UTF-8编码的。所以在使用这套系统后,《希望泉》的网页编码也被迫从gb2312转换到UTF-8。这对“读者评论系统”造成了一定的影响,在下一篇文章中我会详细说一下这件事的。
对于这个“希望泉编辑系统”我为希望泉的编辑写了一个使用说明:
希望泉录入系统使用说明
发布在希望泉Google Group的Google Page上了。
- 看不见的之流量流量统计(本篇)
- 看不见的之“希望泉录入系统”
- 看的见的之读者评论系统
- 看的见的之侧边浮动导航
学着Google的吴军,写个系列文章,分享一下自己的积累。我这里写个What’s behind Hope Spring,将自己在做《希望泉杂志》技术一年多来积累的东西整理一下。也希望对技术部其他同学有所帮助。
这一篇主要写的是《希望泉》页面中用到的流量统计代码。
在06年8月之后的《希望泉》页面代码里你总能找到类似以下的一段:
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script>
<script type="text/javascript">
_uacct = "UA-1351459-1";
urchinTracker();
</script>
这段代码使用的是Google Analytics的统计服务。只要申请一个Google Analytics的帐户,在页面上放置这样一段代码,就可以实现相当完善的流量统计服务。每天的访问量多少、读者都是来自哪个地区的、他们都看了哪些页面、读者是从哪个网站找到《希望泉》的……在Google提供的控制台上,这一切都一目了然。
另外,如果你对比一下各期《希望泉》这段代码出现的位置,就会发现最近几期《希望泉》中这段代码是放在页面最下端的,而以前很长时间这段代码是被放在代码头部head标签之中的。这主要是为了改善读者体验:
对外部javascript的引用如果出现在head之中,浏览器(尤其是IE)会试图在渲染页面之前加载这个外部文件,而Google Analytics的服务器在国外,加载速度比较慢,于是降低页面的显示速度;而把它放在接近</body> 的地方,页面在加载这个外部文件之前就已经渲染地差不多了,即使没有执行这段代码,他们也已经可以阅读其中的文字了。
今天终于把《代码大全》读完了。读这本书的感觉就一个字——爽!
具体对这本书的赞美之辞我就不重复了:http://www.cc2e.com.cn书的中文网站上有很多的。
作者强调自己这本书是在讲软件构建的技术。但就我的理解,这本书从头到尾的主题就是一个:为人编程!
正如作者所言,人的智力是有限的,而软件开发是一个庞大的智力产品开发过程。人的大脑不足以一次完全驾驭这一过程。于是为了完成这一复杂的开发,我们必须想办法将这个大的问题拆分、简化到人类大脑可以完全理解并且能用计算机正确实现它的地步。而且为了确保软件的正确性,在编程时我们要尽力做到要让人易于理解。以方便调试和维护。
为了达到这个目标,我们发明了子程序,提出了对象对象的概念,在编码时要遵循一定的格式,让代码尽可能地易于人的理解。于是乎便到了为人编程这个中心。
当然,为人编程也是有些代价的,为了让程序更便于人的理解,很多时候我们牺牲了一些代码的运行效率。在尽可能提高程序的正确性时,我们消耗掉了越来越多的硬件成本,这便产生了安迪-比尔定理 (Andy and Bill’s Law)。但不管怎样,我们最需要的还是软件的正确性,而且借助于现在运行效率低一些的高级语言,我们可以在更短的时间内开发出更正确的软件来,这难道不是一种效率的提升吗?
为人编程,实为王道!
PS:将Code Complete翻译成代码大全可能是这本书唯一的败笔。害得我每次对没听说过这本书的人都得解释半天这是本到底讲什么的书…
用了一个多月的工厂模式,但一直不过是在用Java中它来做数据库链接的生成,一个“ConnectionFactory.getConnection();”就可以搞定一个Connection,用到链接的时候就不用写那一大堆加载数据库驱动程序、写数据库链接字符串等的操作了。修改数据库链接时也会容易得多。原以为工厂模式不过就这些作用了。
最近从图书馆借了本《WebWork in Action》,恶补WebWork的基础知识(以前就靠从网上找来的几个Doc文件指导,都已经用了半个多月了……),确实理清了WebWork的工作机理。同时,也更了解的一些设计模式的作用。
实际上工厂类的最大作用是实现了类和其所用资源的解耦。这样类中就可以用接口类型的变量来接收工厂生成的对象,而不是自己去实列化一个硬编码、完全确定类型的对象。这样类所接收的资源类型就是可变化的了。最明显的应用就是在代码的测试过程中,你可以让工厂返回一个模拟对象,而不是真实对象来实现方便的测试。
总之一句话:工厂模式给了我们为类提供所需资源的主动权。我们可以根据需要设置工厂,让其返回适当类型的资源,而不需要改动资源使用者的代码。