CSK.Blog--个人原创Weblog

比较"优美"的进行html代码的截断

最近想到该更新下自己网站了,好吧,就从那个我已经看不惯很久的msn space同步转发器开刀...

如果你是先通过space看到这篇文章的话,应该就能看到效果了。撇去显示效果不说,这里提一个有趣的问题:

如何比较优雅的截取一段html代码?

换句话说,假设有下面这段html代码:

<p>this is a truncated html source<a href=\"some _fcksavedurl="\"some" URL\">some hyperlink</a>.<BR>

more text</p><p>one more</p>

出于某种需要,希望只显示(保留)这段代码的前n个字节。这样的需求其实不少见,最明显的就是在msn space文章同步的时候,我只希望对文章的大致内容转发过去,目前的做法就是截取文章的前1000字节。

如果仅仅是对一段普通文本进行这样的处理,那实在简单不过。直接截取即可。但是html却不同。

例如,对于上面的文字,如果截取的部分是:

<p>this is a truncated html source〈a href=\"some

今后将这段代码用于其它页面将出现不可能预见的问题。

考虑下面的代码:

<p>Some html code</p>

The following is a truncated article:<div><%=truncated_text%></div>

将上面被强制截断的代码片断填充到这段代码可能会让好好的html页面面目全非。

因此,我们需要"优雅"的去截断这段html。

何谓"优雅"?

造成上述问题的根本原因在于对html的强制截断忽略了html的结构信息,使得后面浏览器的分析操作出现紊乱。

因此,优雅的去进行html截断必须在截断后仍旧维持当前的html结构信息。

可能你会说,这还不简单,直接实现一个html parser或者用xml dom分析器来完成此事。的确可以,不过这样的效率和代价实在有点可怕了。因此,要完成这个优雅的截断操作,同时需要在执行效率以及资源消耗间做取舍。同时,尽量避免动辄用dom parser的恶俗。

寻找一种刚好能解决此问题,且保证效率较高并尽量避免滥用资源的途径是我们需要的。

我的方法

相信在这个所谓的什么"web2.0" "web3.0?"的扯淡名词时代恐怕已经有人实现过类似的东西,所以这里仅说说我目前的实现方案。如果你知道有更好的办法,希望能和大家分享。

撇开具体实现,这个问题其实很简单,就是一个配对问题。用一个stack来跟踪html标签的使用情况,每个<tag>应该有一个对应的</tag>配对。因此我们只要扫描一遍html,堆栈上残留的元素就是没有配对的tag。这些tag就是因为我们的暴力截取而成为孤对的。因此我们只要在html代码末尾FILO的补上这些这些tag的对应/tag即可。

但是还有些细节问题。

  1. 因为html没有xml规范,所以一些情况下未配对的tag也是允许的,例如<BR>。
  2. 存在单一自配对的<tag/>例如<img xxx />。

 同时,对于暴力截断的html代码,我们不能奢望它们正好截断在一对tag之间,就像上面给出的例子那样,对于末尾是

〈a href=\"some

 的情况,我们还首先需要将这些“残缺”的tag给删去,否则即使配对仍旧存在问题。

大致的思路就是这样,关键就是如何实现的问题了。这里我仅采用javascript的String.replace方法进行上述的html扫描。

具体实现

实际上实现的困难在于如何去识别html的tag。这里的底线是不能用现有的dom parser。Javascript的正则式功能在这里就能派上大用处了。根据上面的分析,为了进行tag匹配的分析,我们需要识别出html中的所有tag。

他们存在下面几种形式

  1. < tagname some_attr>
  2. < / tagname>
  3. < tagname />

我们的任务是编写正则式去查找这些tag。并且捕获到tagname。这里用到了一个偏方,利用String.replace方法。

一般,很多人都这样用它some_str.replace(/some regexp/, "new text");

实际上,他有另一个形式:

some.replace(/some regexp/, function( match_text)

     {

          return "new text";

     });

利用一个匿名函数进行替换...

实际上,这个replace是一个再好不过的基于正则式的查找操作手段。因为相比手写一个查找循环,他的迭代操作是在解析器内部实现的,效率肯定要高很多。同时据我所知,要写个循环依次查找每个匹配正则式的循环很不容易,貌似没法指定搜索的开始字符。

好了,到此关键问题解决了。试验证明用这个办法效率完全可以接受,同时完全没有使用任何第三方的东西。

是具体实现时候要注意考虑前面提到的所有特殊情况。

下面来看下效果,为了展示各种情况,另外给个例子:

<p>this is a truncated html sourcesome hyperlink</a>.<BR>more text</p><div><dt>some url〈a href=\"some UR

经过处理后,变成了:

<p>this is a truncated html sourcesome hyperlink</a>.<BR>more text</p><div><dt>some url</dt></div>

 

有了这个功能,相信在作诸如自动缩略文处理时候就会轻松许多。(此刻让我想起了某些blog强制把html转成纯文本作略文的办法...)

 

最后,给出一个测试代码。喜欢的可以直接拿去用。当然,留下原始作者信息

http://www.csksoft.net/data/legacyftp/Products/code_and_lib/wise_cut_csk.zip

分页:[«]1[»]

Copyright Shikai Chen 2000-2012. Powered By Z-Blog(CSK Modified)