2012-12-20 43 views
6

我正在用C寫一個HTML解析器,並且正在尋找正確的關注the W3C guidelines on parser implementation。其中一個關鍵點是解析器在Unicode代碼點而不是字節流上運行,這很有意義。來自C中字節的Unicode代碼點流?

基本上,然後,給出已知的字符編碼的緩衝(我將在給出一個明確的輸入編碼,或將使用HTML5預掃描算法做出很好的猜測),什麼是用C的最佳途徑 - 理想跨平臺,但堅持UNIX是好的 - 遍歷相同的Unicode代碼點序列?

是alloc'ing幾個合理大小的緩衝區和使用iconv要走的路?我應該看看ICU嗎?像U16_NEXT這樣的宏似乎非常適合我的任務,但是ICU文檔非常冗長,而且很難確切地看到如何將各種東西粘合在一起。

+0

'iconv'似乎是個不錯的開始。它在概念上簡單並且廣泛可用。 –

+0

好的,我會試試'iconv'。你會說轉換爲UTF-32是最有意義的嗎?儘管它可以說是一種幾乎無用的編碼,但這意味着每4個字節就會代表一個Unicode代碼點。 –

+1

是的,確實如此。 UTF-32是一個非常好的編碼。 –

回答

2

ICU是一個不錯的選擇。我用它與C++並且非常喜歡它。我相信你在C中也能得到類似的思路API。

不完全一樣,但有些相關的可能是這個tutorial解釋如何執行流/增量音譯(在這種情況下,困難的是,「光標」可能是有時一個代碼點)。

2

下面將解碼代碼點並返回多少來增加字符串(多少被「咀嚼」)。請注意,xs_utf16是一個無符號短整數。更多信息:http://sree.kotay.com/2006/12/unicode-is-pain-in.html

enum 
{ 
    xs_UTF_Max   = 0x0010FFFFUL, 
    xs_UTF_Replace  = 0x0000FFFDUL, 
    xs_UTF16_HalfBase = 0x00010000UL, 
    xs_UTF16_HighStart = 0x0000D800UL, 
    xs_UTF16_HighEnd = 0x0000DBFFUL, 
    xs_UTF16_LowStart = 0x0000DC00UL, 
    xs_UTF16_LowEnd  = 0x0000DFFFUL, 
    xs_UTF16_MaxUCS2 = 0x0000FFFFUL, 
    xs_UTF16_HalfMask = 0x000003FFUL, 
    xs_UTF16_HalfShift = 10 
}; 


int32 xs_UTF16Decode (uint32 &code, const xs_utf16* str, int32 len, bool strict) 
{ 
      if (str==0||len==0)   {code=0; return 0;} 

      uint32 c1 = str[0]; 

      //note: many implementations test from HighStart to HighEnd, 
      //     this may be a partial code point, and is incorrect(?) 
      //     trivial checking should exclude the WHOLE surrogate range 
      if (c1<xs_UTF16_HighStart || c1>xs_UTF16_LowEnd)   return 1; 
          //really an error if we're starting in the low range 

      //surrogate pair 
      if (len<=1 || str[1]==0)         {code=xs_UTF_Replace; return strict ? 0 : 1;} //error 
      uint32 c2 = str[1]; 
      code = ((c1-xs_UTF16_HighStart)<<xs_UTF16_HalfShift) + (c2-xs_UTF16_LowStart) + xs_UTF16_HalfBase; 

      if (strict==false)          return 2; 

      //check for errors 
      if (c1>=xs_UTF16_LowStart && c1<=xs_UTF16_LowEnd)   {code=xs_UTF_Replace; return 0;} //error 
      if (c2<xs_UTF16_LowStart || c2>xs_UTF16_LowEnd)   {code=xs_UTF_Replace; return 0;} //error 
      if (code>xs_UTF_Max)          {code=xs_UTF_Replace; return 0;} //error 

      //success 
      return 2; 
}