精华内容
下载资源
问答
  • 源文件字符集:源文件本身也是文本文件,所以源文件字符集是指...编译器字符集:编译器在读取源代码文件时所使用的内部字符集决定了编译器如何把读入的源代码文件字节进行转换,转换是指从一种字符集编码的字节经
    1. 源文件字符集:源文件本身也是文本文件,所以源文件字符集是指源文件保存时采用哪种字符集编码。VC++下源文件默认是gbk编码,如果想要更改,可以通过 文件-高级保存选项 修改某个源文件的编码方式,似乎没有什么选项能够设置创建项目时的源文件编码,需要自己一个一个设。

    2. 编译器字符集:编译器在读取源代码文件时所使用的内部字符集决定了编译器如何把读入的源代码文件字节流进行转换,转换是指从一种字符集编码的字节经过解码再编码到另一种字符集编码的字节。当然编译器内部采用什么字符集不是我们所关心的,是编译器内部的事情。

    3. 执行字符集:编译器在编译时会将 字符/字符串 常量从上一步编码得到的字节转化为相应的字符集,转化为哪种字符集决定了程序在运行时这些字符串采用了哪种字符集编码,举个例子:

    printf("你好"); //程序在执行时 "你好" 这个字符串在内存中保存的是哪种字符集的编码呢?就由这个第3步决定。

    那么,编译器到底会转化为哪种字符集呢?分2种情况:
    1. 如果是窄字符/字符串”“(以char为单位),那么不同的编译器可能不一样。以VC++为例,它是由系统代码页决定的,比如在中文windows系统下就采用GBK编码。
    2. 如果字符/字符串前有指定编码方式,那没什么好说的了,就采用指定的编码方式,如下:

    char* s1 = u8"hello"; //窄字符串,utf-8编码 (C++11)
    wchar_t* s2 =  L"hello"; //宽字符串,utf-16编码
    char16_t* s3 =  u"hello"; //宽字符串,utf-16编码 (C++11)
    char32_t* s4 =  U"hello"; //utf-32编码 (C++11)
    
    //'\x12' : \x后面接216进制数字,可表示一个窄字符char,多个\x连起来可表示一个utf-8字符,如"\xE4\xBD\xA0"
    //L'\u1234' : \u后面接416进制数字,可表示一个utf-16宽字符
    //U'\U12345678' : \U后面接816进制数字,可表示一个Utf-32

    VC++里如果想要强行改变执行字符集,可以加上一句预处理:

    //设置执行字符集为utf-8
    #if _MSC_VER >= 1600
    #pragma execution_character_set("utf-8")
    #endif

    控制台输出乱码的问题解决

    控制台的代码页默认是和系统代码页是一样的,中文windows下就是GBK,所以你用输出流函数(printf,wprintf,cout,wcout等)输出GBK编码的字符串肯定没问题,现在讨论2种情况:

    • 输出宽字符串,如果直接输出是会乱码的。这里有一个函数:setlocale(),是用来程序运行时设置当前系统的区域信息。而在所有C++程序启动前,locale的默认设置setlocale(LC_ALL,”C”);会被执行,这个”C”肯定不是能支持中文的这样一个环境,而宽字符串在输出时会根据setlocale()的设置将其转为相应区域代码页的编码,当然就会出错了。所以我们可以手动设置一下locale信息就可以了:
    #include <locale.h>
    //使用""的话就从当前系统获取代码页,当然也可以设成具体的,比如"chs"
    int main()
    {
        setlocale(LC_CTYPE,"");
        wprintf(L"你好"); //这样就不会乱码了
        //...
    }
    • 对于窄字符串来说,是不会作编码转换的,所以如果你输出GBK编码的窄字符串,那是没有问题的,但如果是utf-8编码的窄字符串呢?显然又会乱码,这时只能修改控制台窗口的代码页了:
    //经过测试发现没有乱码,但是鼠标点到字上时会变乱,可能需要设置字体
    system("chcp 65001");
    printf(u8"你好");

    Qt下的中文问题

    以前采用 Qt + MSVC编译器 时,在程序中需要用到中文时,直接将字符串传给QString或一些Qt的函数时,会出现乱码。这是因为:Qt内部采用utf-16编码,当你将字符串传给QString或一些Qt的函数时,Qt会将默认其当作utf-8编码的字符串来转换,之前说过,VC++下执行字符集默认是GBK的,所以就会乱码。解决方法有如下几种:

    • 用QTextCodeC或QString转换
    QTextCodeC* c = QTextCodec::codecForName("gbk");
    QString s = c->toUnicode("你好"); //从gbk转为QString
    //或
    QString s = QString::fromLocal8Bit("你好"); //从本地系统代码页转为QString
    
    • 如果支持C++11,直接使用utf-8字符串 u8"你好"

    • 强行更改执行字符集,方法之前说过

    在Qt5之前有这3个函数,可以设置相应的编码问题:

    //设置QString对c风格字符串采用哪种编码方式来处理
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));  
    
    //设置tr("")时对c风格字符串采用哪种编码方式来处理
    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));  
    
    //主要设置QString::from(to)Local8Bit这个函数认为的本地编码方式
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));

    在Qt5中前2个函数被删除了,因为Qt5中QString等对c字符串默认采用utf-8处理(以前是Latin1),所以只要采用 Qt Creator+MinGW编译器,就没有问题了。因为Qt Creator源文件默认是utf-8编码,MinGW执行字符集就是utf-8编码,所以可以直接这样用,不会乱码了:

    QString s = "你好";
    qDebug()<<"你好";
    QMessageBox::information(nullptr,"标题","你好");
    //...

    参考:
    微软C/C++编译器中管理字符集的新选项
    带你玩转Visual Studio
    拨开字符编码的迷雾–编译器如何处理文件编码
    控制台输出乱码问题
    QTextCodec中的setCodecForTr等终于消失了
    源码必须是UTF-8,QString需要它

    展开全文
  • 最近我到了深圳,在找工作,顺便复习一下基础,今天突然想到以前写过的代码,I/O方面的,代码如下: ... import java.io.IOException;...import java.io....各位大神,这是怎么回事,应该怎样设置字符集。。。
  • 十分钟搞清字符集和字符编码

    千次阅读 2016-08-30 17:30:15
    什么是字符集 什么是字符编码 UTF-8和Unicode的关系 UTF-8编码简介 为什么会出现乱码 如何识别乱码的本来想要表达的文字 常见问题处理之Emoji 本文将简述字符集,字符编码的概念。以及在遭遇乱码时的一些...


    本文将简述字符集,字符编码的概念。以及在遭遇乱码时的一些常用诊断技巧

    背景:字符集和编码无疑是IT菜鸟甚至是各种大神的头痛问题。当遇到纷繁复杂的字符集,各种火星文和乱码时,问题的定位往往变得非常困难。本文就将会从原理方面对字符集和编码做个简单的科普介绍,同时也会介绍一些通用的乱码故障定位的方法以方便读者以后能够更从容的定位相关问题。在正式介绍之前,先做个小申明:如果你希望非常精确的理解各个名词的解释,那么可以查阅wikipedia。本文是博主通过自己理解消化后并转化成易懂浅显的表述后的介绍。


    什么是字符集

    在介绍字符集之前,我们先了解下为什么要有字符集。我们在计算机屏幕上看到的是实体化的文字,而在计算机存储介质中存放的实际是二进制的比特流。那么在这两者之间的转换规则就需要一个统一的标准,否则把我们的U盘插到老板的电脑上,文档就乱码了;小伙伴QQ上传过来的文件,在我们本地打开又乱码了。于是为了实现转换标准,各种字符集标准就出现了。简单的说字符集就规定了某个文字对应的二进制数字存放方式(编码)和某串二进制数值代表了哪个文字(解码)的转换关系。 那么为什么会有那么多字符集标准呢?这个问题实际非常容易回答。问问自己为什么我们的插头拿到英国就不能用了呢?为什么显示器同时有DVI,VGA,HDMI,DP这么多接口呢?很多规范和标准在最初制定时并不会意识到这将会是以后全球普适的准则,或者处于组织本身利益就想从本质上区别于现有标准。于是,就产生了那么多具有相同效果但又不相互兼容的标准了。 说了那么多我们来看一个实际例子,下面就是这个字在各种编码下的十六进制和二进制编码结果,怎么样有没有一种很屌的感觉?

    字符集 16进制编码 对应的二进制数据
    UTF-80xE5B18C1110 0101 1011 0001 1000 1100
    UTF-160x5C4C1011 1000 1001 1000
    GBK0x8CC51000 1100 1100 0101

    什么是字符编码

    字符集只是一个规则集合的名字,对应到真实生活中,字符集就是对某种语言的称呼。例如:英语,汉语,日语。对于一个字符集来说要正确编码转码一个字符需要三个关键元素:字库表(character repertoire)、编码字符集(coded character set)、字符编码(character encoding form)。其中字库表是一个相当于所有可读或者可显示字符的数据库,字库表决定了整个字符集能够展现表示的所有字符的范围。编码字符集,即用一个编码值code point来表示一个字符在字库中的位置。字符编码,将编码字符集和实际存储数值之间的转换关系。一般来说都会直接将code point的值作为编码后的值直接存储。例如在ASCII中A在表中排第65位,而编码后A的数值是0100 0001也即十进制的65的二进制转换结果。 看到这里,可能很多读者都会有和我当初一样的疑问:字库表编码字符集看来是必不可少的,那既然字库表中的每一个字符都有一个自己的序号,直接把序号作为存储内容就好了。为什么还要多此一举通过字符编码把序号转换成另外一种存储格式呢?其实原因也比较容易理解:统一字库表的目的是为了能够涵盖世界上所有的字符,但实际使用过程中会发现真正用的上的字符相对整个字库表来说比例非常低。例如中文地区的程序几乎不会需要日语字符,而一些英语国家甚至简单的ASCII字库表就能满足基本需求。而如果把每个字符都用字库表中的序号来存储的话,每个字符就需要3个字节(这里以Unicode字库为例),这样对于原本用仅占一个字符的ASCII编码的英语地区国家显然是一个额外成本(存储体积是原来的三倍)。算的直接一些,同样一块硬盘,用ASCII可以存1500篇文章,而用3字节Unicode序号存储只能存500篇。于是就出现了UTF-8这样的变长编码。在UTF-8编码中原本只需要一个字节的ASCII字符,仍然只占一个字节。而像中文及日语这样的复杂字符就需要2个到3个字节来存储。


    UTF-8和Unicode的关系

    看完上面两个概念解释,那么解释UTF-8和Unicode的关系就比较简单了。Unicode就是上文中提到的编码字符集,而UTF-8就是字符编码,即Unicode规则字库的一种实现形式。随着互联网的发展,对同一字库集的要求越来越迫切,Unicode标准也就自然而然的出现。它几乎涵盖了各个国家语言可能出现的符号和文字,并将为他们编号。详见:Unicode on Wikipedia。Unicode的编号从0000开始一直到10FFFF共分为16个Plane,每个Plane中有65536个字符。而UTF-8则只实现了第一个Plane,可见UTF-8虽然是一个当今接受度最广的字符集编码,但是它并没有涵盖整个Unicode的字库,这也造成了它在某些场景下对于特殊字符的处理困难(下文会有提到)。


    UTF-8编码简介

    为了更好的理解后面的实际应用,我们这里简单的介绍下UTF-8的编码实现方法。即UTF-8的物理存储和Unicode序号的转换关系。 UTF-8编码为变长编码。最小编码单位(code unit)为一个字节。一个字节的前1-3个bit为描述性部分,后面为实际序号部分。

    • 如果一个字节的第一位为0,那么代表当前字符为单字节字符,占用一个字节的空间。0之后的所有部分(7个bit)代表在Unicode中的序号。
    • 如果一个字节以110开头,那么代表当前字符为双字节字符,占用2个字节的空间。110之后的所有部分(5个bit)加上后一个字节的除10外的部分(6个bit)代表在Unicode中的序号。且第二个字节以10开头
    • 如果一个字节以1110开头,那么代表当前字符为三字节字符,占用2个字节的空间。110之后的所有部分(5个bit)加上后两个字节的除10外的部分(12个bit)代表在Unicode中的序号。且第二、第三个字节以10开头
    • 如果一个字节以10开头,那么代表当前字节为多字节字符的第二个字节。10之后的所有部分(6个bit)和之前的部分一同组成在Unicode中的序号。

    具体每个字节的特征可见下表,其中x代表序号部分,把各个字节中的所有x部分拼接在一起就组成了在Unicode字库中的序号

    Byte 1 Byte 2 Byte3
    0xxx xxxx  
    110x xxxx10xx xxxx 
    1110 xxxx10xx xxxx10xx xxxx

    我们分别看三个从一个字节到三个字节的UTF-8编码例子:

    实际字符在Unicode字库序号的十六进制在Unicode字库序号的二进制UTF-8编码后的二进制UTF-8编码后的十六进制
    $0024010 01000010 010024
    ¢00A2000 1010 00101100 0010 1010 0010C2 A2
    20AC0010 0000 1010 11001110 0010 1000 0010 1010 1100E2 82 AC

    细心的读者不难从以上的简单介绍中得出以下规律:

    • 3个字节的UTF-8十六进制编码一定是以E开头的
    • 2个字节的UTF-8十六进制编码一定是以CD开头的
    • 1个字节的UTF-8十六进制编码一定是以比8小的数字开头的

    为什么会出现乱码

    乱码也就是英文常说的mojibake(由日语的文字化け音译)。 简单的说乱码的出现是因为:编码和解码时用了不同或者不兼容的字符集。对应到真实生活中,就好比是一个英国人为了表示祝福在纸上写了bless(编码过程)。而一个法国人拿到了这张纸,由于在法语中bless表示受伤的意思,所以认为他想表达的是受伤(解码过程)。这个就是一个现实生活中的乱码情况。在计算机科学中一样,一个用UTF-8编码后的字符,用GBK去解码。由于两个字符集的字库表不一样,同一个汉字在两个字符表的位置也不同,最终就会出现乱码。 我们来看一个例子:假设我们用UTF-8编码存储很屌两个字,会有如下转换:

    字符 UTF-8编码后的十六进制
    E5BE88
    E5B18C

    于是我们得到了E5BE88E5B18C这么一串数值。而显示时我们用GBK解码进行展示,通过查表我们获得以下信息:

    两个字节的十六进制数值 GBK解码后对应的字符
    E5BE
    88E5
    B18C

    解码后我们就得到了寰堝睂这么一个错误的结果,更要命的是连字符个数都变了。


    如何识别乱码的本来想要表达的文字

    要从乱码字符中反解出原来的正确文字需要对各个字符集编码规则有较为深刻的掌握。但是原理很简单,这里用最常见的UTF-8被错误用GBK展示时的乱码为例,来说明具体反解和识别过程。

    第1步 编码

    假设我们在页面上看到寰堝睂这样的乱码,而又得知我们的浏览器当前使用GBK编码。那么第一步我们就能先通过GBK把乱码编码成二进制表达式。当然查表编码效率很低,我们也可以用以下SQL语句直接通过MySQL客户端来做编码工作:

    mysql [localhost] {msandbox} > select hex(convert('寰堝睂' using gbk));
    +-------------------------------------+
    | hex(convert('寰堝睂' using gbk))    |
    +-------------------------------------+
    | E5BE88E5B18C                        |
    +-------------------------------------+
    1 row in set (0.01 sec)

    第2步 识别

    现在我们得到了解码后的二进制字符串E5BE88E5B18C。然后我们将它按字节拆开。

    Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6
    E5BE88E5B18C

    然后套用之前UTF-8编码介绍章节中总结出的规律,就不难发现这6个字节的数据符合UTF-8编码规则。如果整个数据流都符合这个规则的话,我们就能大胆假设乱码之前的编码字符集是UTF-8

    第3步 解码

    然后我们就能拿着E5BE88E5B18C用UTF-8解码,查看乱码前的文字了。当然我们可以不查表直接通过SQL获得结果:

    mysql [localhost] {msandbox} ((none)) > select convert(0xE5BE88E5B18C using utf8);
    +------------------------------------+
    | convert(0xE5BE88E5B18C using utf8) |
    +------------------------------------+
    | 很屌                               |
    +------------------------------------+
    1 row in set (0.00 sec)

    常见问题处理之Emoji

    所谓Emoji就是一种在Unicode位于\u1F601-\u1F64F区段的字符。这个显然超过了目前常用的UTF-8字符集的编码范围\u0000-\uFFFF。Emoji表情随着IOS的普及和微信的支持越来越常见。下面就是几个常见的Emoji: emoji1 emoji2 emoji3 那么Emoji字符表情会对我们平时的开发运维带来什么影响呢?最常见的问题就在于将他存入MySQL数据库的时候。一般来说MySQL数据库的默认字符集都会配置成UTF-8(三字节),而utf8mb4在5.5以后才被支持,也很少会有DBA主动将系统默认字符集改成utf8mb4。那么问题就来了,当我们把一个需要4字节UTF-8编码才能表示的字符存入数据库的时候就会报错:ERROR 1366: Incorrect string value: '\xF0\x9D\x8C\x86' for column 。 如果认真阅读了上面的解释,那么这个报错也就不难看懂了。我们试图将一串Bytes插入到一列中,而这串Bytes的第一个字节是\xF0意味着这是一个四字节的UTF-8编码。但是当MySQL表和列字符集配置为UTF-8的时候是无法存储这样的字符的,所以报了错。 那么遇到这种情况我们如何解决呢?有两种方式:升级MySQL到5.6或更高版本,并且将表字符集切换至utf8mb4。第二种方法就是在把内容存入到数据库之前做一次过滤,将Emoji字符替换成一段特殊的文字编码,然后再存入数据库中。之后从数据库获取或者前端展示时再将这段特殊文字编码转换成Emoji显示。第二种方法我们假设用-*-1F601-*-来替代4字节的Emoji,那么具体实现python代码可以参见Stackoverflow上的回答

    reference

    如何配置Python默认字符集 字符编码笔记:ASCII,Unicode和UTF-8 Unicode中文编码表 Emoji Unicode Table Every Developer Should Know About The Encoding

    展开全文
  • 那么知道主要原因是编码和解码方式不一样,那么有些时候如果我们知道编码方式,那么解码自然很好搞,例如输出的contentType会告诉浏览器我输出的内容是什么编码格式的,否则浏览器会才用一个当前默认的字符集编码来...

    前面有一篇文章提及到乱码的产生:http://blog.csdn.net/xieyuooo/article/details/6919007

    那么知道主要原因是编码和解码方式不一样,那么有些时候如果我们知道编码方式,那么解码自然很好搞,例如输出的contentType会告诉浏览器我输出的内容是什么编码格式的,否则浏览器会才用一个当前默认的字符集编码来处理;本文要将一些java如何处理没有带正常协议头部的字符集应当如何来处理。

    这里就说的是文件字符集,在了解字符集之前,回到上一篇文章说到默认字符集,自定义字符集,系统字符集,那么当前环境到底用的什么字符集呢?

    System.out.println(Charset.defaultCharset());

    当前java应用可以支持的所有字符集编码列表:

    Set<String> charsetNames = Charset.availableCharsets().keySet();
    for(String charsetName : charsetNames) {
    System.out.println(charsetName);
    }

    因为java的流当中并没有默认说明如何得知文件的字符集,很神奇的是,一些编辑器,类似window的记事本、editplus、UltraEdit他们可以识别各种各样的字符集的字符串,是如何做到的呢,如果面对上传的文件,需要对文件内容进行解析,此时需要如何来处理呢?


    首先,文本文件也有两种,一种是带BOM的,一种是不带BOM的,GBK这系列的字符集是不带BOM的,UTF-8、UTF-16LE、16UTF-16BE、UTF-32等等不一定;所谓带BOM就是指文件【头部有几个字节】,是用来标示这个文件的字符集是什么的,例如:

    UTF-8 头部有三个字节,分别是:0xEF、0xBB、0xBF

    UTF-16BE 头部有两个字节,分别是:0xFE、0xFF

    UTF-16LE 头部有两个字节,分别是:0xFF、0xFE

    UTF-32BE 头部有4个字节,分别是:0x00、0x00、0xFE、0xFF

    貌似常用的字符集我们都可以再这得到解答,因为常用的对我们的程序来讲大多是UTF-8或GBK,其余的字符集相对比较兼容(例如GB2312,而GB18030是特别特殊的字符才会用到)。

    我们先来考虑文件有头部的情况,因为这样子,我们不用将整个文件读取出来,就可以得到文件的字符集方便,我们继续写代码:

    通过上面的描述,我们不难写出一个类来处理,通过inputStream来处理,自己写一个类:

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.PushbackInputStream;
    
    
    public class UnicodeInputStream extends InputStream {
        PushbackInputStream internalIn;    
        boolean isInited = false;    
        String defaultEnc;    
        String encoding;   
        private byte[]inputStreamBomBytes;
        
        private static final int BOM_SIZE = 4;    
        
        public UnicodeInputStream(InputStream in) {
            internalIn = new PushbackInputStream(in, BOM_SIZE);    
            this.defaultEnc = "GBK";//这里假如默认字符集是GBK 
            try {    
                    init();    
                } catch (IOException ex) {    
                    IllegalStateException ise = new IllegalStateException(    
                            "Init method failed.");    
                    ise.initCause(ise);    
                    throw ise;    
                }    
        }
        
        public UnicodeInputStream(InputStream in, String defaultEnc) {    
            internalIn = new PushbackInputStream(in, BOM_SIZE);    
            this.defaultEnc = defaultEnc;    
        }    
        
        public String getDefaultEncoding() {    
            return defaultEnc;    
        }    
        
        public String getEncoding() {  
            return encoding;    
        }    
        
        /**  
         * Read-ahead four bytes and check for BOM marks. Extra bytes are unread  
         * back to the stream, only BOM bytes are skipped.  
         */    
        protected void init() throws IOException {    
            if (isInited)    
                return;    
        
            byte bom[] = new byte[BOM_SIZE];    
            int n, unread;    
            n = internalIn.read(bom, 0, bom.length);
            inputStreamBomBytes = bom;
        
            if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00)    
                    && (bom[2] == (byte) 0xFE) && (bom[3] == (byte) 0xFF)) {    
                encoding = "UTF-32BE";    
                unread = n - 4;    
            } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)    
                    && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) {    
                encoding = "UTF-32LE";    
                unread = n - 4;    
            } else if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB)    
                    && (bom[2] == (byte) 0xBF)) {    
                encoding = "UTF-8";    
                unread = n - 3;    
            } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) {    
                encoding = "UTF-16BE";    
                unread = n - 2;    
            } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) {    
                encoding = "UTF-16LE";    
                unread = n - 2;    
            } else {//没有捕获到的字符集
                //encoding = defaultEnc; //这里暂时不用默认字符集   
                unread = n;    
                //inputStreamBomBytes = new byte[0];
            }    
            // System.out.println("read=" + n + ", unread=" + unread);    
        
            if (unread > 0)    
                internalIn.unread(bom, (n - unread), unread);    
        
            isInited = true;    
        }    
        
        public byte[] getInputStreamBomBytes() {
            return inputStreamBomBytes;
        }
    
    
        public void close() throws IOException {    
            isInited = true;    
            internalIn.close();    
        }    
        
        public int read() throws IOException {    
            isInited = true;    
            return internalIn.read();    
        }
    }



    好了,下面来看看是否OK,我们测试一个文件,用【记事本】打开一个文件,编写一些中文,将文件分别另存为几种字符集,如下图所示:



    通过这种方式保存的文件是有头部的,windows里面也保存了这个标准,但是并不代表,所有的编辑器都必须要写这个头部,因为文件上并没有定义如果不写头部,就不能保存文件,其实所谓的字符集,是我们逻辑上抽象出来的,和文件本身无关,包括这些后缀的.txt|.sql等等,都是人为定义的;

    好,不带头部的,我们后面来讲,若带有头部,我们用下面的代码来看看是否正确(用windows自带的记事本、UE工具另存为是OK的,用EditPlus是不带头部的,这里为了测试,可以用前两种工具来保存):

    我们这里写个组件类,方便其他地方都来调用,假如我们自己定义个叫FileUtils的组件类,里面定义一个方法:getFileStringByInputStream,传入输入流,和是否关闭输入流两个参数(因为有些时候就是希望暂时不关闭,由外部的框架来关闭),再定义一个重载方法,第二个参数不传递,调用第一个方法是,传入的是true(也就是默认情况下我们认为是需要关闭的)。

    代码如下(其中closeStream是一个自己编写的关闭Closeable实现类方法,这里就不多说了):

    public static String getFileStringByInputStream2(InputStream inputStream , boolean isCloseInputStream) 
                  throws IOException {
         if(inputStream.available() < 2) return "";
         try {
              UnicodeInputStream in = newUnicodeInputStream(inputStream);
              String encoding = in.getEncoding();
              int available = inputStream.available();
              byte []bomBytes = in.getInputStreamBomBytes();
              int bomLength = bomBytes.length;
              byte []last = new byte[available + bomLength];
              System.arraycopy(bomBytes , 0 , last , 0 , bomLength);//将头部拷贝进去
              inputStream.read(last , bomBytes.length , available);//抛开头部位置开始读取
              String result = new String(last , encoding);
              if(encoding != null && encoding.startsWith("GB")) {
                 return result;
              }else {
                 return result.substring(1);
              }
          }finally {
              if(isCloseInputStream) closeStream(inputStream);
          }
    }



    此时找了几个文件果然OK,不论改成什么字符集都是OK的,此时欣喜了一把,另一个人给了我一个Editplus的文件悲剧了,然后发现没有头部,用java默认的OuputStream输出文件也不会有头部,除非自己写进去才会有,或者说,如果你将头部乱写成另一种字符集的头部,通过上述方面就直接悲剧了


    但是如果是不带BOM的,这个方法是不行的,因为没有头部,就没法判定,可以这样说,目前没有任何一种编辑器可以再任何情况下保证没有乱码(一会我们来证明下),类似Editplus保存没有头部的文件,为什么记事本、UE、Editplus都可以认识出来呢(注意,这里指绝大部分情况,并非所有情况);

    首先来说下,如果没有头部,只有咋判定字符集,没办法哈,只有一个办法,那就是读取文件字符流,根据字符流和各类字符集的编码进行匹配,来完成字符集的匹配,貌似是OK的,不过字符集之间是存在一个冲突的,若出现冲突,那么这就完蛋了。

    做个实验:

    写一个记事本或EditPlus,打开文件,在文件开始部分,输入两个字“联通”,然后另存为GBK格式,注意,windows下ASNI就是GBK格式的,或者一些默认,就是,此时,你用任何一种编辑器打开都是乱码,如下所示:


    重新打开这个文件,用记事本:


    用Editplus打开:


    用UE打开:


    很悲剧吧,这里仅仅是个例子,不仅仅这个字符,有些其他的字符也有可能,只是正好导致了,如果多写一些汉字(不是从新打开后写),此时会被认出来,因为多一些汉字绝大部分汉字还是没有多少冲突的,例如:联通公司现在表示OK,这是没问题的。


    回到我们的问题,java如何处理,既然没有任何一种东西可以完全将字符集解析清楚,那么,java能处理多少,我们能否像记事本一样,可以解析编码,可以的,有一个框架是基于:mozilla的一个叫:chardet的东西,下载这个包可以到http://sourceforge.net/projects/jchardet/files/ 里面去下载,下载后面有相应的jar包和源码,内部有大量的字符集的处理。


    那么如何使用呢,他需要扫描整个文件(注意,我们这里没考虑超过2G以上的文件)。

    简单例子,在他的包中有个文件叫:HtmlCharsetDetector.java的测试类,有main方法可以运行,这个我大概测试过,大部分文本文件的字符集解析都是OK的,在使用上稍微做了调整而已;它的代码我这就不贴了,这里说下基于这个类和原先基于头部判定的两种方法结合起来的样子;

    首先再写一个基于第三包的处理方法:

    /**
         * 通过CharDet来解析文本内容
         * @param inputStream 输入流
         * @param bomBytes     头部字节,因为取出来后,需要将数据补充回去
                                              因为先判定了头部,所以头部4个字节是传递进来,也需要判定,而inputStream的指针已经指在第四个位置了
         * @param bomLength    头部长度,即使定义为4位,可能由于程序运行,不一定是4位长度
      这里没有使用bomBytes.length直接获取,而是直接从外部传入,主要为了外部通用
         * @param last          后面补充的数据
         * @return              返回解析后的字符串
         * @throws IOException  当输入输出发生异常时,抛出,例如文件未找到等
         */
        private static String processEncodingByCharDet(InputStream inputStream, 
                                                       byte[] bomBytes,
                                                       int bomLength, 
                                                       byte[] last) throws IOException {
            byte []buf = new byte[1024];
            nsDetector det = new nsDetector(nsPSMDetector.ALL);
            final String []findCharset = new String[1];//这里耍了点小聪明,让找到字符集的时候,写到外部变量里面来下,继承下也可以
            det.Init(new nsICharsetDetectionObserver() {
                public void Notify(String charset) {
                    if(CHARSET_CONVERT.containsKey(charset)) {
                        findCharset[0] = CHARSET_CONVERT.get(charset);
                    }
                }
            });
            int len , allLength = bomLength;
            System.arraycopy(bomBytes, 0, last, 0, bomLength);
    
    
            boolean isAscii = det.isAscii(bomBytes , bomLength);
            boolean done = det.DoIt(bomBytes , bomLength , false);
            BufferedInputStream buff = new BufferedInputStream(inputStream);
    
    
            while((len = buff.read(buf , 0 , buf.length)) > 0) {
                System.arraycopy(buf , 0 , last , allLength , len);
                allLength += len;
                if (isAscii) {
                    isAscii = det.isAscii(buf , len);
                }
                if (!isAscii && !done) {
                    done = det.DoIt(buf , len , false);
                }
            }
            det.Done();
            if (isAscii) {//这里采用默认字符集
                return new String(last , Charset.defaultCharset());
            }
            if(findCharset[0] != null) {
                return new String(last , findCharset[0]);
            }
            String encoding = null;
            for(String charset : det.getProbableCharsets()) {//遍历下可能的字符集列表,取到可用的,跳出
                encoding = CHARSET_CONVERT.get(charset);
                if(encoding != null) {
                    break;
                }
            }
            if(encoding == null) encoding = Charset.defaultCharset();//设置为默认值
            return new String(last , encoding);
        }



    CHARSET_CONVERT的定义如下,也就是返回的字符集仅仅是可以被解析的字符集,其余的字符集不考虑,因为有些时候,chardet也不好用:

    private final static Map<String , String> CHARSET_CONVERT = new HashMap<String , String>() {
            {
                put("GB2312" , "GBK");
                put("GBK" , "GBK");
                put("GB18030" , "GB18030");
                put("UTF-16LE" , "UTF-16LE");
                put("UTF-16BE" , "UTF-16BE");
                put("UTF-8" , "UTF-8");
                put("UTF-32BE" , "UTF-32BE");
                put("UTF-32LE" , "UTF-32LE");
            }
        };


    这个方法写好了,我们将原来的那个方法和这个方法进行合并:

       /**
         * 获取文件的内容,包括字符集的过滤
         * @param inputStream    输入流
         * @param isCloseInputStream 是否关闭输入流
         * @throws IOException IO异常
         * @return String 文件中的字符串,获取完的结果
         */
        public static String getFileStringByInputStream(InputStream inputStream , boolean isCloseInputStream) throws IOException {
            if(inputStream.available() < 2) return "";
            UnicodeInputStream in = new UnicodeInputStream(inputStream);
            try {
                String encoding = in.getEncoding();//先获取字符集
                int available = inputStream.available();//看下inputStream一次性还能读取多少(不超过2G文件,就可以认为是剩余多少)
                byte []bomBytes = in.getInputStreamBomBytes();//取出已经读取头部的字节码
                int bomLength = bomBytes.length;//提取头部的长度
                byte []last = new byte[available + bomLength];//定义下总长度
                if(encoding == null) {//如果没有取到字符集,则调用chardet来处理
                    return processEncodingByCharDet(inputStream, bomBytes, bomLength, last);
                }else {//如果获取到字符集,则按照常规处理
                    System.arraycopy(bomBytes , 0 , last , 0 , bomLength);//将头部拷贝进去
                    inputStream.read(last , bomBytes.length , available);//抛开头部位置开始读取
                    String result = new String(last , encoding);
                    if(encoding.startsWith("GB")) {
                        return result;
                    }else {
                        return result.substring(1);
                    }
                }
            }finally {
                if(isCloseInputStream) closeStream(in);
            }
        }



    外部再重载下方法,可以传入是否关闭输入流;

    这样,通过测试,绝大部分文件都是可以被解析的;

    注意,上面有个substring(1)的操作,是因为如果带BOM头部的文件,第一个字符(可能包含2-4个字节),但是转换为字符后就1个,此时需要将他去掉,GBK没有头部。

    展开全文
  • 字符集和字符编码

    千次阅读 2016-06-08 15:20:26
    本文将简述字符集,字符编码的概念。以及在遭遇乱码时的一些常用诊断技巧 背景:字符集和编码无疑是IT菜鸟甚至是各种大神的头痛问题。当遇到纷繁复杂的字符集,各种火星文和乱码时,问题的定位往往变得非常...
    • 转载自:here
      本文将简述字符集,字符编码的概念。以及在遭遇乱码时的一些常用诊断技巧

    背景:字符集和编码无疑是IT菜鸟甚至是各种大神的头痛问题。当遇到纷繁复杂的字符集,各种火星文和乱码时,问题的定位往往变得非常困难。本文就将会从原理方面对字符集和编码做个简单的科普介绍,同时也会介绍一些通用的乱码故障定位的方法以方便读者以后能够更从容的定位相关问题。在正式介绍之前,先做个小申明:如果你希望非常精确的理解各个名词的解释,那么可以查阅wikipedia。本文是博主通过自己理解消化后并转化成易懂浅显的表述后的介绍。


    什么是字符集

    在介绍字符集之前,我们先了解下为什么要有字符集。我们在计算机屏幕上看到的是实体化的文字,而在计算机存储介质中存放的实际是二进制的比特流。那么在这两者之间的转换规则就需要一个统一的标准,否则把我们的U盘插到老板的电脑上,文档就乱码了;小伙伴QQ上传过来的文件,在我们本地打开又乱码了。于是为了实现转换标准,各种字符集标准就出现了。简单的说字符集就规定了某个文字对应的二进制数字存放方式(编码)和某串二进制数值代表了哪个文字(解码)的转换关系。
    那么为什么会有那么多字符集标准呢?这个问题实际非常容易回答。问问自己为什么我们的插头拿到英国就不能用了呢?为什么显示器同时有DVI,VGA,HDMI,DP这么多接口呢?很多规范和标准在最初制定时并不会意识到这将会是以后全球普适的准则,或者处于组织本身利益就想从本质上区别于现有标准。于是,就产生了那么多具有相同效果但又不相互兼容的标准了。
    说了那么多我们来看一个实际例子,下面就是这个字在各种编码下的十六进制和二进制编码结果,怎么样有没有一种很屌的感觉?

    字符集|16进制编码|对应的二进制数据
    |-|-|
    UTF-8|0xE5B18C|1110 0101 1011 0001 1000 1100
    UTF-16|0x5C4C|1011 1000 1001 1000
    GBK|0x8CC5|1000 1100 1100 0101


    什么是字符编码

    字符集只是一个规则集合的名字,对应到真实生活中,字符集就是对某种语言的称呼。例如:英语,汉语,日语。对于一个字符集来说要正确编码转码一个字符需要三个关键元素:字库表(character repertoire)、编码字符集(coded character set)、字符编码(character encoding form)。其中字库表是一个相当于所有可读或者可显示字符的数据库,字库表决定了整个字符集能够展现表示的所有字符的范围。编码字符集,即用一个编码值code point来表示一个字符在字库中的位置。字符编码,将编码字符集和实际存储数值之间的转换关系。一般来说都会直接将code point的值作为编码后的值直接存储。例如在ASCII中A在表中排第65位,而编码后A的数值是0100 0001也即十进制的65的二进制转换结果。
    看到这里,可能很多读者都会有和我当初一样的疑问:字库表编码字符集看来是必不可少的,那既然字库表中的每一个字符都有一个自己的序号,直接把序号作为存储内容就好了。为什么还要多此一举通过字符编码把序号转换成另外一种存储格式呢?其实原因也比较容易理解:统一字库表的目的是为了能够涵盖世界上所有的字符,但实际使用过程中会发现真正用的上的字符相对整个字库表来说比例非常低。例如中文地区的程序几乎不会需要日语字符,而一些英语国家甚至简单的ASCII字库表就能满足基本需求。而如果把每个字符都用字库表中的序号来存储的话,每个字符就需要3个字节(这里以Unicode字库为例),这样对于原本用仅占一个字符的ASCII编码的英语地区国家显然是一个额外成本(存储体积是原来的三倍)。算的直接一些,同样一块硬盘,用ASCII可以存1500篇文章,而用3字节Unicode序号存储只能存500篇。于是就出现了UTF-8这样的变长编码。在UTF-8编码中原本只需要一个字节的ASCII字符,仍然只占一个字节。而像中文及日语这样的复杂字符就需要2个到3个字节来存储。


    UTF-8和Unicode的关系

    看完上面两个概念解释,那么解释UTF-8和Unicode的关系就比较简单了。Unicode就是上文中提到的编码字符集,而UTF-8就是字符编码,即Unicode规则字库的一种实现形式。随着互联网的发展,对同一字库集的要求越来越迫切,Unicode标准也就自然而然的出现。它几乎涵盖了各个国家语言可能出现的符号和文字,并将为他们编号。详见:Unicode on Wikipedia。Unicode的编号从0000开始一直到10FFFF共分为16个Plane,每个Plane中有65536个字符。而UTF-8则只实现了第一个Plane,可见UTF-8虽然是一个当今接受度最广的字符集编码,但是它并没有涵盖整个Unicode的字库,这也造成了它在某些场景下对于特殊字符的处理困难(下文会有提到)。


    UTF-8编码简介

    为了更好的理解后面的实际应用,我们这里简单的介绍下UTF-8的编码实现方法。即UTF-8的物理存储和Unicode序号的转换关系。
    UTF-8编码为变长编码。最小编码单位(code unit)为一个字节。一个字节的前1-3个bit为描述性部分,后面为实际序号部分。

    • 如果一个字节的第一位为0,那么代表当前字符为单字节字符,占用一个字节的空间。0之后的所有部分(7个bit)代表在Unicode中的序号。
    • 如果一个字节以110开头,那么代表当前字符为双字节字符,占用2个字节的空间。110之后的所有部分(5个bit)加上后一个字节的除10外的部分(6个bit)代表在Unicode中的序号。且第二个字节以10开头
    • 如果一个字节以1110开头,那么代表当前字符为三字节字符,占用2个字节的空间。110之后的所有部分(5个bit)加上后两个字节的除10外的部分(12个bit)代表在Unicode中的序号。且第二、第三个字节以10开头
    • 如果一个字节以10开头,那么代表当前字节为多字节字符的第二个字节。10之后的所有部分(6个bit)和之前的部分一同组成在Unicode中的序号。

    具体每个字节的特征可见下表,其中x代表序号部分,把各个字节中的所有x部分拼接在一起就组成了在Unicode字库中的序号

    Byte 1|Byte 2|Byte3
    |-|-|
    0xxx xxxx||
    110x xxxx|10xx xxxx|
    1110 xxxx|10xx xxxx|10xx xxxx

    我们分别看三个从一个字节到三个字节的UTF-8编码例子:

    实际字符|在Unicode字库序号的十六进制|在Unicode字库序号的二进制|UTF-8编码后的二进制|UTF-8编码后的十六进制
    $|0024|010 0100 |0010 0100|24
    ¢|00A2|000 1010 0010|1100 0010 1010 0010|C2 A2
    €|20AC|0010 0000 1010 1100|1110 0010 1000 0010 1010 1100|E2 82 AC

    细心的读者不难从以上的简单介绍中得出以下规律:

    • 3个字节的UTF-8十六进制编码一定是以E开头的
    • 2个字节的UTF-8十六进制编码一定是以CD开头的
    • 1个字节的UTF-8十六进制编码一定是以比8小的数字开头的

    为什么会出现乱码

    乱码也就是英文常说的mojibake(由日语的文字化け音译)。
    简单的说乱码的出现是因为:编码和解码时用了不同或者不兼容的字符集。对应到真实生活中,就好比是一个英国人为了表示祝福在纸上写了bless(编码过程)。而一个法国人拿到了这张纸,由于在法语中bless表示受伤的意思,所以认为他想表达的是受伤(解码过程)。这个就是一个现实生活中的乱码情况。在计算机科学中一样,一个用UTF-8编码后的字符,用GBK去解码。由于两个字符集的字库表不一样,同一个汉字在两个字符表的位置也不同,最终就会出现乱码。
    我们来看一个例子:假设我们用UTF-8编码存储很屌两个字,会有如下转换:

    字符|UTF-8编码后的十六进制
    |-|-|
    很|E5BE88
    屌|E5B18C

    于是我们得到了E5BE88E5B18C这么一串数值。而显示时我们用GBK解码进行展示,通过查表我们获得以下信息:

    两个字节的十六进制数值|GBK解码后对应的字符
    |-|-|
    E5BE|寰
    88E5|堝
    B18C|睂

    解码后我们就得到了寰堝睂这么一个错误的结果,更要命的是连字符个数都变了。


    如何识别乱码的本来想要表达的文字

    要从乱码字符中反解出原来的正确文字需要对各个字符集编码规则有较为深刻的掌握。但是原理很简单,这里用最常见的UTF-8被错误用GBK展示时的乱码为例,来说明具体反解和识别过程。

    第1步 编码

    假设我们在页面上看到寰堝睂这样的乱码,而又得知我们的浏览器当前使用GBK编码。那么第一步我们就能先通过GBK把乱码编码成二进制表达式。当然查表编码效率很低,我们也可以用以下SQL语句直接通过MySQL客户端来做编码工作:
    {% highlight mysql %}
    {% raw %}
    mysql [localhost] {msandbox} > select hex(convert(‘寰堝睂’ using gbk));
    +————————————-+
    | hex(convert(‘寰堝睂’ using gbk)) |
    +————————————-+
    | E5BE88E5B18C |
    +————————————-+
    1 row in set (0.01 sec)
    {% endraw %}
    {% endhighlight %}

    第2步 识别

    现在我们得到了解码后的二进制字符串E5BE88E5B18C。然后我们将它按字节拆开。

    Byte 1|Byte 2|Byte 3|Byte 4|Byte 5|Byte 6
    |-|-|-|-|-|-|
    E5|BE|88|E5|B1|8C

    然后套用之前UTF-8编码介绍章节中总结出的规律,就不难发现这6个字节的数据符合UTF-8编码规则。如果整个数据流都符合这个规则的话,我们就能大胆假设乱码之前的编码字符集是UTF-8

    第3步 解码

    然后我们就能拿着E5BE88E5B18C用UTF-8解码,查看乱码前的文字了。当然我们可以不查表直接通过SQL获得结果:
    {% highlight mysql %}
    {% raw %}
    mysql [localhost] {msandbox} ((none)) > select convert(0xE5BE88E5B18C using utf8);
    +————————————+
    | convert(0xE5BE88E5B18C using utf8) |
    +————————————+
    | 很屌 |
    +————————————+
    1 row in set (0.00 sec)
    {% endraw %}
    {% endhighlight %}

    常见问题处理之Emoji

    所谓Emoji就是一种在Unicode位于\u1F601-\u1F64F区段的字符。这个显然超过了目前常用的UTF-8字符集的编码范围\u0000-\uFFFF。Emoji表情随着IOS的普及和微信的支持越来越常见。下面就是几个常见的Emoji:
    emoji1
    emoji2
    emoji3
    那么Emoji字符表情会对我们平时的开发运维带来什么影响呢?最常见的问题就在于将他存入MySQL数据库的时候。一般来说MySQL数据库的默认字符集都会配置成UTF-8(三字节),而utf8mb4在5.5以后才被支持,也很少会有DBA主动将系统默认字符集改成utf8mb4。那么问题就来了,当我们把一个需要4字节UTF-8编码才能表示的字符存入数据库的时候就会报错:ERROR 1366: Incorrect string value: '\xF0\x9D\x8C\x86' for column 。 如果认真阅读了上面的解释,那么这个报错也就不难看懂了。我们试图将一串Bytes插入到一列中,而这串Bytes的第一个字节是\xF0意味着这是一个四字节的UTF-8编码。但是当MySQL表和列字符集配置为UTF-8的时候是无法存储这样的字符的,所以报了错。
    那么遇到这种情况我们如何解决呢?有两种方式:升级MySQL到5.6或更高版本,并且将表字符集切换至utf8mb4。第二种方法就是在把内容存入到数据库之前做一次过滤,将Emoji字符替换成一段特殊的文字编码,然后再存入数据库中。之后从数据库获取或者前端展示时再将这段特殊文字编码转换成Emoji显示。第二种方法我们假设用-*-1F601-*-来替代4字节的Emoji,那么具体实现python代码可以参见Stackoverflow上的回答

    reference

    [如何配置Python默认字符集]({{ site.url }}/python/python-encoding)
    字符编码笔记:ASCII,Unicode和UTF-8
    Unicode中文编码表
    Emoji Unicode Table
    Every Developer Should Know About The Encoding

    展开全文
  • Java字符集编码问题 URLConnection

    千次阅读 2018-04-18 11:30:58
    字符集问题,用URLConnection来开启http访问获取数据的问题,数据是GBK编码,获取下来成了乱码。原方法:(注释掉的是将数据进行文件存储)public void download(String URLString) { FileOutputStream out = null;...
  • 深入了解java中的编码和字符集

    千次阅读 2017-02-06 12:58:50
    ascii、gbk、utf-8、utf-16叫字符集编码,英文是encoding,例如utf-8和utf-16编码是Unicode字符集的实现,规定了字符在计算机中的具体编码规则,也就是二进制到底是什么样的,在计算机中的意思是,
  • 字符集(Character set)是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集有:ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。 那么为什么会有那么多字符集...
  • Java 字节 字符流 转换

    万次阅读 2015-05-10 13:55:16
    我们知道Java中的分为字符流和字节,其中字符流主要针对字符文本进行处理,而字节处理范围更为广泛,毕竟图片、电影等只要是文件都是以二进制的形式存在的,而不是字符字符流: FileReader FileWriter。 ...
  • 下面这段代码使用了字节按照指定编码获取字符串,可能很多人也使用它,其实呢这段代码是错误的,如果使用的时候感觉一切正常的话,那只能说你运气挺好。 private String inputStreamToString(InputStream i
  • 在介绍字符集之前,我们先了解下为什么要有字符集。我们在计算机屏幕上看到的是实体化的文字,而在计算机存储介质中存放的实际是二进制的比特。那么在这两者之间的转换规则就需要一个统一的标准,否则把我们的U盘...
  • C# 字符集编码简解

    万次阅读 多人点赞 2012-09-02 21:44:08
    GB2312 字符集 GB2312又称为GB2312-80字符集,全称为《信息交换用汉字编码字符集·基本集》,由原中国国家标准总局发布,1981年5月1日实施。GB2312是中国国家标准的简体中文字符集。它所收录的汉字已经覆盖99.75%...
  • 对于字符集编码来说,很多人都不太理解,一直是一个老大难问题。 下面这个例子采用的是NIO形式读取文件,不是IO哦 下面先写一个例子,将一个文件拷贝到另外一个文件中: 目的是将NioTest13_In.txt文件内容...
  • java字符流

    千次阅读 2016-07-21 14:25:47
    网上有很多地方说inputStreamReader和outStreamWriter、BufferedReader和BufferedWriter都是字符流。不过也有地方说inputStreamReader和outStreamWriter只是转换,实现字节字符流的转换。 而在我看来,两种...
  • unicode字符集与编码

    千次阅读 2019-05-25 19:18:47
    字符编码 个人理解 一个字符需要保存到计算机中,计算机只能识别0、1。这就需要一个规则来表述0、1数据与字符之间的关系。 ASCII码 表述 1个字节 0、1数据与...获取到一个文件,需要知道文件的编码方式,如果这个...
  • JAVA读写文件指定字符集

    万次阅读 2008-07-20 18:34:00
    JAVA读取和写入文件时如果不指定字符集,那么都是采用操作系统默认的字符集.当我们在Windows平台上创建一个文件包含有中文,然后在Linux 平台下用JAVA读出来,那么很有可能会出现乱码.这是因为:在Windows中文版平台下,...
  • java中字符集的问题

    千次阅读 2012-08-10 18:03:46
    1、JVM中单个字符占用的字节长度跟编码方式有关,而默认...因此中文平台(中文平台默认字符集编码GBK)下一个中文字符占2个字节,而英文平台(英文平台默认字符集编码Cp1252(类似于ISO-8859-1))。 3、getBytes()、getBy
  • JAVA字符集

    万次阅读 2006-08-29 17:28:00
    另外,如前所述,使用GET方法提交的信息不支持request.setCharacterEncoding(),但可以通过tomcat的配置文件指定字符集,在tomcat的server.xml文件中,形如: ... URIEncoding="GBK"/>。这种方法将统一设置所有...
  • NSString在不同字符集下的ASCII码

    千次阅读 2013-07-11 16:52:34
    1、在字符集编码为NSUTF8String...在不同的字符集下,获取的每一个字符的字节数已经不一样的,UTF8下汉字三个字节编码,GBK下是两个。这点没有疑问。 有疑问的是,为什么获取的每一个字符的ASCII编码都是一样的。
  • 分析了http协议下,java平台字符集原理,导致中文乱码原因和解决方案。 本文部分内容摘自网络,版权归原作者所有。
  • Kubernetes是通过操作系统LANG环境变量来获取要显示的语言字符集的,将来会考虑通过参数或者配置文件来获取要显示的语言字符集。在Kubernetes1.7版本中通过i18n有限的增加了三种语言字符集,其中包括繁体中文、简体...
  • 使用ICU进行字符集探测 文档译稿

    千次阅读 2010-02-06 13:24:00
    使用ICU进行字符集探测文档译稿原文http://userguide.icu-project.org/conversion/detectionCharacter Set Detection 字符集探测Overview 概述 字符集探测是对未知格式的字符数据进行确定字符集或者编码的过程。...
  • 要了解乱码的症结,我们就得从字符集和字符编码说起,先来看看它们到底是什么: 1:字符集:是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。 2:...
  • 如何使用Java代码获取文件、文件字符串的编码方式
  • python编码类型转换及字符集探讨

    千次阅读 2013-12-15 22:23:54
    一直遇到python编码的问题。常常抓取的网页数据信息,邮件收发信息,涉及到文字处理的,...1、常见字符集 ASCII及其扩展字符集 作用:表语英语及西欧语言。 位数:ASCII是用7位表示的,能表示128个字符;其扩展使用8位
  • 举例说明字符集:ASCII字符集、Unicode字符集。 编码 编码:是一套法则,使用该法则能够对字符集(如字母表或音节表),与数字集合(如号码或电脉冲)进行配对。即在字符集与数字集合之间建立一一对应关系。例如...
  • 字符集和字符编码的概念: 1.字符集:是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。 2.字符编码方式:是把字符集中的字符编码为指定集合中某一...
  • 字符集之 代码书写和底层探索

    千次阅读 2012-04-14 13:14:47
    1.工程配置为多字节字符集时,工程中代码书写用宽字节字符类型和函数的情况是基本无实际用途的,因为我用了MFC等三方库,界面显示到底是由它负责的,在机子配置是非本地语言的情况下界面显示还是乱码,原因估计是...
  • 当你从一个未知编码的文件中,通过输入读取内容时,假如是乱码怎么办?  如果你不知道字符串的编码,可能你只能靠尝试常用的编码的方式,将字符串处理成正确编码格式。 举个例子:“#鍑借喘鍚岃櫣娆惧紡f” 这...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 125,015
精华内容 50,006
关键字:

获取流的字符集