FString 문자열 처리
FString에서는 자체적으로 다양한 기능을 제공 해주는데, 데이터를 자르거나 붙이거나 새로운 방식으로 불러 들이거나, 다양한 연산이 가능하다.
또한, FString이 제공하는 함수에서 내부적으로 FCString이라는 Wrapper Class가 있는데,
C라이브러리에서 제공하는 기본적인 스트링 관련 함수를 가지고 있다.
그래서, FString은 데이터를 보관하지만, 실제 문자열을 찾거나 자르거나 이런 처리들은 FCString을 통해 처리 한다.
FString 활용
코드와 주석 참조
#include "MyGameInstance.h"
void UMyGameInstance::Init()
{
Super::Init();
static const TCHAR LogCharArray[] = TEXT("Hello Unreal");
UE_LOG(LogTemp, Log, LogCharArray);
//출력 : Hello Unreal
//%s와 대응될 때는 TCHAR의 포인터 어레이를 반환해 줘야 하는데 FString을 그대로 쓰면, TCHAR 포인터가 반환 되지않는다.
//그래서 * 을 붙여서 포인터 연산자를 지정해주면 된다.
FString LogCharString = LogCharArray;
UE_LOG(LogTemp, Log, *LogCharString);
//출력 : Hello Unreal
//기본적으로 FString을 다시 TCHAR로 변환하고 싶다하면 const형태로 바꾸지않는걸로 받아온다.
const TCHAR* LongCharPtr = *LogCharString;
//근데 FString을 직접 포인터로 받아와서 값을 바꾸고 싶다면 FString이 관리하고있는 TArray에 첫 인자인 포인터를 가져와야 한다.
TCHAR* LogCharDataPtr = LogCharString.GetCharArray().GetData();
//만약에 다시 배열로 가져오고 싶다면
TCHAR LogCharArrayWithSize[100];
FCString::Strcpy(LogCharArrayWithSize, LogCharString.Len(), *LogCharString);
//Hello Unreal 에서 Unreal만 추출
if (LogCharString.Contains(TEXT("unreal"), ESearchCase::IgnoreCase)) // 대소문자 상관없이 포함하고있는지
{
int32 Index = LogCharString.Find(TEXT("unreal"), ESearchCase::IgnoreCase);
FString EndString = LogCharString.Mid(Index);
UE_LOG(LogTemp, Log, TEXT("Find Test: %s"), *EndString);
// 출력 : Find Test: Unreal
}
//공백을 기준으로 왼쪽 오른쪽으로 자르기 Left = Hello , Right = Unreal 저장
FString Left, Right;
if (LogCharString.Split(TEXT(" "), &Left, &Right))
{
UE_LOG(LogTemp, Log, TEXT("Split Test: %s 와 %s"), *Left, *Right);
// 출력 : Split Test: Hello 와 Unreal
// 여기서 와 라는 한글이 제대로 출력되지않고 이상한 기호로 나타난다면,
// visual studio에서 save as 후 Save 밑에 Save with Encoding 에서
//Uncode(UTF-8 with signature) 로 변경해서 저장해주면 제대로 나타날 것이다.
}
//int,float -> FString으로 변환
int32 IntValue = 32;
float FloatValue = 3.141592;
FString FloatIntString = FString::Printf(TEXT("Int:%d Float:%f"), IntValue, FloatValue);
//Float단일 변환
FString FloatString = FString::SanitizeFloat(FloatValue);
//int단일 변환
FString IntString = FString::FromInt(IntValue);
UE_LOG(LogTemp, Log, TEXT("%s"), *FloatIntString);
//출력 :Int:32 Float:3.141592
UE_LOG(LogTemp, Log, TEXT("Int:%s Float:%s"), *IntString,*FloatString);
//출력 :Int:32 Float:3.141592
//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);
//출력 :Int:32 Float:3.141592
}
FName
- FString으로 문자열 관리를 하는데 FName으로 변환하여 다양한 용도로 사용 할 수있다.
-> 우리가 어떤 asset을 빠르게 찾고 싶을 때, string으로 저장하여 찾게 되면 비교하여 찾으니 오래 걸린다. 그래서, 문자열을 사용하지만 내부적으로 해시값을 사용해서 바로바로 찾을 수 있게 만들어 준다.
-> 그래서 Key,Value 쌍으로 빠르게 우리가 asset을 찾을 수 있게 한다.
-> Key로 변환되기에 int로 저장된다.
-> FString -> FName 으로 변환할때 대소문자를 구분하지 않기에 다시 FName-> FString으로 변환하게 되면 대소문자를 구분하지 않기에 데이터가 손실 된다.
FName은 FNamePool 이라하는 싱글톤이로 되어 있는 글로벌 Pool 자료구조를 가지고 있다.
FName의 형성
흐름
1. HELLO 라는 문자열 저장
2. FName에서는 문자열을 어딘가 따로 저장을 하고 문자열을 변환한 해시 값과 key값이 저장
3. 이 key값을 사용해서 Pool에 있는지 없는지 빠르게 검출
4. Pool에 있으면 검출 후 우리가 원하는 데이터를 가져오는 형태로 구성
- 그래서 실제로는 key값만 들어가 있기 때문에 용량이 굉장히 작다
FName key1(TEXT("GHOSTORY"));
FName key2(TEXT("ghostory"));
UE_LOG(LogTemp, Log,TEXT("FName 비교 결과 : %s"), key1 == key2 ? TEXT("같음") : TEXT("다름"));
//출력 : FName 비교 결과 : 같음
//빈번하게 호출 될때를 가정
for(int i=0; i< 10000; ++i)
{
//이렇게 생성자에 문자열을 넣으면, FName이 문자열을 key로 변환한 다음에
//이 key가 전역 Pool에 있는지를 조사하는 작업을 거친다.
//그래서 이렇게 구현을 하면 빈번하게 씬마다 호출된다 가정하면 오버헤드가 일어난다.
FName SearchInNamePool = FName(TEXT("ghostory"));
//이렇게 한번만 처리하게 해주는게 좋다.
//처음 초기화 할때 데이터를 저장하고 local static 으로 선언했으니 이걸 찾을 일이 없다.
//이 자체를 쓰면 되기 때문에 효과적이다.
const static FName StaticOnlyOnce(TEXT("ghostory"));
}