기존 Windows 프로그램과 인터페이스해야하는 Linux 프로그램을 작성하고 있습니다. Windows 프로그램의 작동 방식을 수정할 수는 없지만 기존 데이터와 통합해야합니다. 이 프로그램은 TCP 네트워크 소켓을 통해 원시 데이터 구조를 수신합니다. 불행하게도 Windows 프로그램은 데이터 구조에 원시 멀티 바이트 문자열을 내장하고 어떤 코드 페이지가 사용 중인지 표시하지 않습니다. 이것은 영어에서는 정상적으로 작동하지만 비 라틴 기반 언어 (예 : 일본어)에서는 비참하게 실패합니다. 기껏해야, 나는 코드 페이지 창에서 사용하고있는 것으로 추측 할 수 있습니다. 내가 실행 중이고 로케일이 "ja"또는 "ja_JP"로 설정된 경우 windows 머신이 "SHIFT-JS"코드 페이지를 사용한다고 가정해야합니다 ... 추악하지만 그게 인생입니다.원시 MBCS 문자열 (SHIFT-JIS)을 Windows에서 UTF-8로 변환하는 방법
질문 :
내가 UTF-8 문자열이 원시 MBCS 문자 문자열을 변환 할 수있는 방법, 나는 코드 페이지에서 제대로 짐작 한 가정?
전송되는 문자열 인 : 私 の ク ラ ス へ よ う こ そ
MBCS 데이터 윈도우 (JP)으로부터 수신이다 (바이트 여분 "× 00"여기
원시 데이터의 샘플 인) 널 (null) 종료를 확인하기 위해 추가 :char kanji_win_raw_bytes[] = { 0x8E, 0x84, 0x82, 0xCC, 0x83, 0x4E, 0x83, 0x89, 0x83, 0x58, 0x82, 0xD6, 0x82, 0xE6, 0x82, 0xA4, 0x82, 0xB1, 0x82, 0xBB, 0x00, 0x00, 0x00 };
은 거의 내가 말할 수있는 문자열은 SHIFT-JS 코드 페이지를 사용하여 윈도우 머신에서오고있다. 나는() mbsrtowcs을 시도했다 :
const char *ptr = (char*)m_data;
// m_data contains the byte array of MBCS data
if (m_data != NULL)
{
std::mbstate_t state = std::mbstate_t();
size_t bufflen = std::mbsrtowcs(NULL, &ptr, 0, &state);
if (bufflen == (size_t)-1)
{
std::cout << "ERROR! mbsrtowcs() " << strerror(errno) << std::endl;
std::cout << "Error at: " << (int32_t)((char*)ptr - (char*)m_data) << std::endl;
return;
}
std::vector<wchar_t> wstr(bufflen);
std::cout << "converting " << bufflen << " characters" << std::endl;
std::mbsrtowcs(&wstr[0], &ptr, wstr.size(), &state);
std::wcout << "Wide string: " << &wstr[0] << std::endl
<< "The length, including '\\0': " << wstr.size() << std::endl;
}
mbsrtowcs() 호출 변환없이 문자 위치 "0"에 실패합니다.
bytes_converted = 0;
char input[4096] = {0};
char dst[4096] = {0};
char* src = input;
size_t dstlen = sizeof(dst);
size_t srclen = 0;
iconv_t conv = iconv_open("UTF-8", "SHIFT-JIS");
// make a copy
memcpy((void*)input, (void*)kanji_win_raw_bytes, sizeof(kanji_win_raw_bytes));
srclen = sizeof(kanji_win_raw_bytes);
if (conv != (iconv_t)-1)
{
bytes_converted = iconv(conv, NULL, NULL, (char**)&dst, &dstlen);
if (bytes_converted == (size_t) -1)
{
std::cerr << "ERROR: initializing output buffer: (" << errno << ") " << strerror(errno) << std::endl;
}
bytes_converted = iconv(conv, (char**)&src, &srclen, (char**)&dst, &dstlen);
if (bytes_converted == (size_t) - 1)
{
std::cerr << "ERROR in conversion: (" << errno << ") " << strerror(errno) << std::endl;
if (errno == EINVAL)
{
std::cerr << "RESULT: iconv() converted " << bytes_converted << " bytes: [" << dst << "]" << std::endl;
}
}
else
{
std::cerr << "SUCCESS: iconv() converted " << bytes_converted << " bytes: [" << dst << "]" << std::endl;
}
iconv_close(conv);
}
else
{
std::cerr << "ERROR: iconv_open() failed: " << strerror(errno) << std::endl;
}
의 iconv 세그먼테이션 폴트 (segfault) (코어 덤프) 지정된 (일본어) 문자열을 사용 :
I 다음 SHIFT-JS 코드 페이지를 사용하여 라이브러리의 iconv 시도. 몇 번만 iconv를 사용했기 때문에 (온라인 샘플에서 복사 한) 코드 스 니핏이 정확하고 비슷한 설정을 사용하지만 라틴 기반 언어에서는 괜찮은 것처럼 보이지만 Windows 서버에서 오는 mbcs 문자열 (즉 : 독일어/프랑스어) .
codecvt 함수 std :: wstring_convert는 -std = C++ 11로 컴파일 할 때조차도 Linux에서 구현되지 않은 것으로 보이므로 옵션으로 보이지 않습니다.
제공 할 수있는 도움에 미리 감사드립니다. 편집 - -
"MYK '의 도움으로, 내가 더 나은 내 문제를 보여주는 샘플 응용 프로그램을 만들었습니다. 그의 제안에 따라 세분화 오류를 해결할 수 있었지만 Windows MBCS 문자열은 내가 선택한 로케일에 관계없이 변환되지 않습니다.
/**
* MBCS test
*/
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <clocale>
#include <string>
#include <iostream>
// 私のクラスへようこそ (welcome to my class)
const char* kanji_string = "私のクラスへようこそ";
// This is what raw UTF-8 should look like
uint8_t kanji_utf8_raw_bytes[] = { 0xE7, 0xA7, 0x81, 0xE3, 0x81, 0xAE, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xA9, 0xE3, 0x82, 0xB9, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x88, 0xE3, 0x81, 0x86, 0xE3, 0x81, 0x93, 0xE3, 0x81, 0x9D };
// This is Windows MBCS using the SHIFT-JS code page
uint8_t kanji_win_raw_bytes[] = { 0x8E, 0x84, 0x82, 0xCC, 0x83, 0x4E, 0x83, 0x89, 0x83, 0x58, 0x82, 0xD6, 0x82, 0xE6, 0x82, 0xA4, 0x82, 0xB1, 0x82, 0xBB, 0x00, 0x00, 0x00 };
int main(int argc, char **argv)
{
std::setlocale(LC_ALL, "en_US.utf8");
std::cout << "KANJI String [" << kanji_string << "]" << std::endl;
std::cout << "KANJI UTF-8 Raw [" << kanji_utf8_raw_bytes << "]" << std::endl;
const char *data = (char*)kanji_win_raw_bytes;
std::mbstate_t state = std::mbstate_t();
size_t result = 0;
wchar_t* buffer = (wchar_t*)malloc(sizeof(wchar_t) * (strlen((char*)data) + 1));
if (buffer)
{
result = std::mbsrtowcs(buffer, &data, strlen(data), &state);
if (result == (size_t)-1)
{
std::cout << "ERROR! mbsrtowcs() " << strerror(errno) << std::endl;
std::cout << "Error at: " << (int32_t)((char*)data - (char*)kanji_win_raw_bytes) << std::endl;
}
else
{
std::wcout << "Wide string: [" << buffer << "] " << std::endl;
}
free(buffer);
}
return 0;
}
참고 :이 컴파일하고 다음 명령을 사용하여 리눅스/맥에서 실행할 수 있습니다 : mbsrtowcs를 들어
g++ mbcs_test.cpp -o mbcs_test && ./mbcs_test
제안 해 주셔서 감사합니다. 당신 말이 맞아요, 위의 샘플에서 setlocale() 호출을 포함하지 않았습니다. 귀하의 제안으로 샘플을 업데이트했으며 충돌 문제를 해결했습니다. mbsrtowcs가 Windows 문자열을 유효한 MBCS 문자열로 인식하지 못하는 문제는 여전히 존재합니다. 항상 "유효하지 않거나 불완전한 멀티 바이트 또는 와이드 문자"를 "0"위치로 반환합니다. – Zoccadoum