2011-12-29 39 views
1

我正在使用CFStringTokenizer將文本加載到單詞中,但我無法橋接CFString使用的任何編碼和UTF8。試想一下:CFStringTokenizer UTF8 C字符串的令牌範圍

NSString *theString = @"Lorem ipsum dolor sit amet!"; 

const char *theCString = [theString cStringUsingEncoding:NSUTF8StringEncoding]; 

tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault, 
            (__bridge CFStringRef)theString, 
            CFRangeMake(0, [theString length]), 
            kCFStringTokenizerUnitWordBoundary, 
            locale); 

while ((tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer)) != kCFStringTokenizerTokenNone) { 
    tokenRange = CFStringTokenizerGetCurrentTokenRange(tokenizer); 
    memcpy(resultPtr, theCString+tokenRange.location, tokenRange.length); 
} 

不幸的是試圖如果遇到了任何非ASCII字符從C字符串讀出時的標記生成報告的範圍不正確。我怎樣才能從標記器獲得正確的範圍以便能夠從我的C字符串中提取正確的字符?

爲了說明,memcpy的東西比上面的要複雜得多,而且是我的目標設備iPhone上的性能所必需的。所以我什至不能做像創建一個CFString子字符串和轉換,我需要在C字符串的範圍。有沒有辦法做到這一點,而不重新實現各種文字邊界庫,以使它適用於我需要的各種不同語言環境? (這是儘可能多的,所以我不能只是通過尋找「」不幸的是迭代..)

亞歷克

回答

1

NSString的和CFStrings交易在UTF-16,而不是UTF-8,但ISN真正的問題。

您的代碼有兩個問題:

  1. 你假設C字符串的索引對應的源字符串的索引。
  2. 您正在將整個字符串一次性複製並轉換爲UTF-8 C字符串。

#1是導致範圍不匹配的原因,#2導致潛在的高內存使用率,具體取決於字符串的長度和內容。 (UTF-8在某些字母表中每個字符可能需要多達四個字節 - 然後爲C字符串終結符添加一個字符。)

您可以在一次更改中解決這兩個問題。

創建一個NSMutableData來保存輸出。對於每個令牌,將數據長度設置爲範圍的length;然後告訴字符串以期望的編碼方式獲得所需範圍內的字節,並將它們存儲在數據的緩衝區中。 NSString有a method with a very long selector(簡單地說,getBytes:::::::),你會想用這個。

由於您只使用字符串相對於字符串的範圍,因此不存在索引/範圍不匹配,並且每個令牌都將正確輸出。

如果您確實需要C字符串,可以將數據長度設置爲範圍的length + 1,然後在獲取令牌字節後,使用單獨的賦值將最後一個字節設置爲'\0'。 (沒有單獨的任務,該字節可能會保存以前的值。)

+0

感謝彼得,我已經使用getBytes現在和範圍問題的排序。我想避免使用這種方法,因爲它在iPhone上增加了很多開銷,現在這個算法花費了大約60%的時間,其餘的工作並不是微不足道的。遺憾的是,getBytes沒有「NoCopy」變體(我意識到這一點),所以我認爲我已經走到了關於優化的道路盡頭.. – Max 2011-12-29 05:22:25

+0

@Alec:你可能想問另一個問題這表明您打算如何處理UTF-8數據。 – 2011-12-29 11:43:00