吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 603|回复: 13
收起左侧

[求助] BIG5编码转为gb2312编码

[复制链接]
kof888 发表于 2024-5-24 22:04
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。

测试代码:

#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[i + j]);
            else
                printf("   ");
        printf(" ");
        for (j = 0; j < 16; j++)
            if (i + j < buflen)
                printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.');
        printf("\n");
    }
}

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

// 代码页信息
// 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[0], 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[0], 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[0], 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[0], 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                          ........

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

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

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
kof888 + 1 + 1 热心回复!

查看全部评分

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[1], SourceLength, @result[1], 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[1], SourceLength, @result[1], SourceLength);
end;
ypcok 发表于 2024-5-25 11:39
Word 有转存功能
 楼主| kof888 发表于 2024-5-25 11:50
非常感谢楼上几位朋友的热心回复,我是想不借助编译器自带的函数来进行转换,就是想问问看有什么算法来自己转换,看起来要么用编译器的函数转换,要么只能自己写一个映射表来进行硬转换了

点评

这不是编译器的函数,是微软系统 dll 提供的。 [md]例如 [LCMapStringEx](https://learn.microsoft.com/windows/win32/api/winnls/nf-winnls-lcmapstringex),你可以看到底部写的该函数来自 `Kernel32.dll`,支持  详情 回复 发表于 2024-5-25 21:15
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编码算是可变长度的编码,编码长度不是固定的。

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

点评

微软的 Unicode(UTF-16-le)是固定长度,每个字符使用双字节表示。  详情 回复 发表于 2024-5-25 21:12
爱飞的猫 发表于 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 提供的。

例如 LCMapStringEx,你可以看到底部写的该函数来自 Kernel32.dll,支持 Windows Vista 及以上系统。

如果不想用它,只能和你说的一样在程序内硬编码对应的字符映射表了。

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-28 07:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表