kof888 发表于 2024-5-24 22:04

BIG5编码转为gb2312编码

big5和gb2312都是双字节编码,一个用于早期的繁体字编码,一个是简体字的编码
所以想问问是否有什么算法可以直接把繁体的big5的文字编码转换成gb2312编码的方法

WoAiPoJie5678 发表于 2024-5-25 07:41

在线工具

爱飞的猫 发表于 2024-5-25 09:18

本帖最后由 爱飞的猫 于 2024-5-25 09:22 编辑

不是所有的简体中文字符都可以映射到 BIG5(虽然包括了很大一部分),也不是所有的繁体中文字符都可以映射到 GBK 等编码。

不过微软提供了简繁转换接口,`LCMapStringEx`,可以将 Unicode 字符串中的简体和繁体仅限转换(不包括当地特有词汇)。

因此,你可以:

- BIG5 繁体字符转到 Unicode
- 使用 `LCMapStringEx` 将 Unicode 字符串的繁体字符映射到简体字符
- 最后将这段 Unicode 字符串转换到 GBK。

测试代码:

```cpp
#include <string>
#include <iostream>
#include <windows.h>
#include <ctype.h>
#include <stdio.h>

// 以十六进制视图打印
void hexdump(const void* ptr, int buflen) {
    auto* buf = (const unsigned char*)ptr;
    int i, j;
    for (i = 0; i < buflen; i += 16) {
      printf("%06x: ", i);
      for (j = 0; j < 16; j++)
            if (i + j < buflen)
                printf("%02x ", buf);
            else
                printf("   ");
      printf(" ");
      for (j = 0; j < 16; j++)
            if (i + j < buflen)
                printf("%c", isprint(buf) ? buf : '.');
      printf("\n");
    }
}

template <typename CONTAINER>
void hexdump(CONTAINER& str)
{
    hexdump(reinterpret_cast<const void*>(str.data()), str.size() * sizeof(str));
}

// 代码页信息
// https://learn.microsoft.com/wind ... de-page-identifiers
constexpr int kCodePageGB2312 = 936; // 简体 (GB2312)
constexpr int kCodePageGB18030 = 54936; // 简体 (GB18030)
constexpr int kCodePageBig5 = 950; // 繁体

// 简单的 Ansi/Unicode 互转
std::wstring A2W(const std::string& ansi, int codePage = CP_ACP)
{
    int len = MultiByteToWideChar(codePage, 0, ansi.c_str(), -1, NULL, 0);
    std::wstring wide(len, 0);
    MultiByteToWideChar(codePage, 0, ansi.c_str(), -1, &wide, len);
    return wide;
}
std::string W2A(const std::wstring& wide, int codePage = CP_ACP)
{
    int len = WideCharToMultiByte(codePage, 0, wide.c_str(), -1, NULL, 0, nullptr, NULL);
    std::string ansi(len, 0);
    WideCharToMultiByte(codePage, 0, wide.c_str(), -1, &ansi, len, nullptr, NULL);
    return ansi;
}


int main()
{
    std::wstring text_src = L"吾爱破解论坛 - 爱飞的猫";


      // 简转繁
    std::wstring text_trad(text_src.size(), 0);
    LCMapStringEx(LOCALE_NAME_INVARIANT, LCMAP_TRADITIONAL_CHINESE, text_src.c_str(), text_src.size(), &text_trad, text_trad.size(), nullptr, nullptr, 0);
    std::wcout << L"繁体后: " << text_trad << L'\n';
    std::cout << "trad(bytes)\n";
    hexdump(text_trad);

    // 繁转简
    std::wstring text_simp(text_trad.size(), 0);
    LCMapStringEx(LOCALE_NAME_INVARIANT, LCMAP_SIMPLIFIED_CHINESE, text_trad.c_str(), text_trad.size(), &text_simp, text_simp.size(), nullptr, nullptr, 0);
    std::wcout << L"简体后: " << text_trad << L'\n';
      std::cout << "simp(bytes)\n";
    hexdump(text_simp);

    // 繁(Unicode) 转 BIG5
    auto text_trad_big5 = W2A(text_trad, kCodePageBig5);
    std::cout << "text_trad_big5(bytes)\n";
    hexdump(text_trad_big5);

    // 简(Unicode) 转 BIG5
    auto text_simp_big5 = W2A(text_simp, kCodePageBig5);
    std::cout << "text_simp_big5(bytes)\n";
    hexdump(text_simp_big5);

    // 繁(Unicode) 转 GB18030
    auto text_trad_GB18030 = W2A(text_trad, kCodePageGB18030);
    std::cout << "text_trad_GB18030(bytes)\n";
    hexdump(text_trad_GB18030);

    // 简(Unicode) 转 GB18030
    auto text_simp_GB18030 = W2A(text_simp, kCodePageGB18030);
    std::cout << "text_simp_GB18030(bytes)\n";
    hexdump(text_simp_GB18030);

    return 0;
}
```

转换结果:


```
trad(bytes)
000000: 3e 54 1b 61 34 78 e3 89 d6 8a c7 58 20 00 2d 00>T.a4x.....X .-.
000010: 20 00 1b 61 db 98 84 76 93 8c                     ..a...v..
simp(bytes)
000000: 3e 54 31 72 34 78 e3 89 ba 8b 5b 57 20 00 2d 00>T1r4x....[W .-.
000010: 20 00 31 72 de 98 84 76 2b 73                     .1r...v+s
text_trad_big5(bytes)
000000: a7 5e b7 52 af 7d b8 d1 bd d7 be c2 20 2d 20 b7.^.R.}...... - .
000010: 52 ad b8 aa ba bf df 00                        R.......
text_simp_big5(bytes)
000000: a7 5e 3f af 7d b8 d1 3f 3f 20 2d 20 3f 3f aa ba.^?.}..?? - ??..
000010: 3f 00                                          ?.
text_trad_GB18030(bytes)
000000: ce e1 90 db c6 c6 bd e2 d5 93 89 af 20 2d 20 90............ - .
000010: db ef 77 b5 c4 d8 88 00                        ..w.....
text_simp_GB18030(bytes)
000000: ce e1 b0 ae c6 c6 bd e2 c2 db cc b3 20 2d 20 b0............ - .
000010: ae b7 c9 b5 c4 c3 a8 00                        ........
```

放到十六进制编辑器看看(调整好代码页):

![](https://imgsrc.baidu.com/forum/pic/item/a8ec8a13632762d0f0154e82e6ec08fa513dc6e0.png)

可以看到如果不进行字符映射,转换到 BIG5 编码后会缺字(显示为问号)。

xuanle6 发表于 2024-5-25 10:28

本帖最后由 xuanle6 于 2024-5-25 10:35 编辑

//Delphi语言
// GBK-->GB2312
// 中華人民共和國 --> 中华人民共和国
function GBCht2Chs(const GBStr: string): AnsiString;
var
    SourceLength: integer;
begin
    SourceLength := Length(GBStr) + 1;
    SetLength(result, SourceLength);
    //GB CHS -> GB CHT
    LCMapString($804, LCMAP_SIMPLIFIED_CHINESE, @GBStr, SourceLength, @result, SourceLength);
end;

// GB2312-->GBK
// 中华人民共和国 --> 中華人民共和國
function GBChs2Cht(const GBStr: string): AnsiString;
var
    SourceLength: integer;
begin
    SourceLength := Length(GBStr) + 1;
    SetLength(result, SourceLength);
    LCMapString($804, LCMAP_TRADITIONAL_CHINESE, @GBStr, SourceLength, @result, SourceLength);
end;

ypcok 发表于 2024-5-25 11:39

Word 有转存功能

kof888 发表于 2024-5-25 11:50

非常感谢楼上几位朋友的热心回复,我是想不借助编译器自带的函数来进行转换,就是想问问看有什么算法来自己转换,看起来要么用编译器的函数转换,要么只能自己写一个映射表来进行硬转换了:'(weeqw

flyer_2001 发表于 2024-5-25 13:40

kof888 发表于 2024-5-25 11:50
非常感谢楼上几位朋友的热心回复,我是想不借助编译器自带的函数来进行转换,就是想问问看有什么算法来自己 ...

https://www.qqxiuzi.cn/zh/hanzi-unicode-bianma.php
unicode编码表

kof888 发表于 2024-5-25 17:41

flyer_2001 发表于 2024-5-25 13:40
https://www.qqxiuzi.cn/zh/hanzi-unicode-bianma.php
unicode编码表

感谢回复 ,Unicode编码算是可变长度的编码,编码长度不是固定的。

不过这贴我只是想了解一下繁体转简体的算法,看起来没有,只能自己做一个映射表来解决

爱飞的猫 发表于 2024-5-25 21:12

kof888 发表于 2024-5-25 17:41
感谢回复 ,Unicode编码算是可变长度的编码,编码长度不是固定的。

不过这贴我只是想了解一下繁体转简 ...

微软的 Unicode(UTF-16-le)是固定长度,每个字符使用双字节表示。

爱飞的猫 发表于 2024-5-25 21:15

kof888 发表于 2024-5-25 11:50
非常感谢楼上几位朋友的热心回复,我是想不借助编译器自带的函数来进行转换,就是想问问看有什么算法来自己 ...
这不是编译器的函数,是微软系统 dll 提供的。

例如 (https://learn.microsoft.com/wind ... innls-lcmapstringex),你可以看到底部写的该函数来自 `Kernel32.dll`,支持 Windows Vista 及以上系统。

如果不想用它,只能和你说的一样在程序内硬编码对应的字符映射表了。
页: [1] 2
查看完整版本: BIG5编码转为gb2312编码