许式伟 ID:xushiweizh
408834次访问,排名111好友3人,关注者35
xushiweizh的文章
原创 123 篇
翻译 0 篇
转载 10 篇
评论 915 篇
许式伟的公告

本博客内容除非特殊说明均属原创,如需转载、引用其中的部分文字,请注意以下几点:

1)请在转载(引用)的内容开始添加本人署名,并提供本博客中相应文章的链接。如你的作品为非电子读物或纯文本,请给出链接的url。

2)请勿用于商业用途。

3)如果愿意,请给我邮件:xushiweizh@gmail.com,让我知道我的东西到哪去了。谢过。

重要链接


订阅

最近评论
christanxw:sgi stl的allocator是线程安全的。它提供了3种分配器:
1. alloc,默认的分配器,线程安全的,通常也是性能最佳的。
2.pthread_alloc,也是线程安全的,是每个线程一个分配器,因此不用任何锁机制。速度自然比alloc更快快,但在这个线程deallocate的内存不能在另一个线程使用。
3.single_client_alloc,不是……
lidaobing:刚才错了一个字,重发

我只了解过 django 的模板引擎, django 的做法是用户自定义函数不在模板里,而是属于你程序的一部分,这些函数在导入你的模块后可以被使用。

我觉得一个好的模板引擎不应当对写模板的人有任何程序能力上的要求,一个专注的美工人员能使用的模板引擎才能算是有效的引擎。
lidaobing:我只了解过 django 的模板引擎, django 的做法是用户自定义函数不在模板里,而不是属于你程序的一部分,这些函数在导入你的模块后可以被使用。

我觉得一个好的模板引擎不应当对写模板的人有任何程序能力上的要求,一个专注的美工人员能使用的模板引擎才能算是有效的引擎。
xushiweizh:这里我补充一下我认为“模板引擎”变成“另一个PHP”的界限:当模板引擎支持用户自定义函数时,那么我就认为,它其实是“另一个PHP”。避免这一事件的发生,模板引擎唯一可以做的事情,就是不断扩展它的函数库,来适应新的格式化需求。
xushiweizh:这里我补充一下我认为“模板引擎”变成“另一个PHP”的界限:当模板引擎支持用户自定义函数时,那么我就认为,它其实是“另一个PHP”。避免这一事件的发生,模板引擎唯一可以做的事情,就是不断扩展它的函数库,来适应新的格式化需求。
文章分类
收藏
相册
DocX预览图
Google vs. 百度
WinX相关
WINX团队
ebasil的专栏(RSS)
VisualFC/WINX专栏(RSS)
任风行(一路奔跑)(RSS)
绅士亦花心之WINX相关(RSS)
许伟群的专栏(RSS)
友情链接
QWL1996的专栏(RSS)
Sting的专栏(RSS)
SunHui的专栏(RSS)
不亦快斋(RSS)
于无声处(RSS)
手机开发论坛
珠穆朗玛(老汉)(RSS)
福&柯实验室(RSS)
存档
软件项目交易
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes

原创 文本分析的三种典型设计模式收藏

新一篇: C++内存管理变革(3):另类内存管理 | 旧一篇: 驳“C语言已经死了”

文本分析的三种典型设计模式

许式伟
2004-10-27


事件驱动:Parse-Handler模型(如:xml之SAX模型)

该模型主要有Parser和Handler两个组件。其原型大体如下:

class xxxHandler
{
public:
   
// any event sended from Parser
   ...
};

class xxxParser
{
public:
   xxxxParser(InputSource
* source);
 
   HRESULT parse(xxxxHandler
* handler)
   {
      
// analyze source and send event to handler
      ...
   }
};

该模型不规定Handler类型的详细规格,由Parser的实现者根据具体情况而定。
这种模型的核心思想就是由Parser类来具体分析文本的格式,而让信息真正的处理者Handler类从具体的格式中脱离出来,不再需要关心文本物理组织细节。


Tokenizer模型(如:编译器的词法分析器)

这种模型仅涉及一个Tokenizer组件。该组件负责将文本分解为一个个token。其原型大体如下:

class xxxTokenizer
{
public:
   xxxTokenizer(InputSource
* source);
 
   
//
   
// 成功返回S_OK,如果遇到eof返回S_FALSE。
   
//
   HRESULT next(TOKEN* token);
};

其中分析的结果以一个结构体TOKEN表示。这个结构体如何设计,同样视具体情况而定。通常它看起来是这样的:

struct TOKEN
{
 UINT type;
 union
 {
  DATATYPE1 data1; 
// 当type = type1时
  DATATYPE2 data2; // 当type = type2时
  ...
 };
};

有了Tokenizer,我们就可以轻易的遍历整个文档:

void visit(InputSource* source)
{
 TOKEN token;
 xxxTokenizer tokenizer(source);
 
while (tokenizer.next(&token) == S_OK)
 {
  print(token);
 }
}

token应当如何划分,其粒度如何,完全取决于设计者的考量。以以下一段xml文本为例:
 <elem attr="value">content</elem>
你可以划分为:

 <elem    // element start
 attr="value"  // attr-value pair
 content    // content
 </elem>    // element end

也可以将attr-value pair细分为三个token:attr, assign-symbol, value。
你甚至也可以将整个element作为一个token。

从广义上来说,我们文件系统提供的字节流本身已经是一个Tokenizer了,只不过它划分的token是一个个并无多少逻辑含义的character。

而我们后面提到的DOM模型,也可以算是一个Tokenizer。只不过它划分的token只有一个,就是DOM树,与文件系统的字节流走的是另一个极端。

Tokenizer方式与Parse-Handler方式设计思路,最大的不同在于具体处理信息的人主被动地位相异。在Tokenizer模式下,信息处理者调用Tokenizer得到分析数据,如果相邻的token存在上下文关系,你可以根据需要去取得下一个token,故处于主动地位。

而Parse-Handler模式相关死板一些,一方面Handler类实现者才是真正试图处理信息的人,但是实际上对信息的划分(token)却是由Parse规定的,未必完全符合Handler类的需求。另一方面在token存在上下文关系,当前接受的数据信息不足时,Handler类无法随心所欲的取得下一个token(因为从流程上它是被动的数据接受方),而只能暂时缓存数据,等待下一条信息的到来。

 

文档对象:DOM模型

DOM模型是最高级的一种模型。它的思路是将文档完整地读入内存,并提供数据访问接口。
DOM模型消耗的内存最多,可提供的服务(我们可以联想一下xml的诸多应用,如xslt等)也最为完整。

这里提到DOM模型消耗的内存最多,这种说法并不全面。例如,在将它与Parse-Handler模型相比时,我们只是计算了Parser的开销,而Handler类是客户实现的,内存开销多少,无从计算。

另一方面,由于DOM模型可以按自己的方式组织数据,它在内存开销上的可优化余地很大,并且客户在使用它时通常不再需要大量的内存分配操作;而Parse-Handler模型中,Handler类的实现者出现蹩脚的设计可能性非常高,计入Handler类的内存开销的话,有时甚至可能远远超过采用DOM模型。

因此我个人认为相对于DOM的能力而言,内存问题在DOM模型中并不算一个了不起的缺陷。实现者可以有很多技巧来进行内存优化。

但是DOM模型有一个问题,就是它一开始就将文档完整的读入了内存,使得它无法胜任那些对响应时间要求较高、希望能够渐进处理的应用。而这一点是采用Parse-Handler模型和Tokenizer模型的好处。

 

后记

这篇文章写得比较早,因为最近写WINX可视化开发工具相关的设计稿时用到,所以整理了下。我个人在文本文件和各种文档格式的文件打交道较多,多年来也算是形成了一定的经验。我个人现在越来越倾向于采用DOM模型来处理文件。原因在于采用DOM模型有很多优点:

  • DOM模型是提供了最高级的服务,模块的客户负担少。
     
  • 模块划分极其清晰,方便维护。通常DOM模型的内部仍然建立于SAX模型(或Tokenizer模型)上,但是这种依赖局限在DOM模型的内部。因此,程序通常会划分为3层:
       SAX(或Tokenizer) ==> DOM模型 ==> DOMClient(实际的应用)
     
  • 内存管理方面的可优化余地大。在多数情况下,我们建立的DOM模型是只读的(或允许进行少量修改),这种情形下,内存管理方案可以以最简洁的方式实现。下文我们详细讨论这一点。在此之前,我推荐你回顾一下《C++内存管理变革:最袖珍的垃圾回收器》。
     
  • 易获得更好的性能。虽然理论上来讲程序建立在SAX模型性能上可以获得更好的性能,但是经验表明,在团代开发的情形下,采用DOM模型的性能通常可优于建立在SAX模型之上的同样功能的复杂程序(不是简单打印或提取有限数据的情形)。

发表于 @ 2007年01月08日 23:22:00|评论(loading...)|编辑

新一篇: C++内存管理变革(3):另类内存管理 | 旧一篇: 驳“C语言已经死了”

评论

#why0603_2000 发表于2007-01-11 15:14:49  IP: 222.66.73.*
一个字,菜
#zeusever 发表于2007-01-11 17:45:13  IP: 125.70.228.*
你所谓的“Parse-Handler”模式应该就是design-parttern 中的“builder”模式吧:)。
#xushiweizh 发表于2007-01-11 18:54:52  IP:
没错,就是builder模式。
#xushiweizh 发表于2007-01-11 18:59:22  IP:
我不喜欢叫Builder,它比较容易出现歧义。而且多数人喜欢把类名命名为Parser/Handler,而不是Director/Builder。
#zeusever 发表于2007-01-12 09:29:39  IP: 125.70.228.*
呵呵,很多时候我并不用这个模式去paser,比较喜欢用它来验证一个包的合法性。
#zoucongjie 发表于2008-04-03 21:08:47  IP: 219.245.122.*
佩服
发表评论  


当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
Csdn Blog version 3.1a
Copyright © 许式伟