227 lines
5.4 KiB
C++
227 lines
5.4 KiB
C++
// Copyright (C) 2017 Jérôme Leclercq
|
|
// This file is part of the "Nazara Engine - Core module"
|
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
|
|
|
#include <Nazara/Core/StringExt.hpp>
|
|
#include <Nazara/Core/Algorithm.hpp>
|
|
#include <Utfcpp/utf8.h>
|
|
#include <Nazara/Core/Debug.hpp>
|
|
|
|
namespace Nz
|
|
{
|
|
namespace
|
|
{
|
|
bool IsSpace(char32_t character)
|
|
{
|
|
return character == '\t' || Unicode::GetCategory(character) & Unicode::Category_Separator;
|
|
}
|
|
|
|
char ToLower(char character)
|
|
{
|
|
if (character >= 'A' && character <= 'Z')
|
|
return character + ('a' - 'A');
|
|
else
|
|
return character;
|
|
}
|
|
|
|
char ToUpper(char character)
|
|
{
|
|
if (character >= 'a' && character <= 'z')
|
|
return character + ('A' - 'a');
|
|
else
|
|
return character;
|
|
}
|
|
|
|
template<std::size_t S>
|
|
struct WideConverter
|
|
{
|
|
static std::string From(const wchar_t* wstr, std::size_t size)
|
|
{
|
|
if constexpr (S == 2)
|
|
{
|
|
// UTF-16 (Windows)
|
|
return FromUtf16String(std::u16string_view(reinterpret_cast<const char16_t*>(wstr), size));
|
|
}
|
|
else if constexpr (S == 4)
|
|
{
|
|
// UTF-32 (Linux)
|
|
return FromUtf32String(std::u32string_view(reinterpret_cast<const char32_t*>(wstr), size));
|
|
}
|
|
else
|
|
{
|
|
static_assert(AlwaysFalse<std::integral_constant<std::size_t, S>>::value, "Unsupported platform");
|
|
return std::string("<platform error>");
|
|
}
|
|
}
|
|
|
|
static std::wstring To(const std::string_view& str)
|
|
{
|
|
if constexpr (S == 2)
|
|
{
|
|
std::wstring result;
|
|
utf8::utf8to16(str.begin(), str.end(), std::back_inserter(result));
|
|
|
|
return result;
|
|
}
|
|
else if constexpr (S == 4)
|
|
{
|
|
std::wstring result;
|
|
utf8::utf8to32(str.begin(), str.end(), std::back_inserter(result));
|
|
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
static_assert(AlwaysFalse<std::integral_constant<std::size_t, S>>::value, "Unsupported platform");
|
|
return std::wstring(L"<platform error>");
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
std::string FromUtf16String(const char16_t* u16str)
|
|
{
|
|
std::size_t size = std::char_traits<char16_t>::length(u16str);
|
|
return FromUtf16String(std::u16string_view(u16str, size));
|
|
}
|
|
|
|
std::string FromUtf16String(const std::u16string_view& u16str)
|
|
{
|
|
std::string result;
|
|
utf8::utf16to8(u16str.begin(), u16str.end(), std::back_inserter(result));
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string FromUtf32String(const char32_t* u32str)
|
|
{
|
|
std::size_t size = std::char_traits<char32_t>::length(u32str);
|
|
return FromUtf32String(std::u32string_view(u32str, size));
|
|
}
|
|
|
|
std::string FromUtf32String(const std::u32string_view& u32str)
|
|
{
|
|
std::string result;
|
|
utf8::utf32to8(u32str.begin(), u32str.end(), std::back_inserter(result));
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string FromWideString(const wchar_t* wstr)
|
|
{
|
|
std::size_t size = std::char_traits<wchar_t>::length(wstr);
|
|
return WideConverter<sizeof(wchar_t)>::From(wstr, size);
|
|
}
|
|
|
|
std::string FromWideString(const std::wstring_view& wstr)
|
|
{
|
|
return WideConverter<sizeof(wchar_t)>::From(wstr.data(), wstr.size());
|
|
}
|
|
|
|
bool StartsWith(const std::string_view& str, const std::string_view& s, CaseIndependent)
|
|
{
|
|
if (s.size() > str.size())
|
|
return false;
|
|
|
|
return std::equal(str.begin(), str.begin() + s.size(), s.begin(), s.end(), [](char c1, char c2)
|
|
{
|
|
return ToLower(c1) == ToLower(c2);
|
|
});
|
|
}
|
|
|
|
bool StartsWith(const std::string_view& str, const std::string_view& s, CaseIndependent, UnicodeAware)
|
|
{
|
|
if (str.empty() || s.empty())
|
|
return str == s;
|
|
|
|
utf8::iterator<const char*> it(str.data(), str.data(), str.data() + str.size());
|
|
utf8::iterator<const char*> it2(s.data(), s.data(), s.data() + s.size());
|
|
do
|
|
{
|
|
if (it2.base() >= s.data() + s.size())
|
|
return true;
|
|
|
|
if (Unicode::GetLowercase(*it) != Unicode::GetLowercase(*it2))
|
|
return false;
|
|
|
|
++it2;
|
|
}
|
|
while (*it++);
|
|
|
|
return true;
|
|
}
|
|
|
|
std::string ToLower(const std::string_view& str)
|
|
{
|
|
std::string result;
|
|
result.reserve(str.size());
|
|
std::transform(str.begin(), str.end(), std::back_inserter(result), Overload<char>(ToLower));
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string ToLower(const std::string_view& str, UnicodeAware)
|
|
{
|
|
if (str.empty())
|
|
return std::string();
|
|
|
|
std::string result;
|
|
result.reserve(str.size());
|
|
|
|
utf8::unchecked::iterator<const char*> it(str.data());
|
|
do
|
|
utf8::append(Unicode::GetLowercase(*it), std::back_inserter(result));
|
|
while (*++it);
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string ToUpper(const std::string_view& str)
|
|
{
|
|
std::string result;
|
|
result.reserve(str.size());
|
|
std::transform(str.begin(), str.end(), std::back_inserter(result), Overload<char>(ToUpper));
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string ToUpper(const std::string_view& str, UnicodeAware)
|
|
{
|
|
if (str.empty())
|
|
return std::string();
|
|
|
|
std::string result;
|
|
result.reserve(str.size());
|
|
|
|
utf8::iterator<const char*> it(str.data(), str.data(), str.data() + str.size());
|
|
do
|
|
utf8::append(Unicode::GetUppercase(*it), std::back_inserter(result));
|
|
while (*++it);
|
|
|
|
return result;
|
|
}
|
|
|
|
std::u16string ToUtf16String(const std::string_view& str)
|
|
{
|
|
std::u16string result;
|
|
utf8::utf8to16(str.begin(), str.end(), std::back_inserter(result));
|
|
|
|
return result;
|
|
}
|
|
|
|
std::u32string ToUtf32String(const std::string_view& str)
|
|
{
|
|
std::u32string result;
|
|
utf8::utf8to32(str.begin(), str.end(), std::back_inserter(result));
|
|
|
|
return result;
|
|
}
|
|
|
|
std::wstring ToWideString(const std::string_view& str)
|
|
{
|
|
return WideConverter<sizeof(wchar_t)>::To(str);
|
|
}
|
|
}
|
|
|
|
#include <Nazara/Core/DebugOff.hpp>
|