本文测试环境 win10+5.7mysql+vs2017
vs2017工程为多字节字符集,文件编码格式为GB2123,数据库字符集为UTF8
1、插入中文报错
[client]
port=3306
default-character-set=utf8
[mysqld]
# 设置为自己MYSQL的安装目录
basedir=E:\UIClientTool\mysql-5.7.26\bin
# 设置为MYSQL的数据目录
datadir=E:\UIClientTool\mysql-5.7.26\data
port=3306
character_set_server=utf8
sql_mode=NO_ENGINE_SUBSTITUTION,NO_AUTO_CREATE_USER
#开启查询缓存
explicit_defaults_for_timestamp=true
#底下代码开启,是数据库每次重启之后不要密码就可以连接数据库,适用于管理员忘记密码时的操作
#skip-grant-tables
default-character-set=utf8
character_set_server=utf8
百度有很多教程,修改配置my.ini文件中上述2个字段重启mysql服务
2、插入中文不显示
当前文件编码格式,GB2312写入到UTF8字符集,存在中文写入为空的情况(图1)
解决方法:多字节->UNICODE->UTF8写入(ConsoleToUtf8)。转化之后,GB2312 C++可以查看正确中文,写入UTF8也可以查看正常中文。当前取出数据后,要再反转一次,UTF8->GB2312,这样C++才能正常显示中文。(图2)
注:当前cpp文件编码格式为GB2312
3、插入中文乱码
把cpp文件编码格式改为UTF8编码,那么不需要转换,直接存取,那么C++文件和Mysql都将显示乱码,无法查看正常的中文。(图3)
4、示例
1)C++编码格式GB2312:
(1)服务器GB2312中文数据直接保存,则数据库表中文不显示(图1 id:9)。
(2)服务器转换中文为UTF8编码,则数据库显示中文正常(图2 id:10)。
(3)服务器读取UTF8编码格式,传回给客户端,直接传回。如果想要本地C++文件显示,则需要转化为GB2312。
2)C++编码格式UTF8:客户端手机一般为linux utf8编码,传送数据到C++服务器。
(1)服务器直接保存中文数据,则数据库表中文显示乱码(图3 id:13)。
(2)服务器转换中文为GB2312编码,本地C++文件显示正常,存入数据库不显示中文。
(3)服务器读取UTF8编码格式,传回给客户端,直接传回。如果想要本地C++文件显示,则需要转化为GB2312。
结论:
1、Linux服务器:直接UTF8编码格式,本地文件和mysql字符集一样,不需要转换编码,直接存取。显示正常。
2、第一,不能插入数据,一般是配置问题。第二,能插入数据,但不显示,编码问题。第三,能插入数据,乱码,编码问题。
3、Unicode编码直接写入UTF8字符集数据库,尚未测试,结果待定。如果出现问题,参考第三条结论。
4、下面提供转换函数参考:依赖库utf8cpp
ConsoleToUtf8(多字节->Unicode->UTF8) UTF8ToConsole(UTF8->Unicode->多字节)
bool StringUtility::Utf8toWStr(const std::string & utf8str, std::wstring & wstr)
{
wstr.clear();
try
{
utf8::utf8to16(utf8str.c_str(), utf8str.c_str() + utf8str.size(), std::back_inserter(wstr));
}
catch (std::exception const&)
{
wstr.clear();
return false;
}
return true;
}
bool StringUtility::IsBasicLatinCharacter(wchar_t wchar)
{
if (wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
return true;
if (wchar >= L'A' && wchar <= L'Z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
return true;
return false;
}
wchar_t StringUtility::wcharToUpper(wchar_t wchar)
{
if (wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
return wchar_t(uint16(wchar) - 0x0020);
if (wchar == 0x00DF) // LATIN SMALL LETTER SHARP S
return wchar_t(0x1E9E);
if (wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
return wchar_t(uint16(wchar) - 0x0020);
if (wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
return wchar_t(uint16(wchar) - 0x0020);
if (wchar >= 0x0101 && wchar <= 0x012F) // LATIN SMALL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK (only %2=1)
{
if (wchar % 2 == 1)
return wchar_t(uint16(wchar) - 0x0001);
}
if (wchar >= 0x0430 && wchar <= 0x044F) // CYRILLIC SMALL LETTER A - CYRILLIC SMALL LETTER YA
return wchar_t(uint16(wchar) - 0x0020);
if (wchar == 0x0451) // CYRILLIC SMALL LETTER IO
return wchar_t(0x0401);
return wchar;
}
wchar_t StringUtility::wcharToUpperOnlyLatin(wchar_t wchar)
{
return IsBasicLatinCharacter(wchar) ? wcharToUpper(wchar) : wchar;
}
bool StringUtility::WStrToUtf8(std::wstring const & wstr, std::string & utf8str)
{
try
{
std::string utf8str2;
utf8str2.resize(wstr.size() * 4); // allocate for most long case
if (wstr.size())
{
char* oend = utf8::utf16to8(wstr.c_str(), wstr.c_str() + wstr.size(), &utf8str2[0]);
utf8str2.resize(oend - (&utf8str2[0])); // remove unused tail
}
utf8str = utf8str2;
}
catch (std::exception const&)
{
utf8str.clear();
return false;
}
return true;
}
bool StringUtility::Utf8ToUpperOnlyLatin(std::string & utf8String)
{
std::wstring wstr;
if (!Utf8toWStr(utf8String, wstr))
return false;
std::transform(wstr.begin(), wstr.end(), wstr.begin(), wcharToUpperOnlyLatin);
return WStrToUtf8(wstr, utf8String);
}
bool StringUtility::ConsoleToUtf8(const std::string & conStr, std::string & utf8str)
{
std::wstring wstr;
wstr.resize(conStr.size());
OemToCharBuffW(&conStr[0], &wstr[0], uint32(conStr.size()));
return WStrToUtf8(wstr, utf8str);
}
bool StringUtility::Utf8ToConsole(const std::string& utf8str, std::string& conStr)
{
#if LENDY_PLATFORM == LENDY_PLATFORM_WINDOWS
std::wstring wstr;
if (!Utf8toWStr(utf8str, wstr))
return false;
conStr.resize(wstr.size());
CharToOemBuffW(&wstr[0], &conStr[0], uint32(wstr.size()));
#else
// not implemented yet
conStr = utf8str;
#endif
return true;
}