-
2021-06-23 11:52:05
总第99篇
本文主要总结一个在
C++
项目跨语言开发过程中遇到的一个乱码错误提示信息,将其转码成中文并提供解决方法,以供后来者参考与学习。1.问题的产生
最近的工作是为
SketchUp
开发C++
扩展插件, 插件的功能用C++
语言实现并制作成.so
文件。在VS2019
中,项目生成后配置调试参数
及调试命令
,按F5
运行时即可启动SketchUp
进行联合调试。今天在调试一个
.so
文件时,SketchUp
中的Ruby
控制台提示了如下图所示的错误:很显然,这种错误的提示是使用了其它的编码方式,我们无法识别具体错误的类型,如何将其转换为中文的
gbk
编码,让我们更快地锁定错误呢?2.问题的澄清
将上图中的错误提示信息分解为如下形式:
\xd5\xd2\xb2\xbb\xb5\xbd\xd6\xb8\xb6\xa8\xb5\xc4\xc4\xa3\xbf\xe
更多相关内容 -
愿编程不再乱码(含Qt)-根因深究
2021-10-08 23:13:17简 述: 本篇重点讲述如下: 乱码知识所涉及的大量知识点 ... 本文仅适合想要深究和学习乱码的原因、以及了解编码等知识的读者 ,最后理解透彻均后,欲自行解决做手中实际的乱码问题;若你仅想找到一两行代码,临简 述: 本篇重点讲述如下:
- 乱码知识所涉及的大量知识点
- MinGW/MSVC 对于
"中文123"
的 ANSI 字符串的字符串的默认编码理解 - MSVC 中一些强制转换为 GBK/UTF-8 的大坑说明
- 使用代码片对上面理论的验证
- 完成心愿:以一种优雅的方式在 MSVC 上使用 UTF-8 和 Qt 跨平台不乱码;同样源码亦可使用 WinGW 编译不乱码
本文仅适合想要深究和学习乱码的原因、以及了解编码等知识的读者 ,最后理解透彻均后,欲自行解决做手中实际的乱码问题;若你仅想找到一两行代码,临时解决当前所囧境,本文可能不适合你。
文章目录
本文初发于 “偕臧的小站”,同步转载于此。
编程环境
本文的所有代码测试环境,均为 💻:
win10 21H1
📎Visual Studio 2017
📎Qt Creator 4.15.0
背景
编程早晚皆会遇乱码,经常一些遇到"拿来主义",经过 C + V,不假思索看效果,或行或不行。忽觉,不应如此,细一缕分析之,看其缘由,解惑之,记载于此。
emmm,若是没遇到过乱码,建议可直接关闭本文;顺便我由衷想说一句:
基础共识
在讲解编程乱码之前,先假定读者和我已有基本的 "字符,字节,字符串和编码" 理解共识,若是理解不够详细,可自行前往字符,字节和编码达成共识。
但其中一部分依旧强调一遍:
- ANSI 编码 表示本地化的一种编码,不同国家、地区的其编码方式不同,且之间互相不兼容。也被称之为 多字节编码 :每个字符使用一个字节或多个字节(并非是固定的 2 字节)。
- 字符 是一个抽象的符号,人们达成的一约定共识。如看到 ‘$’, ‘¥’ 即知其含义。
- 字节 是计算机中的一段存储空间,是一个 8 位的二进制数。
- ANSI 字符串 是形如
"中文123"
这种格式的多个字符,其共占 7 字节,共 5 个字符。
乱码种类
在这里,我将乱码可以分为两类,或许其“称呼”不够准确(不必纠结),但倘若读者由其文字自行理解这两种的差异,和我达成共识了, 即为目的达到了~~(是语言的局限性??)~~。
⓵式 文件读取形式的乱码: A 软件编写了一个 test.txt 文件,里面包含中英文和符号。然后在本机使用 B 软件直接打开,发现乱码了;亦或是将此文件,发送另外一个外国的网友,然后同样使用 A 软件打开,却发现也乱码了。(此处 “发现乱码了” 含义为人看不懂,出现方块符号、或者古生僻汉字、菱形?等)
⓶式 含编程形式的乱码: 在 IDE 中,输出一个 “ANSI 字符串” 或者将其保存到字符串对象 string 、QString 等中,再终端输出,发现也乱码了。
其中⓵式的非常容易解决,其仅和**“源码字符集”** 有关,最常见的解决方式为换一个编码格式解析即可(过于简单不再讨论)。而⓶式的则和**“执行字符集”** 相关,比较复杂、涉及的知识点也比较多,也是工程师常遇到却难以解决、也是余文的篇幅内容。其差异见图示:
分析两种乱码
对于⓶式的乱码,一共涉及到如下环节(按顺序),如果有一个环节出现了问题,则会造成最终的终端打印出现乱码。
以文本 “我是汉字奇” 为例:
- 确定本机的字符编码
- 在 .cpp 中, 写入
我是汉字奇
的*“ANSI字符串”*时,按下保存时,选择的编码格式为? - 将此*“ANSI字符串”*当参数,传递给 QString 时候,其字符编码为?
- IDE 编译 .cpp 时候,其执行字符集为?将其拷贝到内存中时候为?
- 输出到终端的时候,终端的字符集为?
补充说明(巨坑):
-
MSVC 的编码字符集和执行字符集都默认为 GBK;而 QtCretor 编码字符集和执行字符集都默认为 UTF-8。
-
MSVC 执行编译时候,发现近仅只能够将 “UFT-8 带 BOM” 格式的文件正确识别。而不带 BOM 的 UTF-8 实际也是被识别为 GBK 格式。
-
MSVC 在编译时,无论 .cpp 文件源码字符集是
UTF-8
、UTF-8 BOM
、GBK
中的哪一种;只要没有声明为执行码字符集为 UFT-8,则最终在内存中,都会被强制转换 GBK 处理;若一旦声明,则也会被强制转换为 UTF-8 格式 。 -
// 若想声明执行字符集为 UFT-8,添加如下 #pragma execution_character_set("utf-8")
-
若测试的字符串
"xxxxxxx"
为偶数,恰好会有“错错得对”巧合;故特地选择我是汉字奇
这奇数个的中文来测试 -
win10 终端默认的编码是 GBK,有时候还是很坑
-
字符串二进制的表示形式不需要编译,直接拷贝到执行程序的二进制中。
涉及的知识点
由上面的分析可以,牵涉的部分知识点大致包含如下;
- 源码字符集 和 执行字符集
- 字符编码 ANSI,GBK,UTF-8,UTF-16,Latin-1
- 统一码带 BOM 和不带区别?
- 代码页,本地编码,ANSI 编码
- MinGW/MSVC 中默认的编码
- MSVC 的特殊情况(见分析的补充说明)
- Qt/C++ 编码转换使用
- QString、QByteArrary、QChar、string、char *、char []、char
下面逐一解释其内容,内容较多、望君耐心。谁让历史的积累和包袱有这么多呢?已将关联不大部分,一笔带过。
源码字符集 和 执行字符集
名称 解释 源码字符集(the source character set) 源码文件是使用何种编码保存的 执行字符集(the execution character set) 可执行程序内保存的是何种编码(程序执行时内存中字符串编码) C++98 的问题: 既没有规定源码字符集,也没有规定执行字符集。 可参见【转】源码字符集(the source character set) 与 执行字符集(the execution character set)。
字符集/编码/ASCII/ANSI/UNICODE
按照惯例,人们认为字符集 和字符编码 是同义词,因为使用同样的标准来定义提供什么字符并且这些字符如何编码到一系列的代码单元(通常一个字符一个单元)。由于历史的原因,MIME和使用这种编码的系统使用术语字符集 来表示用于将一组字符编码成一系列八位字节数据的整个系统。
字符集(即 字符编码): 被收纳进入标准的 字符和符号的集合。
编码: 规定“字符集”中具体的某一字符存储的方式(字节数、哪些字节)。
但通常所说的 “字符集” 、 “编码” 与 “GB2312, GBK, JIS, Big5” 常有混用,应结合上下文理解到底说的哪一个含义。如 notepad++ 中集中常见的编码;
其分类为如下
分类 编码标准 单字节字符编码 ISO-8859-1,ASCII ANSI 编码(多字节) GB2312(简体中文),BIG5(繁体中文),Shift_JIS(日本) UNICODE 编码 UTF-8,UTF-8-BOM,UTF-16(UCS-2 Big、UCS-2 Little)
ASCII :只支持基本的拉丁字符的字符编码
ISO/IEC 8859 :在 ASCII 基础上加上一些扩展字符,是 15 种字符集。Latin-1 是其中之一。
不论是 ASCII 的 7 位的编码,还是后期演化出来的 ISO/IEC 8859 的 8 位的编码,都还是用单个字节就可以表示一个字符,叫做单字节编码。各种单字节编码之间的关系,可以用下面图表来解释:
Unicode :只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。它的实现方式有如下:
- UTF-8 是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
- UTF-16 用二个字节存储一个字符。
- UTF32 用四个字节存储一个字符。
大端和小端(字节序)
大端(Big Endian) 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节);
小端(Little Endian) 则相反,它认为第一个字节是最低位字节(按照从低地址到高地址的顺序存放据的低位字节到高位字节)。
例子: 如 0x1234abcd 写入到以 0x0000 开始的内存中,则 Little endian 和 Big endian 模式的存放结果如下:
地址 0x0000 0x0001 0x0002 0x0003
big-endian 0x12 0x34 0xab 0xcd
little-endian 0xcd 0xab 0x34 0x12
UTF-8 带 BOM 与不带区别
BOM 就是一个标记,用于放在数据最开始的几个预定的特殊符号,并无特殊的含义。研究一通,最后发现就是本段第一行话。南墙在 UTF-8与UTF-8 BOM && 关于UTF-8的BOM:“EF BB BF”。
BOM Encoding EF BB BF UTF-8 FE FF UTF-16 (big-endian) FF FE UTF-16 (little-endian) 00 00 FE FF UTF-32 (big-endian) FF FE 00 00 UTF-32 (little-endian)
代码页,本地编码,ANSI编码
简单理解:仅在 Windows 系统中才有代码页面,在终端
chcp
可查看。一个代码页的数字,对应这一个字符编码。而 ANSI编码 就是使用的本机器默认的字符编码,本机的简体中文中为 GB2312 。
本地编码 :当前Windows中的二进制的值,用何种编码去解析,然后显示出对应的该编码中的字符。通常是指 ANSI 编码。
ANSI 编码 :使用2个字节(通常使用 0x80~0xFF 范围的2个字节来表示1个字符)来代表一个字符的各种汉字延伸编码方式。不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。但是不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。
- 简体中文系统:ANSI 编码代表 GB2312 编码
- 繁体中文系统:ANSI 编码代表 BIG 编码
- 日文操作系统:ANSI 编码代表 JIS 编码
MinGW/MSVC 中默认的编码
这个里面属实有大坑,如下。
-
MSVC 的编码字符集和执行字符集都默认为 GBK;而 QtCretor 编码字符集和执行字符集都默认为 UTF-8。
-
MSVC 执行编译时候,发现近仅只能够将 “UFT-8 带 BOM” 格式的文件正确识别。而不带 BOM 的 UTF-8 实际也是被识别为 GBK 格式。
-
MSVC 在编译时,无论 .cpp 文件源码字符集是
UTF-8
、UTF-8 BOM
、GBK
中的哪一种;只要没有声明为执行码字符集为 UFT-8,则最终在内存中,都会被强制转换 GBK 处理;若一旦声明,则也都会被强制转换为 UTF-8 格式 。// 若想声明执行字符集为 UFT-8,添加如下 #pragma execution_character_set("utf-8")
-
若测试的字符串
"xxxxxxx"
为偶数,恰好会有“错错得对”巧合;故特地选择我是汉字奇
这奇数个的中文来测试 -
win10 终端默认的编码是 GBK,有时候还是很坑
-
字符串二进制的表示形式不需要编译,直接拷贝到执行程序的二进制中。
C++/Qt 中字符串和编码
开发者自然重点关于 Qt 和 C++ 的字符串,以及涉及到的有关函数,以及里面内部的存储方式。
QString
QString stores a string of 16-bit QChars, where each QChar corresponds to one UTF-16 code unit. (Unicode characters with code values above 65535 are stored using surrogate pairs, i.e., two consecutive QChars.)
文档解释很清楚:QString 内部是以 16 位的 QChar 来存储(Unicode 的一种,但不是 utf-8)。
QByteArray
QByteArray can be used to store both raw bytes (including '\0’s) and traditional 8-bit ‘\0’-terminated strings. Using QByteArray is much more convenient than using
const char *
.QByteArray 既可以用来存储原始的字节,包括
'\0'
,也可以用来存储传统的 8-bit 的以'\0'
结尾的字符串。使用QByteArray比使用普通的const char* 更方便。
QChar
In Qt, Unicode characters are 16-bit entities without any markup or structure. This class represents such an entity. It is lightweight, so it can be used everywhere. Most compilers treat it like an
unsigned short
.在 Qt 中,Unicode 字符是没有任何标记或结构的 16 位实体。 这个类代表了这样一个实体。它是轻量级的,所以它可以被到处使用。大多数编译器把它当作一个 unsigned short。
转入函数 转出函数 描述 fromLocal8Bit toLocal8Bit 与操作系统及本地化语言相关,Linux 一般是 UTF-8 字符串,Windows 一般是 ANSI 多字节编码字符串。 fromUtf8 toUtf8 与 UTF-8 编码的字符串相互转换。 fromUtf16 utf16 和 unicode 与 UTF-16(UCS2)编码的字符串互相转换,utf16 函数与 unicode 函数功能一样, 注意没有 to 前缀,因为 QString 运行时的内码就是 UTF-16,字符的双字节采用主机字节序。 fromUcs4 toUcs4 与 UTF-32(UCS4)编码的字符串互相转换,一个字符用四个字节编码,占空间多,应用较少。 fromStdString toStdString 与 std::string 对象互相转换,因为 C++11 规定标准字符串 std::string 使用 UTF-8 编码,这对函数功能与上面 **Utf8 转码函数相同。 fromStdWString toStdWString 与 std::wstring 对象相互转换,在 Linux 系统里宽字符是四字节的 UTF-32,在 Windows 系统里宽字符是两字节的 UTF-16。因为不同平台有歧义,不建议使用。 fromCFString fromNSString toCFString toNSString 仅存在于苹果 Mac OS X 和 iOS 系统。 QTextCodec:仅支持在非 Unicode 格式和 Unicode 之间进行转换。不能不同的非 Unicode 之间直接转换(如: Shift_JIS 和 GBK 之间不可直接转换、必须使用 Unicode 中转一次)
C++ 使用的字符串
在 C++ 中,以前通常使用 char 表示单字节的字符,使用 wchar_t 表示宽字符,对国际码提供一定程度的支持。 char * 字符串有专门的封装类 std::string 来处理,标准输入输出流是 std::cin 和 std::cout 。对于 wchar_t * 字符串,其封装类是 std::wstring,标准输入输出流是 wcin 和 wcout。
虽然规定了宽字符,但是没有明确一个宽字符是占用几个字节,Windows 系统里的宽字符是两个字节,就是 UTF-16;而 Unix/Linux 系统里为了更全面的国际码支持,其宽字符是四个字节,即 UTF-32 编码。这为程序的跨平台带来一定的混乱,除了 Windows 程序开发常用 wchar_t* 字符串表示 UTF-16 ,其他情况下 wchar_t* 都用得比较少。
MFC 一般用自家的 TCHAR 和 CString 类支持国际化,当没有定义 _UNICODE 宏时,TCHAR = char,当定义了 _UNICODE宏 时,TCHAR = wchar_t,CString 内部也是类似的。Qt 则用 QChar 和 QString 类(内部恒定为 UTF-16),一般的图形开发库都用自家的字符串类库。
在新标准 C++11 中,对国际码的支持做了明确的规定:
- char * 对应 UTF-8 编码字符串(代码表示如 u8"多种文字"),封装类为 std::string;
- 新增 char16_t * 对应 UTF-16 编码字符串(代码表示如 u"多种文字"),封装类为 std::u16string ;
- 新增 char32_t * 对应 UTF-32 编码字符串(代码表示如 U"多种文字"),封装类为 std::u32string 。
因为 Qt 有封装好的 QString,所以不太需要这些新增的字符串格式。
char *
- 如果是“窄字符/字符串”(以char为单位),那么不同的编译器可能不一样。以 VC++ 为例,它是由系统代码页决定的,比如在中文 windows 系统下就采用 GBK 编码。(算是 ⓶式的乱码的最开始原因)
- 如果字符/字符串前有指定编码方式,那没什么好说的了,就采用指定的编码方式,如下:
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后面接2个16进制数字,可表示一个窄字符char,多个\x连起来可表示一个utf-8字符,如"\xE4\xBD\xA0" //L'\u1234' : \u后面接4个16进制数字,可表示一个utf-16宽字符 //U'\U12345678' : \U后面接8个16进制数字,可表示一个Utf-32
char []
通常情况下和可以
char []
和char *
进行混用,一个为形参,另一个为实参。不同点为,详细可见 【C/C++】对char* 和 char[]区别的一些理解:
- char*是变量,值可以改变, char[]是常量,值不能改变。
- char[]对应的内存区域总是可写,char*指向的区域有时可写,有时只读
- char * 和char[]的初始化操作有着根本区别(指向常量区和赋值变量的栈区)
string
typedef basic_string string;
String class
Strings are objects that represent sequences of characters.
The standard
string
class provides support for such objects with an interface similar to that of a standard container of bytes, but adding features specifically designed to operate with strings of single-byte characters.The
string
class is an instantiation of the basic_string class template that useschar
(i.e., bytes) as its character type, with its default char_traits and allocator types (see basic_string for more info on the template).Note that this class handles bytes independently of the encoding used: If used to handle sequences of multi-byte or variable-length characters (such as UTF-8), all members of this class (such as length or size), as well as its iterators, will still operate in terms of bytes (not actual encoded characters).
字符串类是 basic_string 类模板的实例,它使用 char(即字节)作为其字符类型,并具有默认的char_traits 和分配器类型(关于模板的更多信息请参见 basic_string )。
请注意,该类处理字节的方式与使用的编码无关。如果用于处理多字节或可变长度的字符序列(如 UTF-8),这个类的所有成员(如 length 或 size ),以及它的迭代器,仍将以字节为单位进行操作(而不是实际编码的字符)。
see: https://www.cplusplus.com/reference/string/string
char
char - 能在目标系统上最有效地处理的字符表示的类型(拥有与 signed char 或 unsigned char 之一相同的表示和对齐,但始终是独立的类型)。多字节字符串用此类型表示编码单元。对于每个范围 [0, 255] 中的 unsigned char 类型值,将该值转换成 char 再转换回 unsigned char 产生原值。 (C++11 起) char 的符号性取决于编译器和目标平台: ARM 和 PowerPC 的默认设置常为无符号,而 x86 与 x64 的默认设置常为有符号。
wchar_t - 宽字符表示的类型(见宽字符串)。要求大到足以表示任何受支持的字符编码位点(支持 Unicode 的系统上为 32 位。值得注意的例外是 Windows,其中 wchar_t 为 16 位并保有 UTF-16 编码单元)。它与上述整数类型之一具有相同的大小、符号性和对齐,但它是独立的类型。
see: https://en.cppreference.com/w/cpp/language/types
代码验证
光说不练可不行,故自行验证上面理论的代码片如下;
#include <iostream> #include <QDebug> using namespace std; //#pragma execution_character_set("utf-8") int main() { const char * cc = "\xce\xd2\xca\xc7\xba\xba\xd7\xd6\xc6\xe6"; // GBK const char * cc1 = "\xe6\x88\x91\xe6\x98\xaf\xe6\xb1\x89\xe5\xad\x97\xe5\xa5\x87"; // UTF-8 const char * cc2 = "我是汉字奇"; // 是 10 或 15 字节,但一定是 5 个字符 cout << "cout ==> cc: " << &cc << " " << cc << endl; cout << "cout ==> cc1: " << &cc1 << " " << cc1 << endl; cout << "cout ==> cc2: " << &cc2 << " " << cc2 << endl; qDebug() << "qDebug ==> cc: " << &cc << " " << cc; qDebug() << "qDebug ==> cc1: " << &cc1 << " " << cc1; qDebug() << "qDebug ==> cc2: " << &cc2 << " " << cc2; return 0; }
将上面代码分别在 VS2017 和 QtCreator 中验证;(取消)注释
//#pragma execution_character_set("utf-8")
来验证;最后测试的验证结果如图 https://kdocs.cn/l/slqOBPQmfajc。
优雅在 Win 上使用 UTF-8 + Qt 跨平台
最初的愿望和其简单,只不过是想使用一套代码,既可以使用 MSVC + Qt + UTF-8 编译运行不乱码;也可以在 Linux + gcc + UTF-8 也不乱码。
综上的解决方案为同运行一下即可:
-
在 CMakeLists.txt 中添加如下代码
# 此处配合 VMSVC 的 UTF8-BOM 插件,达到跨平台 if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") message("---using Clang---") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") message("---using GCC---") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") message("---using Intel C++---") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") message("---sing Visual Studio C++---") add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>") add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>") endif()
-
Visual Studio 中开发时候,所有 .h .cpp 文件都使用
UTF-8-BOM
格式,可以安装ForceUTF8(withBOM)
扩展
感觉这样子使用 utf-8 跨平台清爽了很多。 对于网上的添加
//#pragma execution_character_set("utf-8")
方式,则需要在每一个 .h/.cpp 中都加上这几行,相比之下只用在 cmake 中添加两行,则是优雅了很多。#if _MSC_VER >= 1600 #pragma execution_character_set("utf-8") #endif
总结
关于使用 Visual Studio、Qt Crator 中容易出现的字符乱码问题;一般可重如下三个方面入手:⑴文件编码、⑵代码编码、⑶输出结果显示的编码。我们只要以此来检查这三部分,就可以找到乱码的原因,结合上面的每一个知识点的理解,即可更正。毕竟乱码的问题是由编码和解码方式不对引起的。
希望本篇能够协助读者彻底理解乱码原因后,最后均能可自行解决自己平台所对应的实际乱码问题,最终授人以渔。最后,若没啥疑问和问题的话?那我就要去准备喝汤了~~
回顾本文一些重点 key:
- 形如
"中文123"
这种格式的 ANSI 字符串,其在不同编码下所占字节和字符个数? - 不同系统(默认的编码)对
"中文123"
字符串是如何处理的? - MSVC 的一些大坑、以及强制转换 GBK/UTF-8
- 终端的编码是否会影响输出效果?
参考
-
如何用EditPlus软件进行简单的编程和预览检查?
2021-01-05 17:55:55我们在工作中有时会需要用到大批量...接下来小编教大家如何用EditPlus软件进行简单的编程和预览检查? 1、使用EditPlus时,在新建文本里面可以选择普通TXT格式和HTML网页编辑格式。假如你选择了HTML格式,打开就是编程我们在工作中有时会需要用到大批量的修改,添加,替换数据。一个个的修改真的很浪费时间和精力。由此小编就给大家分享一款我经常使用的文档编辑软件–EditPlus。
EditPlus可以可处理文本、HTML,各种编码替换、检查十分醒目。虽然是国外的软件,不过它有中文版的绿色安装软件,分为电脑32位和64位,简单又实用。接下来小编教大家如何用EditPlus软件进行简单的编程和预览检查?1、使用EditPlus时,在新建文本里面可以选择普通TXT格式和HTML网页编辑格式。假如你选择了HTML格式,打开就是编程页面了。
2、我们编完程序还可以直接在浏览器中显示页面。编程成果一目了然。
3、设置浏览器也很简单。 工具–首选项–点击“ 工具选项”,调用其他浏览器。设置你最常用的浏览器就可以了。
有时候你编写好程序后进行浏览预览,会发现汉字出现乱码,别着急,这是因为你编码没有设置好。
4、我们 在 文档–文本编码–转换文本编码–选择ANSI ,再次打开浏览器,你就会发现,汉字能正常显示了。
以上EditPlus操作教程分享,你学会了吗?如果你也想用EditPlus进行文档编辑,可以在安卓软件网站zbhcgm.cn下载editplus中文版使用哦! -
python2中文乱码
2021-12-03 23:19:08python2中的中文乱码情况,本文将从一下四种情况进行展开。...2.在python中,对于任何Unicode类型编码的字符,打印时会自动根据环境编码转为特定编码后再显示。 接下来,看看字符在python代码中是如何被编码的。在不python2中的中文乱码情况,本文将从一下四种情况进行展开。
下面两句话是本文的重点,文中的内容都是围绕下面两句话展开的
1.乱码的本质是字符的编码格式与显示字符的环境编码格式不一致引起的。这句话告诉我们要解决乱码问题,我们需要知道两个信息,一个是字符本身是什么编码,另一个就是显示字符的环境编码是什么,两者必须一致,才能显示出正确的内容。
2.在python中,对于任何Unicode类型编码的字符,打印时会自动根据环境编码转为特定编码后再显示。
接下来,看看字符在python代码中是如何被编码的。在不同的python版本中,字符编码的方式不一样。本文主要说的是python2版本。
乱码情况1
python2默认使用ASCII来编码代码的,如果代码中出现中文,那么就必须在py文件的开头注明支持中文的编码格式,如果没有声明,python2就会使用默认的ASCII编码来识别中文,就会报错。
s = "中文"
E:\PycharmProjects\LEDdisplay2\venv\Scripts\python.exe E:/PycharmProjects/LEDdisplay2/1.py File "E:/PycharmProjects/LEDdisplay2/1.py", line 1 SyntaxError: Non-ASCII character '\xe4' in file E:/PycharmProjects/LEDdisplay2/1.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details Process finished with exit code 1
上述报错翻译过来就是,在1.py文件的第一行有非ASCII字符“\e4”,而且没有声明编码。
如果我们设置编辑器pycharm此时的环境编码是utf-8的话,用软件查看1.py文件的十六进制,可以看到“中文”存储的是\xe4\xb8\xad\xe6\x96\x87。(utf-8存储文件一个字符需要三个字节表示,可以看到“中文”两个字符是六个字节)
使用nodepad++查看十六进制
python2默认编码格式ASCII编码是不认识“\xe4”的,无法识别“中文”,所以会报错。所以,需要在py文件的开头加上 # encoding:utf-8 声明脚本的编码方式,则python就可以识别代码中的汉字字符串,并按照声明的字符编码格式来进行编码。补充:
代码查看python环境的默认编码
代码查看字符串的十六进制# encoding:utf-8 import sys s = "中文" print(sys.getdefaultencoding()) print (repr(s))
E:\PycharmProjects\LEDdisplay2\venv\Scripts\python.exe E:/PycharmProjects/LEDdisplay2/1.py ascii '\xe4\xb8\xad\xe6\x96\x87' Process finished with exit code 0
乱码情况2
如果我们在py文件开头声明脚本的编码格式为utf-8,设置编辑器pycharm的环境编码为GBK,那么,当我们打印中文时,会出现什么情况呢?答:还是乱码# coding=utf-8 s = "中文" print(s)
E:\PycharmProjects\LEDdisplay2\venv\Scripts\python.exe E:/PycharmProjects/LEDdisplay2/1.py 涓枃 Process finished with exit code 0
pycharm编码设置:
原因是,上述代码中s变量的编码是utf-8的,而我们运行脚本的编辑器pycharm设置的环境编码却是GBK,两者编码方式不一致,所以必定会出现乱码。
解决方法有以下几种:
(这几种方法是互斥的,目的是为了保证文件开头声明的编码格式和pycharm编辑器设置的环境编码格式一致)
1.可以修改编辑器pycharm的环境编码为UTF-8
2.可以修改py文件开头声明脚本的编码方式为GBK
3.在变量s前加一个u,将其强制转换为Unicode编码(前面已经说过了,对于Unicode编码的字符,python打印时会自动根据环境编码转为特定编码后再显示)
4.通过decode和encode函数。使用decode方法可以将字符串按照指定的格式解码成Unicode,需要注意的是,我们对所有的非Unicode类型的字符只能进行decode操作,不能进行encode操作,对Unicode类型的字符只能进行encode操作,不能进行decode操作。
# encoding:utf-8 s = "中文" y1 = s.decode("utf-8") # s.decode("utf-8")这句话跟u“中文”效果是等价的 y2 = s.decode("utf-8").encode("gbk") print(y1) print(y2)
E:\PycharmProjects\LEDdisplay2\venv\Scripts\python.exe E:/PycharmProjects/LEDdisplay2/1.py 中文 中文 Process finished with exit code 0
注意:encode和decode的时候都是需要指定编码的。
在 Python 中编码是可以互相转换的,但是不同编码之间不能直接转换,需要通过Unicode字符集中间过渡下。比如从utf-8转换为gbk,需要先将utf-8格式解码成Unicode,再编码成gbk格式。
encode的正常使用:对Unicode类型进行encode,得到字节串str类型。也即是Unicode-> encode(根据指定编码) -> str。
decode的正常使用:对str类型进行decode,得到Unicode类型。也即是str -> decode(根据指定编码) -> Unicode。
encode的不正常使用:对str类型进行encode,因为encode需要的是Unicode类型,这个时候python会用默认编码decode成Unicode类型,再用你给出编码进行encode。(注意这里默认编码不是开头的encoding,而是ASCII编码)
decode的不正常使用:对Unicode类型进行decode,python会用默认的系统编码encode成str类型,再用你给出的编码进行decode。
另外,需要注意的是,用什么字符编码对Unicode进行编码(编码为str类型),就要用对应的字符编码对str类型进行解码(解码为Unicode类型)。
举个不正常使用的例子:
# encoding:utf-8 import sys s = "中文" print(sys.getdefaultencoding()) y3 = s.encode("utf-8") print(y3)
E:\PycharmProjects\LEDdisplay2\venv\Scripts\python.exe E:/PycharmProjects/LEDdisplay2/1.py ascii Traceback (most recent call last): File "E:/PycharmProjects/LEDdisplay2/1.py", line 5, in <module> y3 = s.encode("utf-8") UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128) Process finished with exit code 1
上面的代码可以看出,python2的默认编码是ASCII编码,直接对str类型的变量s进行encode时,python会使用默认编码ASCII码将变量s先deconde成Unicode,而文件开头已经声明代码用utf-8编码,所以会报ASCII码无法decode字节“0xe4”,而“0xe4”是utf-8编码存储变量s=“中文”的第一个字节的十六进制表示。
乱码情况3
将下面代码文件(存储时选择utf-8编码)直接在命令行里面运行,又会发生什么问题呢?
# encoding:gbk s = "中文" y1 = s.decode("gbk") #s.decode("gbk")这句话跟u“中文”效果是等价的 y2 = s.decode("gbk").encode("utf-8") print(y1) print(y2)
y1正常显示中文了,y2却出现了乱码。这次出现乱码的原因又是什么呢?windows命令行的环境编码是GBK格式,y1经过decode后是Unicode码,前面提到对于任何Unicode类型编码的字符,打印时python会自动根据环境编码转为特定编码后再显示,所以y1在cmd命令行下正常显示。y2经过解码和编码后是utf-8格式,只能在环境编码为utf-8的环境中才能正常显示,在winows命令行下运行就会出现由于编码不一致而导致的乱码。如果上述代码再加一句print(s),将其分别在pycharm和cmd下运行,结果会是怎样呢?
# encoding:gbk s = "中文" y1 = s.decode("gbk") #s.decode("gbk")这句话跟u“中文”效果是等价的 y2 = s.decode("gbk").encode("utf-8") print(y1) print(y2) print(s)
E:\PycharmProjects\LEDdisplay2\venv\Scripts\python.exe E:/PycharmProjects/LEDdisplay2/1.py 中文 中文 ���� Process finished with exit code 0
在pycharm环境下运行,输出s会乱码,因为pycharm环境编码我们设置的是utf-8,文件开头声明编码是gbk,编码方式不一致,故乱码。在cmd环境下运行,输出a不会乱码,因为cmd环境编码是GBK,而我们开头文件声明的编码格式也是GBK,编码方式一致,故正常显示。上述的代码都是在python2环境下运行的,如果是python3的脚本的话,则要简单得多。因为python3中,所有的字符串不再受系统环境编码的影响,统一使用Unicode来进行编码,字符串类型统一为str,所以不再需要在中文前面加u来使中文字符变为Unicode这种写法。而且所有python3的脚本默认都是utf-8来编码的,所以我们也不需要在脚本开头指定coding:utf-8了(但是一般建议写上,兼容python2)。打印显示的时候也会方便很多,由于是字符串都是Unicode格式,所以不管在命令行中还是pycharm中,都会正常显示而不会出现乱码。
乱码情况4
如果是直接在命令行中写脚本,又会出现什么问题呢?我们只需要弄清楚字符本身的编码和环境编码是否一致就可以得出答案了。在python shell(即命令行)中直接写代码运行时,我们需要知道的是,windows下命令行的默认编码是gbk的,Linux环境下命令行的默认编码是utf-8的。
第一行我们在定义a="中文"时,并不会报错,因为在命令行中默认是gbk编码,所以此时其实a的编码已经是gbk了,支持中文没有任何问题。直接显示a变量时,打印出来的不是乱码,而是该字符串的字节码表示方式,大家可以理解成给计算机看的,不是给人看的,只有print出来的内容才是给人看的。print(a)也不会报错,因为按照gbk方式编码并且在gbk环境中运行,不可能会出问题。直接将a进行decode解码时,解码方式必须跟编码方式是一致的,gbk方式编码的内容不能用utf-8解码为Unicode,只能用gbk解码成Unicode。用gbk进行decode之后,字符串会变为Unicode,python会自动根据环境的编码进行编码,故可以正常显示。最后,我们将Unicode按照utf-8编码时,字符的编码格式又跟环境编码不一致了,所以再次出现了乱码。linux下同理,只是linux下命令行的默认编码格式是utf-8。
参考链接:
https://blog.csdn.net/joyfixing/article/details/79971667
https://zhuanlan.zhihu.com/p/74613584?utm_source=wechat_session
https://www.cnblogs.com/liaohuiqiang/p/7247393.html -
Windows操作系统中消除汉字乱码有绝招
2013-02-07 12:28:35我们在操作电脑的时候,经常会遇到汉字乱码,例如打开“写字板”,里面的文字是一塌糊涂,中英文、乱码三足鼎立;玩游戏时菜单也一片乱码,让你不知所措;至于电子邮件乱码,那就更常见了,大家可能都遇到过。为了消除... -
vscode编写c语言程序输出中文乱码问题
2022-03-25 09:41:51这个时候,如果我们的c语言程序的编码格式与cmd命令行的字符集不统一,那么就会输出乱码。 而vscode运行c程序本身也是这个原理,它帮我们打开一个shell,执行gcc生成exe,运行exe文件看到输出效果,但是vscode... -
IDEA 控制台输出中文出现乱码的解决办法,亲测有效
2022-06-12 21:16:42首先我们去java官网下载JDK17版本,因为jdk18就是出现乱码的根源官网:Java Downloads | Oracle 下载完成后安装到自己创建的文件夹下,如图我的文件夹是javajava下: 然后我们打开idea,开始新建项目,并配置下载好... -
STM32 在PC端串口助手上打印中文字符----printf()函数重定向
2019-01-31 12:30:33比较形象,但是自己在写串口的时候写出来的程序不能像当初VC++里的C语言一样利用printf()函数还输出汉字,而是一堆乱码的东西或者16进制数字,看着很难受,于是就决定把这个东西的原理给搞懂;串口的配置就不多说了... -
Day11 2021.3.13转换流-序列反序列化-打印流-网络编程入门
2021-03-13 16:00:26GBxxx字符: 为了显示中文而设计的一套字符集 GB2312:简体中文码表,一个小于127字符的意义是原来相同,但两个大于127的字符连在一起时,表示一个汉字。 GBK:常用的中文码表。双字节编码。 GB18030:最新的... -
VScode关于print输出中文乱码问题解决方法
2022-04-01 22:00:12如果你的vscode出现了中文乱码不知道怎么解决,请点这里看看噢,相信可以解决你的问题 -
qt 中文乱码 - jwzhangjie的个人空间 - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园
2021-06-26 01:14:14初学Linux,直接进阶QT编程。然而,第一个Demo程序就碰到了中文乱码,巨汗!环境:1、RedHat AS52、QT4.4.03、LANG="zh_CN.GB18030"程序:...QTextCodec::setCodecForTr(QTextCodec::codecForName("gb18030"));...... -
[求助] printf("乱码“); 为何输出中文时是乱码。
2020-12-19 01:15:06#include "stdio.h"#include "conio.h"main(){printf("我的爱好是编程\n");getch();}重装系统后还是输出乱码,为什么?搜索更多相关的解决方案:printf乱码中文输出----------------解决方案------------------------... -
记事本乱码怎么办【解决方法】
2021-06-16 02:32:02我们在平常经常会将一些资料记录在记事本中,或者将word文档另存为记事本,但是等到我们过一阵再打开它是却常常发现里面已经是一堆乱码,无法正常的查看了。那么这时应该怎么办呐,下面就让小编来教你如何应对这种... -
计算机编程语言的代码——编码
2020-04-07 09:25:53数字32到126表示的这些字符都是可打印字符,0到31和127表示一些不可以打印的字符,这些字符一般用于控制目的。 ISO-8859-1 ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全... -
万字长文总结JAVA几种常见的编码格式和乱码原因分析
2021-02-01 09:09:00它能表示 21003 个汉字,它的编码是和 GB2312 兼容的,也就是说用 GB2312 编码的汉字可以用 GBK 来解码,并且不会有乱码。 GB18030(兼容GB2312) 全称是《信息交换用汉字编码字符集》,是我国的强制标准,它可能是... -
Python 网络爬虫 006 (编程) 解决下载(或叫:爬取)到的网页乱码问题
2016-09-13 20:57:02解决下载(或叫:爬取)到的网页乱码问题使用的系统:Windows 10 64位 Python 语言版本:Python 2.7.10 V 使用的编程 Python 的集成开发环境:PyCharm 2016 04 我使用的 urllib 的版本:urllib2注意: 我没这里... -
如何解决PHP中文乱码问题?
2021-03-23 14:59:54早期的软件(尤其是操作系统),为了解决本地字符信息的计算机处理,出现了各种本地化版本 (L10N),为了区分,引进了 LANG, Codepage 等概念。但是由于各个本地字符集代码范围重叠,相互间信息交换困难;软件各个本地... -
Qt编程
2019-10-14 20:59:57QTextCodec类,在Qt中,在编辑器中所写入的汉字字符为GBK(GB2312),而在组件中的字符识别为unicode字符集,所以写入的字符运行起来后通常会出现乱码。 QString类中常用的函数 1、数字不需要转换为GBK 直接通过... -
ARM-LINUX平台下的文本文件打印机打印
2021-10-07 17:12:092. 上层服务软件的移植。 3. 打印接口制作。 在计划最后,还准备实验佳能公司打印机,会编写单独的实验报告,本文档不会详细介绍。 二、ARM-LINUX平台下实现文本文件打印方案 根据前期工作,已明确使用... -
解决在STM32编程中由于printf函数里面有中文导致编译时出现警告的问题!
2021-08-07 17:35:48编译结果如下图所示: 1、首先有网友提出是由文件夹里面有...这时候可能会发现原先的中文变成了乱码,此时只需要删除原先的中文然后进行重新编辑即可,最后别忘了保存。 编码格式转换好之后我又打开Keil软件重新... -
一个汉字占两个字节(2的16次方,0 ~ 65535)。 * * 4. 国际 Unicode (universal code):utf-8 : 兼容ASCII表, 其次 归纳其他主流文字 * 1. 一个英文一个字节 * 2. 一个中文三个字节ÿ...
-
汉字取模读取并显示
2021-11-15 16:48:40目录一、概述二、什么是点阵1、8×8点阵原理图2、8×8点阵实物图三、汉字编码1、区位码2、机内码3、对于16×16点阵字库4、对于14×14与12×12点阵...OpenCV显示图片并打印汉字1、实验要求2、实验进行前的准备3、代码编写... -
编程必备基础知识-计算机组成原理-概述篇
2020-01-22 18:52:33简单记录-慕课网-编程必备基础 计算机组成原理+操作系统+计算机网络 编程必备基础知识-计算机组成原理-概述篇 回头补补计算机基础知识的理论 计算机基础知识-计算机组成原理、操作系统、计算机网络 目录 文章目录... -
常见乱码问题分析和总结
2018-05-04 16:51:38夏 怀英 和 David Chen2018 年 1 月 17 日发布在我们的日常工作生活中一定碰到过下面的情况:场景 1: 安装完某个软件后,看到的安装程序变成类似这样的一组字符" µç×Ó˰Îñ¾ÖÖ¤ÊéÇý¶¯¼°·... -
VSCODE C语言终端输出中文乱码编码分析设置和简单汇总
2021-03-25 19:32:412、VScode C语言printf打印中文,终端输出乱码 3、外部终端和VScode内部终端的区别之处,以及可能出现的乱 码、无法编译等情况分析 4、VScode 的C程序中文包括注释都是乱码 # 问题描述: 1、2、乱码时的可能... -
解决keil uVision5中文乱码或设置编码问题!
2020-07-03 14:00:38解决keil uVision5中文乱码或设置编码问题! 1.打开软件 2.选择Edit 3.在弹出的菜单选项中选择configuration按钮进入编辑的配置选项 4.在editor的选项卡里面encoding默认使用的编码是ansi编码 5.我们只需要把ansi... -
mysql数据库乱码怎么修改
2021-01-19 08:22:30解决MySQL中文乱码以及版本不一致问题这几天基于Heritrix写了一个爬虫,用到MySQL,在导入导出数据时,遇到一些乱码问题,好不容易解决了,记录一下,以备查看。一、导出数据先说明一下自己的环境:Mac OS X 10.8.3,... -
Java一个汉字占几个字节(详解与原理)
2020-05-14 12:27:49那时候凡是受过加持,会编程的计算机僧侣们都要每天念下面这个咒语数百遍: "一个汉字算两个英文字符!一个汉字算两个英文字符……" 因为当时各个国家都像中国这样搞出一套自己的编码标准,结果互相之间谁也不懂谁... -
jsp中文显示乱码解决方案
2018-07-12 22:55:28jsp中文显示乱码解决方案(文章来源:https://blog.csdn.net/weixin_41648325/article/details/79465966)一、JSP页面显示乱码二、表单提交中文时出现乱码三、数据库连接大家在JSP的开发过程中,经常出现中文乱码的... -
软件测试笔记
2021-01-05 11:21:28软件测试自己整理笔记(非常实用)