반응형

초창기 컴퓨터는 ASCII 문자 인코딩 방식을 사용

128개의 문자 표현가능한 7비트로 알파벳 / 숫자 / 기본기호 등만 사용가능하였다.

하지만 한글 일본어 독일어 프랑스어 특수문자 같은 문자들을 표현할 수 없었다.

 

그래서 컴퓨터는 8비트를 쓰니까 남는 1비트도 추가하여 확장 ASCII라는것을 만들어 256개 문자 표현이 가능해졌다.

하지만 이 128~255 영역은 표준화 되지않아서 여러버전이 생겼다.

 

Windows 에서 쓰던 8비트 확장 ASCII 인코딩이 ANIS 이다.

 

 

또한 한국 중국 일본어는 글자수가 많아서 각자 다른 인코딩을 사용했었다.

ASCII 영역은 그대로 1바이트를 유지하되, 한자/한글 등은 2바이트를 사용하기로 하였다.

한국 [EUC-KR / CP949 (Windows-949)]

일본 [Shift_JIS / EUC-JP]

중국 [GB2312 / Big5]

 

 

유니코드

1991년에서야 등장한 전 세계 문자를 하나의 코드 체계로 통합한 국제 표준 문자 번호 체계

16bit / 32bit 전 세계 문자를 컴퓨터에서 일관되게 나타내고 처리

 

유니코드는 문자번호 체계이고 실제 저장방식은 UTF 인코딩

 

현재 정의되어있는 유니코드 범위

U+0000 ~ U+10FFFF

 

초기 유니코드는 2^16 = 65536 로 설계되었지만 문자가 부족하게되어 범위를 확장하였지만 이미 전세계 시스템이 16비트 기반으로 돌아가고있어서  Surrogate Pair 라는것을 사용하여 16비트 2개로 표현

 

[U+0000 ~ U+FFFF] BMP - Basic Multilingual Plane    

[U+10000 ~ U+10FFFF] BMP 밖 - Supplementary Planes  (ex 이모티콘이나 중국어 확장형)

 

BMP 영역은 16비트 1개로 UTF-16 (uint16) 으로 표현이 가능하지만

BMP 밖 영역은 16비트가 2개 필요함 혹은 UTF-32 (uin32) 하나로 표현 가능

 

[U+D800 ~ U+DFFF]   (2048개) - Surrogate Pair

해당영역은 UTF-16 인코딩 예약 영역으로 유니코드 문자가 할당되어있지 않는다.

즉, 단독으로 등장하면 잘못된 것  ->  잘못된 유니코드가 들어왔을 때 대신 표시하는 대체문자 � 가 나온다.

 

 

 

언리얼에서는 Surrogate Pair 영역인지, 유효한 유니코드인지 확인하는 파일이 StringConv.h 에 있다.

또한 Supplementary Planes 영역 유니코드를 제대로 출력하기위한 TUTF32ToUTF16_Convert 이런것도 같이 있다.

또한 언리얼에서 UnicodeBlockRange.inl 파일에서 정의되어있는 블록을 가져와서 범위안에있는지 살펴볼 수 있다.

 

예시)

// 문자열을 Unicode List로 바꿔주는 예시
TArray<UTF32CHAR> ULocalizationLibrary::ConvertStringToUnicodeList(const FString& String)
{
	// BMP 외 문자 인식을 위해 UTF-16(TCHAR*) -> UTF-32 변환
	TArray<UTF32CHAR> Utf32Buffer;
	Utf32Buffer.SetNumUninitialized(TUTF16ToUTF32_Convert<TCHAR, UTF32CHAR>::ConvertedLength(*String, String.Len()));
	TUTF16ToUTF32_Convert<TCHAR, UTF32CHAR>::Convert(Utf32Buffer.GetData(), Utf32Buffer.Num(), *String, String.Len());
    
    #if !UE_BUILD_SHIPPING
	FString DebugString;
	DebugString.Reserve(Utf32Buffer.Num() * 8);

	for (int32 i = 0; i < Utf32Buffer.Num(); ++i)
	{
		DebugString += FString::Printf(TEXT("U+%04X"), static_cast<uint32>(Utf32Buffer[i]));
		if (i + 1 < Utf32Buffer.Num())
			DebugString += TEXT(" ");
	}

	UE_LOG(ZLogFramework, Log, TEXT("[%s] OriginString: [%s]"), Z_FUNCTIONW, *String);
	UE_LOG(ZLogFramework, Log, TEXT("[%s] UnicodeList: [%s]"), Z_FUNCTIONW, *DebugString);
#endif

	return Utf32Buffer;
}

// Unicode 를 문자로 바꾸어주는 예시
FString ULocalizationLibrary::UnicodeToString(UTF32CHAR Unicode)
{
	FString Out; 

	if (!StringConv::IsValidCodepoint(Unicode))
	{
		return Out;
	}

	// BMP & surrogate 영역 제외
	if (Unicode <= static_cast<UTF32CHAR>(MAX_uint16) 
		&& !StringConv::IsHighSurrogate(Unicode) && !StringConv::IsLowSurrogate(Unicode))
	{
		Out.AppendChar(static_cast<TCHAR>(Unicode));
		return Out;
	}

	TCHAR Buf[2];
	const int32 Written =TUTF32ToUTF16_Convert<uint32, TCHAR>::Utf16FromCodepoint(static_cast<uint32>(Unicode), Buf, UE_ARRAY_COUNT(Buf));

	Out.AppendChars(Buf, Written);
	return Out;
}


bool ULocalizationLibrary::IsHangulSyllables(UTF32CHAR Unicode)
{
	const FInt32Range Range = FUnicodeBlockRange::GetUnicodeBlockRange(EUnicodeBlockRange::HangulSyllables).GetRange();
	return Range.Contains(Unicode);
}

bool ULocalizationLibrary::IsCJKIdeograph(UTF32CHAR Unicode)
{
	const FInt32Range Range = FUnicodeBlockRange::GetUnicodeBlockRange(EUnicodeBlockRange::CJKUnifiedIdeographs).GetRange();
	return Range.Contains(Unicode);
}

bool ULocalizationLibrary::IsEmoticonsEmoji(UTF32CHAR Unicode)
{
	const FInt32Range Range = FUnicodeBlockRange::GetUnicodeBlockRange(EUnicodeBlockRange::EmoticonsEmoji).GetRange();
	return Range.Contains(Unicode);
}

 

보통 한자를 사용하려면 CJKUnifiedIdeographs 를 사용하는데 중국 간체 / 번체, 일본 신자체, 한국 한자 등을 다 따로 코드를 주면 낭비라서 묶었다고 한다.

 

혹은 확장형A 까지는 CJKUnifiedIdeographsExtensionA 허용한다는데 이것도 BMP 영역안이라서 허용한다고 하는듯

반응형

'이론' 카테고리의 다른 글

비트 연산자  (0) 2025.04.09
앱 식별자 용어  (0) 2025.02.10
캐시 메모리 (Cache Memory)  (1) 2023.03.04
의존성 제어  (0) 2022.12.20
Solid  (0) 2022.11.06

+ Recent posts