今日单词:
Parse:解析,(协议解析)
codec:编码器 n.
code:代码 n.
Wide:宽的 adj.
automatically:自动地 adv.
require:需要 v.
1、MultiByte和WideChar
a)ANSI 和 UTF8 都是MultiByte(俗称窄字节)
b)UTF16大端和小端都是WideChar(俗称宽字节)
Win32 API提供了一些函数来转换文本编码。下面是一些常用的转换函数:
MultiByteToWideChar:将ANSI编码的文本转换为Unicode编码的文本
WideCharToMultiByte:将Unicode编码的文本转换为ANSI或Utf-8编码的文本
MultiByteToWideChar和WideCharToMultiByte的组合:将ANSI编码的文本转换为UTF-8编码的文本
以下是使用这些函数进行转换的示例代码:
2、文本文件编码识别:
a)ANSI没有头部标识
b)U16大端和小端的头部标识:0xFFFE 和 0xFEFF
c)U8的头部标识:0xEF BB BF
WideCharToMultiByte 函数是用于将宽字符编码转换为多字节编码的函数,其参数如下:
int WideCharToMultiByte(
UINT CodePage, // [in] 多字节编码的代码页标识符 ANSI 或UTF8 目标要输出的种类
DWORD dwFlags, // [in] 转换标志
LPCWCH lpWideCharStr, // [in] 宽字符字符串指针 来源文字
int cchWideChar, // [in] 宽字符字符串的字符数 带入-1代表自动计算长度,除非截取
LPSTR lpMultiByteStr, // [out] 多字节字符串指针 目标空间
int cbMultiByte, // [in] 多字节字符串缓冲区的大小 空间长度(边界限制)
LPCCH lpDefaultChar, // [in] 用于表示未转换字符的默认字符指针
LPBOOL lpUsedDefaultChar // [out] 指针,用于指示是否使用了默认字符来转换字符
);
int n = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
n = WideCharToMultiByte(CP_ACP, 0, str, -1, p, n, NULL, NULL);
参数具体含义如下:
CodePage:多字节编码的代码页标识符,用于指定要使用的多字节编码类型,例如 CP_ACP、CP_UTF8等。
dwFlags:转换标志,用于指定转换方式和处理方式。常用的标志有以下几个:
WC_COMPOSITECHECK:检查是否存在复合字符,如果存在则将其转换为单个字符。
WC_DEFAULTCHAR:用默认字符替换无法转换的字符。
WC_NO_BEST_FIT_CHARS:禁用最佳匹配模式,如果无法精确匹配则返回错误。
lpWideCharStr:宽字符字符串指针,指向要转换的宽字符编码字符串。
cchWideChar:宽字符字符串的字符数,以字符为单位,表示要转换的宽字符字符串的长度。
lpMultiByteStr:多字节字符串指针,指向存储转换后的多字节编码字符串的缓冲区。
cbMultiByte:多字节字符串缓冲区的大小,以字节为单位表示存储转换后的多字节编码字符串的缓冲区大小。
lpDefaultChar:用于表示未转换字符的默认字符指针,如果设置了 WC_DEFAULTCHAR 标志,则用此字符替换无法转换的字符。
lpUsedDefaultChar:指针用于指示是否使用了默认字符来转换字符,如果使用了则该值为TRUE,否则为FALSE。
MultiByteToWideChar 函数用于将多字节字符转换为宽字符的函数。
int MultiByteToWideChar(
UINT CodePage, // 源字符集的代码页标识符
DWORD dwFlags, // 转换标志
LPCSTR lpMultiByteStr, // 指向多字节字符串的指针
int cbMultiByte, // 多字节字符串的字节数
LPWSTR lpWideCharStr, // 指向宽字符缓冲区的指针
int cchWideChar // 宽字符缓冲区的大小
);
int n = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
n = MultiByteToWideChar(CP_UTF8, 0, str, -1,p, n);
CodePage:源字符集的代码页标识符,可以使用常量或数字作为参数。例如,CP_UTF8 表示 UTF-8 编码,CP_ACP 表示当前 ANSI 代码页,936 表示简体中文 GBK 编码等。
dwFlags:转换标志,可以使用常量或数字作为参数。例如,0 表示使用默认行为,MB_ERR_INVALID_CHARS 表示遇到无效的多字节字符时引发错误等。
lpMultiByteStr:指向多字节字符串的指针。
cbMultiByte:多字节字符串的字节数,不包括结尾的空字符。如果此值为-1,则假定字符串以空结束,并自动计算长度。
lpWideCharStr:指向宽字符缓冲区的指针。
cchWideChar:宽字符缓冲区的大小,以字符为单位。如果此参数为 0,则函数将返回需要的缓冲区大小,不执行转换操作。
注意:MultiByteToWideChar 函数的返回值表示转换后的宽字符数,不包括结尾的空字符。如果转换失败,则返回值为 0,并可以使用 GetLastError 函数获取错误代码。
codec.cpp 编码格式转换
#include
bool CheckUtf8(LPCSTR p) //无BOM头的Utf8的编码识别算法
{
auto q = p;
while (*p)
{
BYTE c = *p;
BYTE x = 0x80;
int n = 0;
while ((c & x) == x)
++n, x >>= 1;
if (n == 1 || n > 4)
return false;
++p;
while (--n>0)
{
c = *p++;
if (c >> 6 != 2) //00000010
return false;
}
}
return true;
}
void ConvertBig(LPSTR p) //UTF16大端转换
//将一个以null结尾的字符串中的每两个字符进行交换,即将每两个字符的顺序逆序
{
while (*(WORD*)p) //双字节的0结尾结束
{
*p = *p ^ p[1]; //没有中间变量的反转
p[1] = *p ^ p[1];
*p = *p ^ p[1];
p += 2;
}
/* 采用了异或运算(^)来实现交换两个字符的位置。具体来说
它首先将p所指向的字符与下一个字符进行异或运算,并将结果保存到p所指向的字符中。
然后将下一个字符和上一个字符进行异或运算,并将结果保存到下一个字符中。
最后再将p所指向的字符和下一个字符进行异或运算,并将结果保存到p所指向的字符中 */
}
char* UnicodeToANSI(const wchar_t* str)
{
int n = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); //第一次求长度 带L是Unicode的格式
auto p = new char[n + 1];
n = WideCharToMultiByte(CP_ACP, 0, str, -1, p, n, NULL, NULL); //第二次填充 p, n 你申请的空间,边界限制
p[n] = 0; //结尾
return p;
} //算出长度 申请空间 填充长度
wchar_t* UTF8ToUnicode(const char* str)
{
int n = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
auto p = new wchar_t[n + 1];
n = MultiByteToWideChar(CP_UTF8, 0, str, -1,p, n);
p[n] = 0;
return p;
}
char* UTF8ToANSI(const char* str)
{
auto p = UTF8ToUnicode(str);
auto q= UnicodeToANSI(p);
delete[] p;
return q;
}
Notepad.cpp
#define _CRT_SECURE_NO_WARNINGS
#include
#include"resource.h"
#include
void ConvertBig(LPSTR p);
char* UnicodeToANSI(const wchar_t* str);
char* UTF8ToANSI(const char* str);
bool CheckUtf8(LPCSTR p);
void ParseText(HWND hwndDlg, LPSTR p)
{
char* q = nullptr;
switch (*(WORD*)p)
{
case 0xFFFE: //BE 大端 大端与小端之间完全颠倒 每个字节之间完全的进行反转 翻转以后就说小端的代码
ConvertBig(p);
case 0xFEFF: //LE 小端
q = UnicodeToANSI(LPWSTR(p+2));
SetDlgItemText(hwndDlg, IDC_TEXT, q);
delete[] q;
return;
case 0xBBEF: //UTF8 BOM
if (p[2]==(char)0xBF)
{
q=UTF8ToANSI(p + 3);
SetDlgItemText(hwndDlg, IDC_TEXT, q);
delete[] q;
return;
}
return;
}
if (CheckUtf8(p))
{
q = UTF8ToANSI(p);
SetDlgItemText(hwndDlg, IDC_TEXT, q);
delete[] q;
}
else
SetDlgItemText(hwndDlg, IDC_TEXT, p);
}
int GetFileSize(FILE* pf)
{
long m = ftell(pf);
fseek(pf, 0, SEEK_END);
long n = ftell(pf);
fseek(pf, m, SEEK_SET);
return n;
}
void ReadTextFile(HWND hwndDlg, LPCSTR sFile)
{
FILE *pf = fopen(sFile, "rb");
if (!pf)
return;
int nSize = GetFileSize(pf);
if (nSize>0)
{
char* p = new char[nSize + 2];
auto n= fread(p, 1, nSize, pf);
p[n] = 0;
p[n + 1] = 0;
ParseText(hwndDlg, p);
// SetDlgItemText(hwndDlg, IDC_TEXT, p);
delete[] p;
}
fclose(pf);
}
void onDropFile(HWND hwndDlg, HDROP hDrop)
{
char s[MAX_PATH];
int nCount = DragQueryFile(hDrop, 0, s, sizeof(s)); //取第一个文件名 如果要去最后一个,先求出总数再ncount-1
//SetDlgItemText(hwndDlg, IDC_TEXT, s);
ReadTextFile(hwndDlg, s);
DragFinish(hDrop);
}
INT_PTR CALLBACK theProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DROPFILES:
MessageBox(hwndDlg, "拖入文件成功", "提示", 0);
onDropFile(hwndDlg, (HDROP)wParam);
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, 88);
break;
}
}
}
return 0;
}
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
DialogBox(hInstance, (LPCSTR)IDD_NOTE_DLG, NULL, theProc);
return 0;
}