MFC开发第四天 关于Unicode与ANSI编码转换技术和文本文件的识别、无BOM头的Utf8的编码识别算法

关于Unicode与ANSI编码转换技术和文本文件的识别、无BOM头的Utf8的编码识别算法

今日单词:
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<windows.h>
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<windows.h>
#include"resource.h"
#include<stdio.h>
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;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jcrry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值