Сделал декодирование экранированных UTF-8 символов опциональным
This commit is contained in:
parent
3a3b6b18fd
commit
0c3287aa1b
@ -24,7 +24,7 @@ private:
|
||||
|
||||
private:
|
||||
inline void clear_internal_buffers() const;
|
||||
inline void init_from_utf8_str(const char* str);
|
||||
inline void init_from_utf8_str(const char* str, bool needUnescape);
|
||||
inline void init_from_utf16_str(const char16_t* str, byte_order byteOrder = BYTE_ORDER_LITTLE_ENDIAN);
|
||||
inline void init_from_utf32_str(const char32_t* str, byte_order byteOrder = BYTE_ORDER_LITTLE_ENDIAN);
|
||||
|
||||
@ -38,10 +38,10 @@ public:
|
||||
ustring();
|
||||
ustring(const ustring& str);
|
||||
ustring(ustring&& str);
|
||||
ustring(const char* str);
|
||||
ustring(const char* str, bool needUnescape = false);
|
||||
ustring(const char16_t* str, byte_order byteOrder = BYTE_ORDER_LITTLE_ENDIAN);
|
||||
ustring(const char32_t* str, byte_order byteOrder = BYTE_ORDER_LITTLE_ENDIAN);
|
||||
ustring(const std::string& str);
|
||||
ustring(const std::string& str, bool needUnescape = false);
|
||||
ustring(const std::wstring& str);
|
||||
explicit ustring(std::size_t n);
|
||||
|
||||
|
||||
@ -60,13 +60,13 @@ const char32_t* utf32_skip_bom(const char32_t* str);
|
||||
std::size_t significant_bits(uint32_t v);
|
||||
void utf32_strcpy_with_convert_byteorder(const char32_t* src, char32_t* dst, std::size_t num, byte_order byteOrder = BYTE_ORDER_LITTLE_ENDIAN);
|
||||
|
||||
void utf8_to_ucs4(const char* src, char32_t* dst, std::size_t symbols);
|
||||
void utf8_to_ucs4(const char* src, char32_t* dst, std::size_t symbols, bool needUnescape);
|
||||
void ucs4_to_utf8(const char32_t* src, char* dst, std::size_t symbols);
|
||||
void utf16_to_ucs4(const char16_t* src, char32_t* dst, std::size_t symbols, byte_order byteOrder = BYTE_ORDER_LITTLE_ENDIAN);
|
||||
void ucs4_to_utf16(const char32_t* src, char16_t* dst, std::size_t symbols, byte_order byteOrder = BYTE_ORDER_LITTLE_ENDIAN);
|
||||
|
||||
std::size_t utf8_str_len(const char* str);
|
||||
std::size_t utf8_get_symbol_size(const char* str);
|
||||
std::size_t utf8_str_len(const char* str, bool needUnescape);
|
||||
std::size_t utf8_get_symbol_size(const char* str, bool needUnescape);
|
||||
std::size_t utf16_str_len(const char16_t* str, byte_order byteOrder = BYTE_ORDER_LITTLE_ENDIAN);
|
||||
std::size_t utf16_get_symbol_size(const char16_t* str, byte_order byteOrder = BYTE_ORDER_LITTLE_ENDIAN);
|
||||
std::size_t utf32_str_len(const char32_t* str);
|
||||
|
||||
@ -44,12 +44,13 @@ ustring::ustring(ustring&& str): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(null
|
||||
/**
|
||||
* Конструктор из UTF-8 строки
|
||||
* @param str Исходная строка в UTF-8 (null terminated)
|
||||
* @param needUnescape Определяет нужно ли декодировать экранированные UTF-8 символы (\uXXXX и \UXXXXXXXX)
|
||||
* @detailed Так как символы ASCII являются подмножеством UTF-8, при создании строки
|
||||
* из массива ASCII символов нужно применять именно этот конструктор
|
||||
*/
|
||||
ustring::ustring(const char* str): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||||
ustring::ustring(const char* str, bool needUnescape /* = false */): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||||
{
|
||||
init_from_utf8_str(str);
|
||||
init_from_utf8_str(str, needUnescape);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,10 +76,11 @@ ustring::ustring(const char32_t* str, byte_order byteOrder /* = BYTE_ORDER_LITTL
|
||||
/**
|
||||
* Конструктор из std::string
|
||||
* @param str Исходная строка в UTF-8
|
||||
* @param needUnescape Определяет нужно ли декодировать экранированные UTF-8 символы (\uXXXX и \UXXXXXXXX)
|
||||
*/
|
||||
ustring::ustring(const std::string& str): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||||
ustring::ustring(const std::string& str, bool needUnescape /* = false */): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||||
{
|
||||
init_from_utf8_str(str.c_str());
|
||||
init_from_utf8_str(str.c_str(), needUnescape);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,13 +104,13 @@ ustring::ustring( std::size_t n ): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nu
|
||||
}
|
||||
|
||||
|
||||
void ustring::init_from_utf8_str(const char* str)
|
||||
void ustring::init_from_utf8_str(const char* str, bool needUnescape)
|
||||
{
|
||||
const char* strData = utf8_skip_bom(str);
|
||||
_len = utf8_str_len(strData);
|
||||
_len = utf8_str_len(strData, needUnescape);
|
||||
_capacity = _len;
|
||||
_pData = new char32_t[_len + 1];
|
||||
utf8_to_ucs4(strData, _pData, _len);
|
||||
utf8_to_ucs4(strData, _pData, _len, needUnescape);
|
||||
_pData[_len] = char32_t(0);
|
||||
}
|
||||
|
||||
|
||||
17
src/utf.cpp
17
src/utf.cpp
@ -113,18 +113,19 @@ char32_t invert_byte_order_32(char32_t val)
|
||||
* @param src Указатель на буфер с UTF-8 строкой (без BOM)
|
||||
* @param dst Указатель на буфер для UCS-4 строки
|
||||
* @param symbols Количество символов в строке
|
||||
* @param needUnescape Определяет нужно ли декодировать экранированные UTF-8 символы (\uXXXX и \UXXXXXXXX)
|
||||
* @throw bad_conversion Генерируется в случае ошибки декодирования (строка на входе закодирована не в UTF-8)
|
||||
* @detailed Функция поддерживает декодирование экранированных UCS-2 (\uXXXX)
|
||||
* и UCS-4 (\UXXXXXXXX) символов
|
||||
*/
|
||||
void utf8_to_ucs4(const char* src, char32_t* dst, std::size_t symbols)
|
||||
void utf8_to_ucs4(const char* src, char32_t* dst, std::size_t symbols, bool needUnescape)
|
||||
{
|
||||
std::size_t bytes = 0;
|
||||
uint32_t s = 0;
|
||||
|
||||
for(std::size_t i = 0; i < symbols; ++i)
|
||||
{
|
||||
bytes = utf8_get_symbol_size(src);
|
||||
bytes = utf8_get_symbol_size(src, needUnescape);
|
||||
s = 0;
|
||||
|
||||
if(bytes == 1) // ASCII
|
||||
@ -236,15 +237,16 @@ void ucs4_to_utf8(const char32_t* src, char* dst, std::size_t symbols)
|
||||
/**
|
||||
* Возвращает длину UTF-8 строки
|
||||
* @param str UTF-8 строка
|
||||
* @param needUnescape Определяет нужно ли декодировать экранированные UTF-8 символы (\uXXXX и \UXXXXXXXX)
|
||||
* @return Длина втроки в символах
|
||||
*/
|
||||
std::size_t utf8_str_len(const char* str)
|
||||
std::size_t utf8_str_len(const char* str, bool needUnescape)
|
||||
{
|
||||
std::size_t len = 0;
|
||||
|
||||
while(*str)
|
||||
{
|
||||
str += utf8_get_symbol_size(str);
|
||||
str += utf8_get_symbol_size(str, needUnescape);
|
||||
++len;
|
||||
}
|
||||
|
||||
@ -272,13 +274,14 @@ std::size_t ucs4_get_utf8_str_bytes(const char32_t* str)
|
||||
/**
|
||||
* Возвращает размер символа UTF-8 строки с учетом экранированных UCS-2 и UCS-4 символов
|
||||
* @param str Указатель на требуемый символ в UTF-8 строке
|
||||
* @param needUnescape Определяет нужно ли декодировать экранированные UTF-8 символы (\uXXXX и \UXXXXXXXX)
|
||||
* @return Количество байт, занимаемых символом
|
||||
*/
|
||||
std::size_t utf8_get_symbol_size(const char* str)
|
||||
std::size_t utf8_get_symbol_size(const char* str, bool needUnescape)
|
||||
{
|
||||
uint32_t s = 0;
|
||||
if(*str == '\\') // UCS unescape
|
||||
{
|
||||
if(needUnescape && *str == '\\') // UCS unescape
|
||||
{
|
||||
if(*(str + 1) == 'u')
|
||||
{
|
||||
return 6;
|
||||
|
||||
@ -92,9 +92,9 @@ const unsigned char helloResultUcs4[] = { 0x48, 0x00, 0x00, 0x00, 0x65, 0x00, 0x
|
||||
|
||||
TEST(Convert, utf8_symbol_size)
|
||||
{
|
||||
ASSERT_EQ(1, utf8_get_symbol_size((const char*)&helloStrUtf8[0]));
|
||||
ASSERT_EQ(2, utf8_get_symbol_size((const char*)&helloStrUtf8[15]));
|
||||
ASSERT_EQ(4, utf8_get_symbol_size((const char*)&helloStrUtf8[41]));
|
||||
ASSERT_EQ(1, utf8_get_symbol_size((const char*)&helloStrUtf8[0], false));
|
||||
ASSERT_EQ(2, utf8_get_symbol_size((const char*)&helloStrUtf8[15], false));
|
||||
ASSERT_EQ(4, utf8_get_symbol_size((const char*)&helloStrUtf8[41], false));
|
||||
}
|
||||
|
||||
//
|
||||
@ -114,7 +114,7 @@ TEST(Convert, utf8_symbol_size_by_ucs4_symbol)
|
||||
|
||||
TEST(Convert, utf8_length)
|
||||
{
|
||||
ASSERT_EQ(helloStrLen, utf8_str_len((const char*)helloStrUtf8));
|
||||
ASSERT_EQ(helloStrLen, utf8_str_len((const char*)helloStrUtf8, false));
|
||||
}
|
||||
|
||||
//
|
||||
@ -193,9 +193,9 @@ TEST(Convert, utf32_length)
|
||||
//
|
||||
TEST(Convert, utf8_to_ucs4)
|
||||
{
|
||||
std::size_t len = utf8_str_len((const char*)helloStrUtf8);
|
||||
std::size_t len = utf8_str_len((const char*)helloStrUtf8, false);
|
||||
char32_t* data = new char32_t[len];
|
||||
utf8_to_ucs4((const char*)helloStrUtf8, data, len);
|
||||
utf8_to_ucs4((const char*)helloStrUtf8, data, len, false);
|
||||
EXPECT_EQ(0, memcmp(helloStrUcs4, data, len*sizeof(char32_t)));
|
||||
delete[] data;
|
||||
}
|
||||
@ -274,7 +274,7 @@ TEST(Convert, ucs4_to_utf16be)
|
||||
|
||||
TEST(ConvertError, utf8_length_error)
|
||||
{
|
||||
EXPECT_THROW(utf8_str_len((const char*)badStr2Utf8), bad_conversion);
|
||||
EXPECT_THROW(utf8_str_len((const char*)badStr2Utf8, false), bad_conversion);
|
||||
}
|
||||
|
||||
//
|
||||
@ -283,9 +283,9 @@ TEST(ConvertError, utf8_length_error)
|
||||
|
||||
TEST(ConvertError, utf8_decode_error)
|
||||
{
|
||||
std::size_t len = utf8_str_len((const char*)badStrUtf8);
|
||||
std::size_t len = utf8_str_len((const char*)badStrUtf8, false);
|
||||
char32_t* data = new char32_t[len];
|
||||
EXPECT_THROW(utf8_to_ucs4((const char*)badStrUtf8, data, len), bad_conversion);
|
||||
EXPECT_THROW(utf8_to_ucs4((const char*)badStrUtf8, data, len, false), bad_conversion);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
@ -335,7 +335,15 @@ TEST(ConvertError, ucs4_wrong_symbol)
|
||||
TEST(Ustring, utf8_constructor)
|
||||
{
|
||||
ustring str((const char*)helloStrUtf8);
|
||||
ustring str2("Hello\\u0020world!", true);
|
||||
ustring str3("Hello\\u0020world!", false);
|
||||
ustring str4 = "Hello\\u0020world!";
|
||||
|
||||
|
||||
EXPECT_EQ(0, memcmp(helloStrUcs4, str.utf32_str(), sizeof(helloStrUcs4)));
|
||||
EXPECT_TRUE(str2 == "Hello world!");
|
||||
EXPECT_TRUE(str3 == "Hello\\u0020world!");
|
||||
EXPECT_TRUE(str4 == "Hello\\u0020world!");
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
4
todo
4
todo
@ -1,9 +1,9 @@
|
||||
Задачи на будущее
|
||||
|
||||
1. Сделать декодирование экранированных UCS-2 (\uXXXX) и UCS-4 (\UXXXXXXXX) символов опциональным (по умолчанию выключено), добавить соответствующий тестю
|
||||
1. Сделать декодирование экранированных UCS-2 (\uXXXX) и UCS-4 (\UXXXXXXXX) символов опциональным (по умолчанию выключено), добавить соответствующий тест.
|
||||
|
||||
2. В функции ucs4_to_utf8 добавить опциональное экранирование не-ANSI символов (по умолчанию выключено), добавить тесты.
|
||||
|
||||
3. Тестирование на android.
|
||||
3. Тестирование на android. Можно сделать в QEMU виртуальную машину с ARM процессором.
|
||||
|
||||
4. Сравнение по производительности с std::string, профилирование, оптимизация (возможно переписывание узких мест на ассемблере с использованием SIMD инструкций)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user