del 2008-06-21
背景
当本Blog从PJBlog的ASP改装成JSP的时候,网页HTML编辑器就是一大软肋,PJBlog支持两种HTML编辑器支持FCKeditor和UBB,前者功能强大,内容丰富,但出于对JavaScript和CSS的不熟悉,我最后只采用了简单的UBB,但即便是UBB,我也得用Java重写UBB转义部分的代码,我先是从网上下载了某人的源码,然后对其修改和添加以适合自己的具体需求。于是乎,大量的字符串查找,匹配和替换,其中还混杂着我后来添加的一些正则表达式,代码变得凌乱不堪,当添加新的转义时,常常故此失彼。这是我打算重写UBB转义代码的首要原因。
另外,我努力使Blog以技术文章为主,有很多地方会引用到代码,而原来的UBB已被我折腾得肯定不支持code了...
最后,看到JavaEye的页面对代码支持得不错,UBB编辑也够简单,对我也刚好够用,于是决定开搞了
准备
在JavaEye上draft了一篇测试文章,把所有UBB代码都用了一边,将该文章内容(里面含有原始的UBB代码)其copy出来,以txt文件保存到本地,不妨命名为crazycow.txt。然后发布这篇文章,并使用浏览器的“另存为”把该文章的页面下载到本地,不妨命名为crazycow,于是得到一个crazycow.htm文件和一个crazycow文件夹,文件夹中的内容就是该htm页面要用到的一些资源:JavaScript代码,CSS代码和图片。
对htm的内容稍做修改,将对css,JavaScript和图片的引用链接修改正确,然后将这htm文件和文件夹,放到自己本地的应用下面,开启Tomcat,测试一下这个页面,效果和JavaEye上的一模一样,于是我知道拥有这部分内容就可以实现我的需求了。
分析
从下载的html代码可以看出,原始的含有UBB代码的文章经过JavaEye的UBB转义所形成的html代码主要集中在标签<divclass="blog_content"&rt;之内,转义主要做了如下工作:
到了这里,我大概知道了JavaEye实现UBB代码转义的基本原理,对于简单的UBB标签,用服务器后台程序转义直接成html代码,对于的转义,则是先将其转义成新的标签,然后再结合JavaScript和CSS实现代码高亮的功能。
于是我们在到JavaScript文件中去寻找相关的代码,注意到html代码中有一段JavaScript,其中有一句:dp.SyntaxHighlighter.HighlightAll('code',true,true); 正是这句代码将原来在页面平淡无味的代码变得丰富多彩.我在shCoreCommon.js中找到了相关的定义.读下来,大概思路是:找到name属性值为code的,名为pre的所有tag;对这每一个pre标签,找到其code属性的值,如java,c等,再根据这个值用相应的高亮刷(shCoreCommon.js为每一个所支持的语言提供一个高亮刷),刷pre标签里面的代码,实际上是重新生成了能够被SynataxHighlighter.css作用的html代码,最后将原来pre标签隐藏,并插入新生成的html代码.借助于SynataxHighlighter.css,最终代码就能被高亮地显示在页面上了.
[b]实现自己的UBB转义
看到这里,前台部分应该结束了,下面就是实现自己的UBB转义了,既然要用到JavaEye的前台功能,那我只能按照她的要求来实现了.我有下面两个途径:
1,使用Java的正则表达式.
2,自己对文章内容从前到后逐字做解析.
用正则表达式的好处是,抽象功能强,也比较适于结构性强的文本解析,还有强大的替换功能,你只要能写出正确的正则表达式,剩下来的工作就很简单了,而且你的代码也会很简单.然而,我在最先尝试这条路径,竟遇到了死胡同:我能匹配大部分UBB标签,除了list和code,我的正则表达式如下:
"\\[(\\w+)(=\"([\\w:,/-\\\\.]+)\")?\\]([^\\]]*)\\[/\\1\\]"
其中group(1)对应于UBB标签,如code,group(3)对应标签的属性,如java,group(4)对应于标签内的内容,因为Java的正则表达式好像是最大匹配,如果你用"\\[.*\\]"去匹配"[aa]bb[cc]"只能find到一个匹配,它把"aa]bb[cc"都用来匹配.*,于是我用排除"]"的正则表达式来匹配标签内的内容,可这样以来就匹配不了list和code了,因为它们内部都有"]",就算你将list和code单独提出来,使用多次匹配,仍只能解决list的问题,因为list有"
"特征,但这个方法不能解决code,因为code里面的内容没有特征,而且仍然会有"]",如果你的文章中存在两段code,就一点办法都没有了.再一个,如果进行多次匹配,遇到了大文章,性能上也是不划算的.(如果java的正则表达式能给出"不出现某字符串"的正则匹配,那我这个问题也能解决,不过我没有试出来,也没有找到)于是我只好采用第二种方法,幸运的是,解析没有我想得那么复杂,很简单的逻辑也就完成了,部分代码如下.
收尾
差不多可以在我的网站上使用支持code的UBB了,最后再部署之前,我还做了一些裁减工作,将和自己需求无关的内容全部去掉,可以最大程度上减少外来代码和本地代码的冲突。于是在一遍遍Ctrl-C,Ctrl-V,F5和alert之后,我只用到了shCoreCommon.js和SyntaxHighlighter.css,其实shCoreCommon.js中还用到了定义在application.js中的部分代码,我只是觉得这部分代码很小而且很独立,就直接copy过来,放到了shCoreCommon.js里面。
结论