zzOPENCV XML函數完美支持中文方法

           

XML即extensibe markup language的縮寫,也就是可擴展標識語言。由於其開放性,越來越多的軟件採用它作爲描述語言;由於其平臺無關性,越來越多的系統採用它作爲數據傳遞中介。計算機行業已經把XML爲數據交換的標準,並提供了相當數量的支持工具。但是,C++中解析xml還依然不夠完美,特別是對於中文字符集的支持。大家總是遇到各種問題,本文改進了OPENCV的XML讀寫函數,支持中文字符串。

在OPENCV開發包中,存在着讀寫XML的一系列函數,雖然並不完善,有些功能還有欠缺。但是,比起動輒幾兆的XML讀寫開發包(如Xerces-C++),它容易使用,代碼量小。對於在計算機視覺研究過程中的數據交換任務,這些簡單IO函數基本足夠了。唯一可惜的是,它目前不支持中文,在某些需要中文字符串的場合,有些遺憾。能不能通過簡單的修改,讓它支持中文?作者做了如下試驗,修改方法簡單可行!

首先,分析cxpersistence.cpp中的函數,發現只需要修改一處就能夠讓XML系列函數支持中文[2]。也就是檢測字符C是否可打印的宏cv_isprint。即將:
#define cv_isprint(c)     ((signed char)(c) >= (signed char)' ')
替換爲
#define cv_isprint(c)     ((unsigned char)(c) >= 0x20 )

經過一系列測試,發現這樣的修改是可行的。在debug版完全正常,可是,當用release發佈時。VC罷工了,編譯的程序進入類似死循環的狀態。接着,進入漫長的release版本和debug版本的剖析分析[3]。本文來自:http: //www.shenlejun.cn.

最終,得到結論:DEBUG版和RELEASE版的區別,是cxpersistence.cpp中的XML解析函數用到的isdigit(),isalpha(),isalnum(),isspace()等C庫函數,其DEBUG版和RELEASE版的行爲居然不一樣。解決這些問題的途徑很多,最簡單的方法就是,將cxpersistence.cpp中所有的
char c
替換爲
unsigned char c

通過上述2處修改,OPENCV的XML讀寫函數,完全支持中文(包括簡體和繁體)了。呵呵!

測試程序如下:本文來自:蜜蜂電腦.

int sub_test_opencv_xml_write(void)
{
 // 創建文件存儲對象
 CvFileStorage *fs=cvOpenFileStorage("test.xml",0,CV_STORAGE_WRITE);
 // 寫註釋
 cvWriteComment(fs,"測試寫XML文件",1);
 
 // 開始寫結構,類型是圖map,也就是有名字的無序節點集合
 cvStartWriteStruct(fs,"Employee",CV_NODE_MAP);
 // 註釋
 cvWriteComment(fs,"MAP類型,姓名,年齡,薪水",1);
 // 姓名
 cvWriteString(fs,"name","劉越");
 // 年齡
 cvWriteInt(fs,"age",18);
 // 薪水
 cvWriteReal(fs,"salary",2780.3);
 // 銷售次數
 cvWriteInt(fs,"sales_count",4);
 {
  // 銷售具體數據
  int sales_record[]={30000,4200,50090};
  // 註釋
  cvWriteComment(fs,"SEQ類型,銷售記錄",1);
  // 開始寫結構,類型是序列sequence,無名字的有序節點集合
  cvStartWriteStruct(fs,"sales_record",CV_NODE_SEQ);
  // 前3條銷售記錄
  cvWriteRawData(fs,sales_record,3,"i");
  // 第4條銷售記錄,注意無名字
  cvWriteInt(fs,0,6100);
  // 結束
  cvEndWriteStruct(fs);
 }
 {
  // 註釋
  cvWriteComment(fs,"MAP類型,親友",1);
  // 開始
  cvStartWriteStruct(fs,"Parent",CV_NODE_MAP);
  // 父親
  cvWriteString(fs,"father","楊舜");
  // 母親
  cvWriteString(fs,"mother","王娟");
  // 結束
  cvEndWriteStruct(fs);
 }
 // 結束
 cvEndWriteStruct(fs);
 // 釋放文件存儲對象
 cvReleaseFileStorage(&fs);
}

int sub_test_opencv_xml_read(void)
{
 // 文件節點
 CvFileNode * node, *node2;
 char * str;
 int count;
 int * d;
 
 //cve_dm.debug_break();
 // 打開XML文件
 CvFileStorage *fs = cvOpenFileStorage("test.xml",0,CV_STORAGE_READ);
 // 獲得第一層數據節點
 node = cvGetFileNodeByName(fs,0,"Employee");
 str = cvReadStringByName(fs,node,"name");
 printf("/n姓名=%s",str);
 printf("/n年齡=%d",cvReadIntByName(fs,node,"age"));
 printf("/n薪水=%g",cvReadRealByName(fs,node,"salary"));
 count = cvReadIntByName(fs,node,"sales_count");
 printf("/n銷售%d條",count);
 d = cvAlloc(sizeof(int)*count);
 if(d)
 {
  int i;
  node2 = cvGetFileNodeByName(fs,node,"sales_record");
  if(node2)
  {
   cvReadRawData(fs,node2,d,"i");
   printf("/n銷售記錄=");
   for(i=0;i<count;i++)
    printf("%d, ",d[i]);
  }
  cvFree(&d);
 }
 // 獲得第二層節點
 node = cvGetFileNodeByName(fs,node,"Parent");
 printf("/n根節點=%s",cvGetFileNodeName(node));
 str = cvReadStringByName(fs,node,"father");
 printf("/n父親=%s",str);
 str = cvReadStringByName(fs,node,"mother");
 printf("/n母親=%s",str);
}
 


開發環境: VC6.0 + WINXP。

若您有任何改進建議,請告訴我 ^_^

轉自http://www.shenlejun.cn/my/article/show.asp?id=35,沒試過裏面的方法,只是想拿來分享下,有用的時候再來看看。

 

參考文獻:
[1]鄒月明, 剖析Xml4C源碼,完美兼容中文XML
[2]ASCII 、GB2312、GBK、GB18030、unicode、UTF-8字符集編碼詳解
[3]Joseph M. Newcomer, Surviving the Release Version

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章