字符串转码后损坏

问题描述 投票:0回答:1

为了便于描述,我提供了以下代码的最小复制:

#include <bits/stdc++.h>
#include <iostream>
#include <regex>
#include <string>
#include <string>
#include <Windows.h>

// GBK 转 UTF-8
std::string GBKToUTF8(const std::string& gbkStr) {
    // 1. 先将 GBK 转换为宽字符(UTF-16)// Convert GBK to wide characters first (UTF-16)
    int len = MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), -1, nullptr, 0);
    std::wstring wstr(len, 0);
    MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), -1, &wstr[0], len);

    // 2. 将宽字符(UTF-16)转换为 UTF-8 // Convert wide characters (UTF-16) to UTF-8
    len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
    std::string utf8Str(len, 0);
    WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &utf8Str[0], len, nullptr, nullptr);

    return utf8Str;
}

int main() {
    // 示例身份证号,长度为18 // Example ID number, length 18
    std::string id_number = GBKToUTF8("610702199404261983");  
    // 检查字符串长度 // Check string length
    std::cout << "Length before: " << id_number.length() << "\n"
        << id_number << std::endl;

    // 正则表达式 // Regular expression
    const std::regex id_number_pattern18("^([1-6][1-9]|50)\\d{4}(18|19|20)\\d{2}((0[1-9])|10|11|12)(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$");

    // 进行匹配 // Make a match
    if (std::regex_match(id_number, id_number_pattern18)) {
        std::cout << "Match successful!" << std::endl;
    } else {
        std::cout << "Match failed!" << std::endl;
    }

    return 0;
}

现在的问题是,当

id_number
字符串转码为UTF-8时,长度从18变成了19。另外,正则表达式不再正确匹配字符串(如果不转码也可以正确匹配)。

我怀疑字符串被转码并添加了一些不可见的字符,但我不知道如何解决这个问题。

下面是VS2022(ISO C++17)调试的一些截图供参考(当然截图不是来自最小复现代码,但应该很好理解):

转码前
image

转码后
image

我目前不知道如何执行此操作,或者我想提供解决方案并描述问题是如何出现的。

c++ regex string winapi
1个回答
0
投票

问题是您要求

MultiByteToWideChar()
WideCharToMultiByte()
在它们返回的长度中包含空终止符的空间,然后在为
std::wstring
std::string
分配内存时包含该空终止符。这些字符串类型不是以 null 结尾的,因此请从等式中删除 null 终止符,例如:

GBK 转 UTF-8
std::string GBKToUTF8(const std::string& gbkStr) {
    // 1. 先将 GBK 转换为宽字符(UTF-16)
    int len = MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), -1, nullptr, 0);
    std::wstring wstr(len-1, 0);
    MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), -1, &wstr[0], len);

    // 2. 将宽字符(UTF-16)转换为 UTF-8
    len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
    std::string utf8Str(len-1, 0);
    WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &utf8Str[0], len, nullptr, nullptr);

    return utf8Str;
}

或者:

GBK 转 UTF-8
std::string GBKToUTF8(const std::string& gbkStr) {
    // 1. 先将 GBK 转换为宽字符(UTF-16)
    int len = MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), gbkStr.size(), nullptr, 0);
    std::wstring wstr(len, 0);
    MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), gbkStr.size(), &wstr[0], len);

    // 2. 将宽字符(UTF-16)转换为 UTF-8
    len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.size(), nullptr, 0, nullptr, nullptr);
    std::string utf8Str(len, 0);
    WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.size(), &utf8Str[0], len, nullptr, nullptr);

    return utf8Str;
}
© www.soinside.com 2019 - 2024. All rights reserved.