亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
12下一頁
最近訪問板塊 發(fā)新帖
查看: 9555 | 回復: 12
打印 上一主題 下一主題

[C] 單字節(jié)字符編碼識別問題,windows-1251字符集識別問題 [復制鏈接]

論壇徽章:
3
摩羯座
日期:2013-11-12 20:06:19午馬
日期:2013-11-27 16:35:55雙魚座
日期:2014-04-04 19:02:30
跳轉到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2012-10-26 21:46 |只看該作者 |倒序瀏覽
好吧,不得不提個問題了,關于windows-1251字符集檢測和轉碼utf-8的問題。

其實我對字符集,unicode,utf-8啥的一知半解。
  

    最近在做android,遇到一個mp3文件中俄文字符顯示亂碼的問題。其實呢,對于這種蛋疼的問題完全可以無視的,但是bug是外國客戶報出來的,優(yōu)先級P0。我想肯定是那個制作這個mp3的人,在編輯文件信息(歌曲名字,專輯...)的時候保存成了window-1251,結果到android上媒體文件掃描的時候,不認識這個字符集然后就亂碼了。我又想起序哥當年教育我,utf-8保存文件是程序員的基本常識。
    我看了下android上媒體掃描這部分的代碼,對于雙字節(jié)編碼的字符android上會做一個檢測找到其對應的字符集,例如gbk,big5, shift-jis這些字符集。這個檢測依據(jù)就是到一個CharSetRange的表中出二分查找這個字符,看看在不在對應的表中。
   Ok,我的問題是,對于windows-1251這種單字節(jié)編碼的字符,該怎么做檢測呢?比如兩個俄文字符例如 A B,在windows-1251上被編碼成0xCFF0,但是按照android原來的檢測方案0xCFF0這兩個字節(jié)會被當成一個字符去那幾個CharSetRange里面查表,查找失敗就什么都不做直接傳到上層,然后顯示就是亂碼,那些亂碼的字符和用utf-8打開這個mp3文件看到的一樣。
   唉,我凌亂了,對于這種單字節(jié)編碼的字符,在這個字符串傳過來的時候我有辦法做個檢測嗎?有辦法知道是哪種字符集嗎?我想通過查找字符范圍的方法并不能確定是哪一個單字節(jié)字符集吧?因為,單字節(jié)誒我怎么知道0xCF這個字符不會出現(xiàn)在其他的什么XXX字符集中?
   看看這個鏈接是windows-1251 to Unicode table。其實,這種字符的轉換的問題,只要按照一個native code to unicode表轉成對應的unicode碼字傳到上層就ok了,是這樣嗎?
     
    字太多,大神看的煩,我可以把代碼貼上來。謝謝各位了。


@starwing83 序哥,我就不浪費你的電話費了,浪費一點點流量吧!

論壇徽章:
3
摩羯座
日期:2013-11-12 20:06:19午馬
日期:2013-11-27 16:35:55雙魚座
日期:2014-04-04 19:02:30
2 [報告]
發(fā)表于 2012-10-26 21:53 |只看該作者
還是貼個代碼吧....

  1. static uint32_t possibleEncodings(const char* s)
  2. {
  3.     uint32_t result = kEncodingAll;
  4.     // if s contains a native encoding, then it was mistakenly encoded in utf8 as if it were latin-1
  5.     // so we need to reverse the latin-1 -> utf8 conversion to get the native chars back
  6.     uint8_t ch1, ch2;
  7.     uint8_t* chp = (uint8_t *)s;

  8.     while ((ch1 = *chp++)) {
  9.         if (ch1 & 0x80) {
  10.             ch2 = *chp++;
  11.             ch1 = ((ch1 << 6) & 0xC0) | (ch2 & 0x3F);
  12.             // ch1 is now the first byte of the potential native char

  13.             ch2 = *chp++;
  14.             if (ch2 & 0x80)
  15.                 ch2 = ((ch2 << 6) & 0xC0) | (*chp++ & 0x3F);
  16.             // ch2 is now the second byte of the potential native char
  17.             int ch = (int)ch1 << 8 | (int)ch2;
  18.             result &= findPossibleEncodings(ch);
  19.         }
  20.         // else ASCII character, which could be anything
  21.     }

  22.     return result;
  23. }
復制代碼
  1. extern uint32_t findPossibleEncodings(int ch)
  2. {
  3.     // ASCII matches everything
  4.     if (ch < 256) return kEncodingAll;

  5.     int result = kEncodingNone;

  6.     if (charMatchesEncoding(ch, kShiftJISRanges, ARRAY_SIZE(kShiftJISRanges)))
  7.         result |= kEncodingShiftJIS;
  8.     if (charMatchesEncoding(ch, kGBKRanges, ARRAY_SIZE(kGBKRanges)))
  9.         result |= kEncodingGBK;
  10.     if (charMatchesEncoding(ch, kBig5Ranges, ARRAY_SIZE(kBig5Ranges)))
  11.         result |= kEncodingBig5;
  12.     if (charMatchesEncoding(ch, kEUCKRRanges, ARRAY_SIZE(kEUCKRRanges)))
  13.         result |= kEncodingEUCKR;

  14.     return result;
  15. }
復制代碼

論壇徽章:
5
獅子座
日期:2013-08-20 10:12:24午馬
日期:2013-11-23 18:04:102015年辭舊歲徽章
日期:2015-03-03 16:54:152015亞冠之德黑蘭石油
日期:2015-06-29 18:11:1115-16賽季CBA聯(lián)賽之新疆
日期:2024-02-21 10:00:53
3 [報告]
發(fā)表于 2012-10-26 21:55 |只看該作者
這樣,你能不能獲得系統(tǒng)的默認編碼?如果發(fā)現(xiàn)編碼不是UTF8(這個應該很簡單),就認為是當前編碼(肯定是俄文),然后轉換成utf8,怎么樣?

論壇徽章:
3
摩羯座
日期:2013-11-12 20:06:19午馬
日期:2013-11-27 16:35:55雙魚座
日期:2014-04-04 19:02:30
4 [報告]
發(fā)表于 2012-10-26 22:01 |只看該作者
starwing83 發(fā)表于 2012-10-26 21:55
這樣,你能不能獲得系統(tǒng)的默認編碼?如果發(fā)現(xiàn)編碼不是UTF8(這個應該很簡單),就認為是當前編碼(肯定是俄 ...


肯定不行。磕愫鲇莆野,我跟我那個同事的方案不是一樣惡心嗎?用你的話說,很臟....

論壇徽章:
5
獅子座
日期:2013-08-20 10:12:24午馬
日期:2013-11-23 18:04:102015年辭舊歲徽章
日期:2015-03-03 16:54:152015亞冠之德黑蘭石油
日期:2015-06-29 18:11:1115-16賽季CBA聯(lián)賽之新疆
日期:2024-02-21 10:00:53
5 [報告]
發(fā)表于 2012-10-26 22:05 |只看該作者
回復 4# mci2004


    C層面應該有直接轉utf8的方法,即使沒有我記得Android的C層面也有ICU這樣的庫,你找找怎么用,獲取默認locale應該也是有方法的,一種是LANG環(huán)境變量,一種是LC_XXX環(huán)境變量等等,你找找這方面的資料嘛。

論壇徽章:
2
青銅圣斗士
日期:2015-11-26 06:15:59數(shù)據(jù)庫技術版塊每日發(fā)帖之星
日期:2016-07-24 06:20:00
6 [報告]
發(fā)表于 2012-10-26 22:40 |只看該作者
character(或者code point) 是否能按某種方式編碼為 bytes? 這是可以檢測出的。
具體術語其實很混亂。。。 舉個例子就是:

'©' <- 能看到這個字符么? copy right sign。 它的code point是0xa9。
可以確定它能按utf8編碼為0xc2, 0xa9, 也能確定它不能按cp936編碼。 至于怎么確定。。。 查文檔。。。



而從一堆bytes推測它們是由哪些character以什么編碼得到。。。 這只能。。。
舉個例子。。。
"\xce\xbb", 它可能是'λ'(小寫希臘字母lambda, code point=0x3bb)按utf-8編碼得到, 也可能是'位'(code point=0x4f4d)按cp936編碼得到。
如果把"\xce\xbb"傳給你的人不告訴你他使用的編碼方式。。。  是沒法確定他到底是想表達'λ'還是'位'。。。

當然,bytes給得夠多的話,還是有很高概率猜對(只有一種解碼方式完全不產生錯誤)的。。。

具體。。。   讓序哥去翻vim的源代碼唄。。。

論壇徽章:
3
摩羯座
日期:2013-11-12 20:06:19午馬
日期:2013-11-27 16:35:55雙魚座
日期:2014-04-04 19:02:30
7 [報告]
發(fā)表于 2012-10-27 00:00 |只看該作者
回復 6# OwnWaterloo


    Waterloo大神都來了,十分感謝,“猜”這個我大概明白一點,說白了就是計算一個可信度的問題。這個蛋疼的問題,和序哥討論過了,只能用比較惡心的方法來規(guī)避了。其實,我倒覺得不改最和諧。

論壇徽章:
3
摩羯座
日期:2013-11-12 20:06:19午馬
日期:2013-11-27 16:35:55雙魚座
日期:2014-04-04 19:02:30
8 [報告]
發(fā)表于 2012-10-28 02:02 |只看該作者
本帖最后由 mci2004 于 2012-10-28 02:02 編輯

@starwing83 序哥,今天晚上又仔細看了下代碼,發(fā)現(xiàn)代碼中似乎不可能出現(xiàn)我昨天說的情況----在手機看到的亂碼就是latin1編碼。

1,
首先,可以確定你說的是對的,在vim上打個一個mp3文件看到的亂碼確實是latin1,為此我特地去查了ISO-8859-1,也就說明了一個文件在vim上如果它不認識直接就當作latin1來轉了。而且latin1是單字節(jié)的。

2,
關于locale的問題,我也查看了代碼,locale信息的確定實際上通過jdk里面的Local類來確定的。這個Locale的確定又和android的系統(tǒng)屬性有關。還記得我們昨天看到的那個函數(shù)嗎?
  1. // if the locale encoding matches, then assume we have a native encoding.
  2.         if (encoding & mLocaleEncoding)
復制代碼
事實上這個函數(shù)是做一個double check后面一個mLocalEncoding是通過android系統(tǒng)在java層獲得的。前面一個encoding是通過findPossibleEncoding()---查巨表的函數(shù)獲得的。如果這兩個相等就非常確定可以是四種字符集中的某一個了,就可以交給下面的conertValues()了。

3,
回到最開始的問題,我為什么可以確定latin1編碼不可能出現(xiàn)呢?因為,我看到了下面的代碼
還記得endFile()這個函數(shù)吧?在沒有比配成功字符集后,會直接交給上層去處理,也就是下面的邏輯
  1. // if the locale encoding matches, then assume we have a native encoding.
  2.         if (encoding & mLocaleEncoding)
  3.             convertValues(mLocaleEncoding);

  4.         // finally, push all name/value pairs to the client
  5.         for (int i = 0; i < mNames->size(); i++) {
  6.             status_t status = handleStringTag(mNames->getEntry(i), mValues->getEntry(i));
  7.             if (status) {
  8.                 break;
  9.             }
復制代碼
convertValues沒有機會執(zhí)行,那么直接handleSringTag,這個時候那個傳過來的字符(亂碼那個)被當作一個字符串傳進了handleString里(沒做任何處理)。

//序哥下面是最后一個函數(shù)handleStringTag,主要關注value參數(shù),它是亂碼
  1. virtual status_t handleStringTag(const char* name, const char* value)
  2.     {
  3.         ALOGV("handleStringTag: name(%s) and value(%s)", name, value);
  4.         jstring nameStr, valueStr;
  5.         if ((nameStr = mEnv->NewStringUTF(name)) == NULL) {
  6.             mEnv->ExceptionClear();
  7.             return NO_MEMORY;
  8.         }

  9.         // Check if the value is valid UTF-8 string and replace
  10.         // any un-printable characters with '?' when it's not.
  11.         char *cleaned = NULL;
  12.         //判斷是不是utf-8原理很簡單,看單個字節(jié)是否在0x80-->0xBF之間,序哥這里有什么要補充的嗎?
  13.         if (utf8_length(value) == -1){
  14.             cleaned = strdup(value);
  15.             char *chp = cleaned;
  16.             char ch;
  17.             while ((ch = *chp)) {
  18.                 if (ch & 0x80) {
  19. //看這里,如果不是utf-8且字符在0x80之后,就認為是unprintable,然后設置成‘?’。
  20.                     *chp = '?';
  21.                 }
  22.                 chp++;
  23.             }
  24.             value = cleaned;
  25.         }
  26.         valueStr = mEnv->NewStringUTF(value);
  27.         free(cleaned);
  28.         if (valueStr == NULL) {
  29.             mEnv->DeleteLocalRef(nameStr);
  30.             mEnv->ExceptionClear();
  31.             return NO_MEMORY;
  32.         }

  33.         mEnv->CallVoidMethod(
  34.             mClient, mHandleStringTagMethodID, nameStr, valueStr);

  35.         mEnv->DeleteLocalRef(nameStr);
  36.         mEnv->DeleteLocalRef(valueStr);
  37.         return checkAndClearExceptionFromCallback(mEnv, "handleStringTag");
  38.     }
復制代碼
所以我覺得應該會被顯示成'?'才對啊。難道序哥,這個字符傳到java層會被轉換城latin1嗎?不可能吧,java的文檔我查了,沒有這個說法?
但是我肯定我在手機上看到的那個亂碼是latin1.

論壇徽章:
5
獅子座
日期:2013-08-20 10:12:24午馬
日期:2013-11-23 18:04:102015年辭舊歲徽章
日期:2015-03-03 16:54:152015亞冠之德黑蘭石油
日期:2015-06-29 18:11:1115-16賽季CBA聯(lián)賽之新疆
日期:2024-02-21 10:00:53
9 [報告]
發(fā)表于 2012-10-28 03:57 |只看該作者
回復 8# mci2004


    那么,你要干一件事情:

在C++的handleStringTag之前,把數(shù)據(jù)打印出來:直接按16進制打印裸的二進制到Log,然后把數(shù)據(jù)拿出來看。我懷疑在這一步以前,數(shù)據(jù)就已經被當作latin-1給轉成utf-8了。這意味著,讀出來的時候就被轉換了。那么,你就順著數(shù)據(jù)來的方向,隔一段距離打印一次,看看到底是在哪兒被改掉(變成合法的utf-8)的,最終應該能被追蹤到StageFright里面去。然后就容易了。

論壇徽章:
0
10 [報告]
發(fā)表于 2012-10-28 07:59 |只看該作者
叔叔一年多前做android系統(tǒng)層, 也處理過andorid media庫掃描的問題. LZ貼的代碼我依稀看過.

不過對LZ問題的解決, 我?guī)筒簧厦? 純灌水...

順帶吐槽下, Android媒體庫掃描真TMD爛. 認為掃描路徑只有/system/xxx/xxx和一張SD卡的Google程序員更是腦子被驢踢了...

您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復

  

北京盛拓優(yōu)訊信息技術有限公司. 版權所有 京ICP備16024965號-6 北京市公安局海淀分局網監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關心和支持過ChinaUnix的朋友們 轉載本站內容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP