中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

細(xì)說(shuō) Java 中的字符和字符串( 一 )

2018-07-02    來(lái)源:importnew

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬(wàn)Linux鏡像隨意使用

一道經(jīng)典問(wèn)題

Java里的char類型能不能存儲(chǔ)一個(gè)中文字符?

對(duì)于這道題,絕大多數(shù)的答案都是“可以存儲(chǔ)”。給出的原因包括:
1. java中的char是unicode存儲(chǔ),unicode編碼字符集中包含了漢字,所以可以存儲(chǔ)中文;
2. java內(nèi)部其實(shí)是使用的UTF-16的編碼,所以是支持大部分非生僻漢字的;
3. 采用Unicode編碼集,一個(gè)char占用兩個(gè)字節(jié),而一個(gè)中文字符也是兩個(gè)字節(jié),因此Java中的char是可以表示一個(gè)中文字符的;
4. Java的char只能表示utf-16中的BMP部分中文字符,不能表示擴(kuò)展字符集里的中文字符;

那么,這個(gè)問(wèn)題的終極答案到底是什么?

Java API中關(guān)于char的說(shuō)明

原文地址:https://docs.oracle.com/javase/7/docs/api/java/lang/Character.html

char類型是按照Unicode規(guī)范實(shí)現(xiàn)的一種數(shù)據(jù)類型,固定16bit大小,F(xiàn)如今,
Unicode字符集已經(jīng)進(jìn)行了擴(kuò)展,表示的范圍已經(jīng)超過(guò)了16bit。Unicode字符集的
數(shù)值范圍擴(kuò)大到了[U+0000,U+10FFFF]。

也就是說(shuō)一個(gè)char能夠存儲(chǔ)16bit大小的數(shù)值,即2個(gè)字節(jié)。但是,就常用的UTF-8編碼來(lái)說(shuō),我們都聽(tīng)說(shuō)過(guò)他是用3或者4個(gè)字節(jié)來(lái)表示一個(gè)漢字的。就拿3個(gè)字節(jié)來(lái)算的話,一個(gè)char也存不下是不是?

我們繼續(xù)看api文檔的其他段落:

一個(gè)char值可以表示BMP范圍內(nèi)的Unicode字符。BMP表示[U+0000, U+FFFF]之間的Unicode字符。

而且,絕大部分的中文字符的Unicode范圍是[0x4E00, 0x9FBB],恰好是在BMP范圍內(nèi)。

是不是說(shuō)這里出現(xiàn)了破解不了的矛盾呢?UTF-8占用3到4個(gè)字節(jié),char只能存2個(gè)字節(jié)(16bit),然而UTF-8中的幾乎所有漢字都是在BMP范圍內(nèi),也就是在char可存儲(chǔ)的范圍內(nèi),是不是矛盾了?

答案是不矛盾!關(guān)鍵點(diǎn)就在于接下來(lái)給出總結(jié)的第一條!

這里先給出總結(jié),后續(xù)再給出解釋:
1.char字符存儲(chǔ)的是Unicode編碼的代碼點(diǎn),也就是存儲(chǔ)的是U+FF00這樣的數(shù)值,然而我們?cè)谡{(diào)試或者輸出到輸出流的時(shí)候,是JVM或者開(kāi)發(fā)工具按照代碼點(diǎn)對(duì)應(yīng)的編碼字符輸出的。
2. 所以雖然UTF-8編碼的中文字符是占用3個(gè)或者4個(gè)字節(jié),但是對(duì)應(yīng)的代碼點(diǎn)仍然集中在[0x4E00, 0x9FBB],所以char是能夠存下在這個(gè)范圍內(nèi)的中文字符的。
3. 但是對(duì)于超過(guò)16bit的Unicode字符集,也就是Unicode的擴(kuò)展字符集,一個(gè)char是放不下的,需要兩個(gè)char才能放下。

Unicode編碼

Unicode的出現(xiàn)是對(duì)混亂的ANSI編碼世界的一個(gè)大一統(tǒng),因而也叫做統(tǒng)一碼、萬(wàn)國(guó)碼、單一碼。Unicode編碼把世界上常用的語(yǔ)言字符都進(jìn)行了統(tǒng)一的編碼,一個(gè)數(shù)值就代表一個(gè)字符,而且世界范圍內(nèi)公認(rèn)。

ANSI的編碼世界里,各中語(yǔ)言有自己的編碼規(guī)范,同一個(gè)數(shù)值在不同的國(guó)家代表不同的字符。所以當(dāng)文字在不同國(guó)家傳遞的時(shí)候(比如發(fā)郵件,看國(guó)外網(wǎng)頁(yè)),問(wèn)題就很大了,我明明寫(xiě)的是“愛(ài)我中華”,美國(guó)朋友看到的確實(shí)”°??ò?D?a”,一定是一臉問(wèn)號(hào)!

        //=====模擬文字在不同編碼語(yǔ)言間傳遞的過(guò)程=====
        //發(fā)帖子
        String s = "愛(ài)我中華";
        //編碼成字節(jié)流,通過(guò)網(wǎng)絡(luò)傳入,或者存儲(chǔ)到文件
        byte[] bytes = s.getBytes("GB2312");
        System.out.println(s);
        //國(guó)外朋友用自己電腦的編碼方式解析字節(jié)流
        String s2 = new String(bytes, "ISO-8859-1");
        //oh! shit, wtf!        
        System.out.println(s2);

有了Unicode這個(gè)統(tǒng)一編碼之后,全世界的計(jì)算機(jī)都能正確的解析到原始的字符,對(duì)于國(guó)內(nèi)的文字信息,國(guó)外的朋友唯一要做的就是懂中文!

UTF-8只是Unicode編碼的一種編碼轉(zhuǎn)換規(guī)范,也就是怎么存儲(chǔ)Unicode代碼點(diǎn)的方案之一。另外還有UTF-16和UTF-32等編碼規(guī)范。Unicode為什么需要這么多編碼規(guī)范?直接存儲(chǔ)代碼點(diǎn)行不行?

當(dāng)然不行,存儲(chǔ)了就需要解析比如”漢字”兩個(gè)字的Unicode代碼點(diǎn)是“0x6c49和0x5b57”也就是”6c495b57”。而且,Unicode的代碼點(diǎn)還有3個(gè)字節(jié)的,比如”10FF3B”,對(duì)于一個(gè)很長(zhǎng)的上述數(shù)字串該怎么解析?比如“10FF3B6c495b57”!

所以,需要某種編碼方案來(lái)區(qū)分那幾個(gè)數(shù)值是一個(gè)Unicode代碼點(diǎn),這種方案就是UTF-8、UTF-16、UTF-32這樣的編碼方案。

UTF-8編碼和代碼點(diǎn)對(duì)應(yīng)關(guān)系

UTF-8以字節(jié)為單位對(duì)Unicode進(jìn)行編碼。從Unicode到UTF-8的編碼方式如下:

Unicode編碼(十六進(jìn)制) UTF-8 字節(jié)流(二進(jìn)制)
000000-00007F 0xxxxxxx
000080-0007FF 110xxxxx 10xxxxxx
000800-00FFFF 1110xxxx 10xxxxxx 10xxxxxx
010000-10FFFF 11110xxx10xxxxxx10xxxxxx10xxxxxx

有沒(méi)有發(fā)現(xiàn)點(diǎn)什么?當(dāng)一個(gè)字節(jié)表示一個(gè)字符時(shí),二進(jìn)制開(kāi)頭是0;當(dāng)兩個(gè)字節(jié)表示一個(gè)字符時(shí),二進(jìn)制開(kāi)頭是11;當(dāng)3個(gè)字節(jié)表示一個(gè)字符時(shí),二進(jìn)制開(kāi)頭是111;依次類推!

UTF-8編碼加入了多余的標(biāo)識(shí)位來(lái)區(qū)分一個(gè)Unicode代碼點(diǎn)!才會(huì)出現(xiàn)中文漢字集中在[0x4E00, 0x9FBB]范圍的16bit數(shù)值內(nèi),UTF-8卻需要3個(gè)字節(jié)存儲(chǔ)的原因。

另一個(gè)經(jīng)典問(wèn)題

怎么判斷Java字符串是否包含中文?

這個(gè)問(wèn)題也很經(jīng)典,一般我們可以查到的方法如下:

    //代碼來(lái)自HanLP自然語(yǔ)言處理庫(kù),git地址:https://github.com/hankcs/HanLP/blob/master/src/main/java/com/hankcs/hanlp/utility/TextUtility.java
    /**
     * 判斷某個(gè)字符是否為漢字
     *
     * @param c 需要判斷的字符
     * @return 是漢字返回true,否則返回false
     */
    public static boolean isChinese(char c)
    {
        String regex = "[\\u4e00-\\u9fa5]";
        return String.valueOf(c).matches(regex);
    }
//來(lái)源地址:https://blog.csdn.net/z69183787/article/details/53162069這里考慮進(jìn)了CJK的擴(kuò)展字符集


// GENERAL_PUNCTUATION 判斷中文的“號(hào)  
    // CJK_SYMBOLS_AND_PUNCTUATION 判斷中文的。號(hào)  
    // HALFWIDTH_AND_FULLWIDTH_FORMS 判斷中文的,號(hào)  
    private static final boolean isChinese(char c) {  
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);  
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS  
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS  
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A  
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION  
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION  
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {  
            return true;  
        }  
        return false;  
    }

總結(jié)一下,一般來(lái)說(shuō)用第一種方法就足夠了,擴(kuò)展字符集用的比較少,另外從HanLP的github星數(shù)來(lái)說(shuō),這種方案的通用度還是可信的。

這里寫(xiě)圖片描述

好了,先到這里。這里也留一個(gè)坑,mysql數(shù)據(jù)庫(kù)里邊的VARCHAR類型和Java的char類型是一種處理方式么?下一篇也會(huì)從String源代碼的角度對(duì)這里的分析進(jìn)行一個(gè)佐證。

標(biāo)簽: Mysql 代碼 數(shù)據(jù)庫(kù) 網(wǎng)絡(luò)

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:使用 JITWatch 查看 JVM 的 JIT 編譯代碼

下一篇:深入 Spring Boot :實(shí)現(xiàn)對(duì) Fat Jar jsp 的支持