Skip to main content

[Unreal] 언리얼 문자열 처리 방식




UTF-16에 대해 알아보자 #

  • 문자열 처리방식은 ANSI, ASCII, EUC-KR, CP949, UTF-8 BOM, UTF-8, UTF-16 등 정말 다양하다.

  • 유니코드(Unicode)
    • 전 세계의 모든 문자를 컴퓨터에서 일관되게 표현할 수 있도록 고안된 코드 집합(표)이다.

  • 인코딩 방식이란?
    • 문자나 기호들을 컴퓨터가 이용할 수 있는 신호로 만드는 것을 말한다.
    • 즉, 문자들을 바이트열에 표현하는 방식이다.

  • 유니코드의 인코딩 방식
    • 여기에는 UTF-8, UTF-16 등이 있다.
    • ANSI, ASCII, EUC-KR, CP949 등의 인코딩 방식은 코드 표에서 원하는 문자에 해당하는 코드를 찾아 그대로 바이트열에 쓰는 방식이었다.
    • 하지만 유니코드는 똑같은 문자도 인코딩 방식에 따라 바이트열에 다르게 표현될 수 있다.
    • 먼저 유니코드 표에서 인코딩하고자 하는 문자의 코드를 찾는다.
    • 다음으로, 그 코드를 각 인코딩 방식에서 정해둔 어떤 규칙에 따라 변형시켜서 바이트열에 표현한다.

  • UTF-16 (16-bit Unicode Transformation Format)
    • 인코딩 하려는 문자가 속한 범위에 따라서 16bit 단위로 늘려가며 인코딩하는 가변 인코딩 방식이다.
    • 주로 사용되는 기본 다국어 평면 (BMP, Basic multilingual plane)에 속하는 문자들은 그대로 16bit 값으로 인코딩이 되고, 그 이상의 문자는 특별히 정해진 방식으로 32bit로 인코딩이 된다.

  • BOM(Byte Order Mark, 바이트 순서 표시)
    • 파일의 맨 앞에 붙여서, 바이트를 저장한 방식이 리틀 엔디언인지 빅 엔디언인지 전달한다.

  • 리틀 엔디언(Little Endian)빅 엔디언(Big Endian)
    • 컴퓨터는 데이터를 byte 단위로 나눠서 메모리에 저장하는데, 이 때 데이터를 메모리에 어떤 순서로 저장할 것인가(바이트 오더)를 엔디안이라고 한다.
      항목 설명 0x12345678 의 표현
      리틀 엔디언 낮은 주소에 MSB부터 저장하는 방식이다.
      (Most Significant Bit, 최상위 비트)
      0x12, 0x34, 0x56, 0x78
      빅 엔디언 낮은 주소에 LSB부터 저장하는 방식이다.
      (Least Significant Bit, 최하위 비트)
      0x78, 0x56, 0x34, 0x12



언리얼의 문자열 처리 방식 #


  • 인코딩 변환 매크로들
    • 스트링을 다양한 인코딩으로 상호 변환할 수 있는 매크로가 많이 있다.
TCHAR_TO_ANSI(str)
TCHAR_TO_OEM(str)
ANSI_TO_TCHAR(str)
TCHAR_TO_UTF8(str)
UTF8_TO_TCHAR(str)

  • 유니코드를 위한 언리얼 표준 캐릭터 타입(네이티브 유니코드 인코딩)이 바로 TCHAR 이다.
  • TEXT() 매크로를 사용해서 문자열을 지정하면 TCHAR[] 배열로 지정된다.
  • TEXT() 매크로를 지정하지 않으면, 리터럴은 ANSI 를 사용해서 인코딩되기에, 지원되는 글자가 크게 제한된다.
    • ANSI 리터럴을 FString로 전달하면 TCHAR으로의 변환하는 과정을 겪어야 하기에, TEXT()를 사용하는 편이 보다 효율적이다.
  • 언리얼 공식 문서 : 문자열 처리



FString #

  • 조작이 가능한 유일한 스트링 클래스이다.
  • TCHAR[] 배열로 만들어져있다.

  • FStringTCHAR 와의 관계
// TCHAR 배열
TCHAR LogCharArray[] = TEXT("Hello Unreal");
UE_LOG(LogTemp, Log, LogCharArray);

// TCHAR 배열을 다루는 FString 클래스 -> *연산자 붙여야 한다. 
FString LogCharString = LogCharArray;
UE_LOG(LogTemp, Log, TEXT("%s"), *LogCharString);

// FString 클래스에 *연산자를 붙이면 const TCHAR*를 받을 수 있다.   
const TCHAR* LogCharPtr = *LogCharString;

// FString 클래스 안에 있는 진짜 데이터를 끄집어내는 방법 -> 문자열 수정 가능 
TCHAR* LogCharDataPtr = LogCharString.GetCharArray().GetData();

  • 다른 타입과 FString 간의 변환
int32 IntValue = 32;
float FloatValue = 3.141592;

// Int, Float -> FString 
FString FloatIntString = FString::Printf(TEXT("Int : %d, Float : %f"), IntValue, FloatValue);
FString IntString = FString::FromInt(IntValue);
FString FloatString = FString::SanitizeFloat(FloatValue);

UE_LOG(LogTemp, Log, TEXT("%s"), *FloatIntString);
UE_LOG(LogTemp, Log, TEXT("Int : %s, Float : %s"), *IntString, *FloatString);


// FString -> Int, Float (안전하지 않으므로 주의가 필요하다.)
int32 IntValueFromString = FCString::Atoi(*IntString);
float FloatValueFromString = FCString::Atof(*FloatString);

FString FloatIntString2 = FString::Printf(TEXT("Int : %d, Float : %f"), IntValueFromString, FloatValueFromString);
UE_LOG(LogTemp, Log, TEXT("%s"), *FloatIntString2);



  • FString은 용도에 따라 FName, FText로 관리될 수 있다.

FName #

  • 에셋 관리를 위해 사용되는 문자열 체계이다. 문자를 표현하는 용도가 아닌 에셋 키를 지정하는 용도로 사용한다.
  • 대소문자를 구분하지 않고, 한 번 선언되면 변경이 불가능하다.
  • FNamePool이라는 싱글톤 자료구조가 있고, 그 안에서 FName을 해시 테이블로 관리한다.
  • 해시를 사용하므로 찾기가 매우 빠르다.
  • FName을 생성할 때는 문자열을 Key로 변환하고 전역 Pool에 있는지를 검사하는 오버헤드가 발생하므로 주의가 필요하다.
// 빈번하게 호출되는 상황 
for (int i = 0; i < 10000; i++)
{
    // FName 생성자에 문자열을 넣으면?
    // 문자열을 Key로 변환하고 전역 Pool에 있는지를 검사하는 오버헤드가 발생한다. 
    // 따라서 주의가 필요하다. 
    FName SearchInNamePool = FName(TEXT("pelvis"));

    // 이렇게 한번만 처리하도록 하는 것이 좋겠다. 
    const static FName StaticOnlyOnce(TEXT("pelvis"));
}

FText #

  • 다국어 지원을 위한 문자열 체계이다.
  • 별도의 문자열 테이블 정보가 추가로 요구된다.
  • 게임 빌드시 자동으로 다양한 국가별 언어로 변환된다.

상호 간의 변환 #

  • FString으로의 변환
from to 코드
FName FString MyName.ToString();
FText FString MyText.ToString();
언어 변환시 손실 위험 때문에 안전하지 않다.
  • FName으로의 변환
from to 코드
FString FName FName(*MyString);
FName이 대소문자 구분 없기에 손실 위험이 있다.
FText FName FText → FString → FName (직접 변환 없음)
FName이 대소문자 구분 없기에 손실 위험이 있다.
  • FText으로의 변환
from to 코드
FString FText FText::FromString(MyString);
자동 현지화 못받을 수 있다.
FName FText FText::FromName(MyName);
자동 현지화 못받을 수 있다.



References #