2012-11-26 3 views
2

파일 시스템에서 휴대용이 아닌 이름의 charcters를 검색했습니다. 이를 위해 mbtowc 함수를 사용하여 모든 문자를 검사하십시오.mbtowc는 osx에서 항상 1 바이트를 반환합니다.

는 OSX에 내가 시도 :

// 왜 모든 문자 만 1 mbtows 반환하지

#include <iostream> 

using namespace std; 

int main(int argc, const char * argv[]) 
{ 
string s1 = "Ä"; 
size_t len = s1.length();   // will be 2, ok 


const char* s1c = s1.c_str();  // 0xC3 0x84 0x00, ok 

char a = s1[0];      // 0xc3, ok 
char b = s1[1];      // 0x84, ok 

mbtowc(NULL,NULL,0);    // reset 

wchar_t wc; 
int mb_len = mbtowc(&wc,s1c,len); // mb_len = 1, wc=0xc3 00 00 00 
            // why only one byte? 
            // how can i get the right Wchar??? 
char mb2[10]; 
int mblen2 = wctomb(mb2,wc);  // mblen2 = 1; mb2 = 0xC3 

string s2 = string(mb2);   // len = 1 only 0xC3 


return 0; 
} 

OSX

에?

Heribert

답변

2

내 프로그램 ASCII (또는 불특정 ASCII 호환 8 비트 인코딩)와 같은 문자열을 처리 C 로케일에서 시작한다. 따라서 mbtowc()은 단순히 문자열의 첫 번째 바이트를 wchar_t에 복사합니다. 소스가 UTF-8로 인코딩되어 있기 때문에 문자열 상수도 마찬가지로 setlocale(LC_CTYPE, locale)에 UTF-8을 사용하는 로켈로 호출해야합니다.

setlocale(LC_CTYPE, "")은 사용자의 현재 로캘 설정을 사용하므로 사용자가 제공 한 파일을 읽는 경우에 적합합니다. 그러나 누군가가 UTF-8 로켈을 사용하지 않는 시스템에서 프로그램을 실행하려고 시도하면 예제가 손상 될 수 있습니다. 대신 UTF-8을 항상 사용하는 로케일 인 setlocale(LC_CTYPE, "UTF-8")을 사용할 수 있습니다 (표준화 된 것은 아니지만 적어도 Mac OS X 및 Linux 상자에는 제공됨).

다음은 간단한 예입니다 (C++이 아닌 순수한 C 언어의 경우). 무슨 일인지 보여주기 위해 printfs를 추가했습니다. 을 호출하기 전과 후에 모두 동일한 mbtowc()을 실행합니다.

#include <stdio.h> 
#include <locale.h> 
#include <string.h> 
#include <stdlib.h> 

void test_mbtowc(char *s) { 
    size_t len = strlen(s); 
    wchar_t wc; 

    mbtowc(NULL,NULL,0); 
    int mb_len = mbtowc(&wc,s,len); 
    printf("%d, %08x\n", mb_len, wc); 
} 

int main() 
{ 
    char *s = "Ä"; 

    printf("%02hhx %02hhx %02hhx\n", s[0], s[1], s[2]); 
    test_mbtowc(s); 

    setlocale(LC_CTYPE, "UTF-8"); 
    test_mbtowc(s); 

    return 0; 
} 

다음은 출력 결과입니다. 보시다시피 UTF-8로 인코딩 된 문자열이 있습니다. mbtowc에 대한 첫 번째 호출은 간단히 첫 번째 바이트를 복사합니다. mb_len1이며 결과적으로 c3이됩니다. 두 번째 숫자는 mb_len이고, c4이고 Ä의 유니 코드 코드 포인트는 wc입니다.

c3 84 00 
1, 000000c3 
2, 000000c4 
+0

덕분에, 여기 말했다. – user1854272

1

mbtowc()은 변환 할 인코딩을 결정하기 위해 C 로켈을 사용합니다. C 로켈은 항상 "C"으로 시작합니다. 기본 문자 집합 (ASCII로 지원되는 추상 문자 레퍼토리의 하위 집합) 외부의 문자는 지원되지 않을 수 있습니다.

OS X은 기본적으로 다른 모든 곳에서 UTF-8을 사용하므로 mbtowc()은 예상 한 인코딩간에 변환하지 않습니다.

C 로캘을 적절한 인코딩을 사용하는 것으로 설정할 수 있습니다. 당신은 C++ 프로그램에서이 작업을 수행 할 경우에 당신은 (다시 C 로케일을 설정합니다)를 C++ 글로벌 로케일을 설정하여 그것을 아마해야하지만 로케일 덤비는

std::locale::global(std::locale("en_US.UTF-8")); // locale names are not portable 

하는 것은 일반적으로 좋은 일이 아니다. 전역 로케일은 본질적으로 전역 변수이며이를 사용하는 모든 정상적인 이유가 있습니다. 다양한 효과가 있습니다. 특정 로케일에 설정되지 않은 경우에 따라 달라질 수있는 라이브러리의 일부분에 sprintf()의 일부 사용을 적용 할 수 있습니다. 또한 로케일에 민감한 함수는 스레드로부터 안전하지 않고 재진입 할 ​​수 없습니다.

OS X에는 글로벌 로켈을 사용하는 대신 추가 로캘 매개 변수를 사용하는 로캘 감지 기능의 *_l 버전이있는 '확장 로캘 지원'라이브러리 (헤더 <xlocale.h>)가 있습니다. 이것은 글로벌 로케일의 많은 문제점을 수정합니다. 당신은 당신이 모든 로케일을 사용하지 않아도 알려진 인코딩 사이의 변환해야하는 경우도 OS X에

locale_t loc = newlocale(LC_ALL_MASK, "en_US.UTF-8", NULL); 
char buf[MB_CUR_MAX_L(loc)]; 
mbstate_t state = {}; 
wcrtomb_l(buf, L'A', &state, loc); 
freelocale(loc); 

에 표준 C++ 로케일 많은 기능을 구현하는 데 사용 믿습니다. iconv는 대량의 인코딩간에 직접 변환을 허용하는 API입니다. C++은 다양한 유니 인코딩 (UTF-8, UTF-16, 및 UTF-32)를 wstring_convert 템플릿을 이용하여 일부 기준 codecvt 패싯 (codecvt_utf8, codecvt_utf8_utf16) 사이, 특히, 특정 인코딩 간의 변환을 지원한다. 또한 codecvt_byname이 로케일과 직접 덤비는없이 charwchar_t 로케일 인코딩 사이의 변환을 적용 할 수 있습니다.


당연히 모든 인코딩은 인코딩간에 변환해야하는 경우에만 중요합니다. 그것은 단지 '휴대용이 아닌 이름의 charcters를 찾기 위해 파일 시스템에서 검색하는 것이 필요하다는 것은 분명하지 않습니다.' 법적 (또는 불법적 인 목록)이라고 생각되는 코드 포인트 목록이있는 경우 UTF-8 문자열에서 해당 코드 포인트의 UTF-8 인코딩을 직접 검색하면 변환이 필요하지 않습니다. 이 문제였다

+0

고마워, 내가 이런 식으로 사용할거야. – user1854272

+0

localied extension은 다른 시스템에서도 사용할 수 있습니다. (Visula Studio 2010 : 이름 앞에 '_'가 붙음). MB_CUR_MAX는 현재 콘솔에 의존합니다. 프로그램이 시작되면 consloe가 C가되고 값은 1이되어 버퍼 오버런이 발생합니다. MB_LEN_MAX는 모든 인코딩에 대해 최대 길이를 반환합니다 (대부분 6). – user1854272

+0

@ user1854272 예, 여러분은'MB_CUR_MAX'에 대해 맞습니다. '_l' 함수와 함께 사용할 매크로'MB_CUR_MAX_L() '이 있습니다. – bames53

관련 문제