为了描述方便,我提供了以下代码的最小复制:
#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)调试的一些截图,供参考(当然截图不是来自最小复现代码,但应该很好理解):
我目前不知道该怎么做,或者我想提供一个解决方案以及问题如何出现的描述。
问题在于您要求
MultiByteToWideChar()
在它们返回的长度中WideCharToMultiByte()
包含显式NUL 终止符的空间:std::wstring
在为和分配内存时,您将包含额外的空间std::string
。但是,与 C 字符串不同,C++ 字符串不是以空字符结尾的。它们可以包含嵌入的 NUL 字符(包含在其 中)size
,并且具有隐式NUL 终止符(不包含在其 中)size
。因此,您不应将 C++ 字符串视为以空字符结尾的字符串。不要向 API 请求 NUL 终止符的空间。请改用实际的字符串大小,例如: