4372 lines
90 KiB
C++
4372 lines
90 KiB
C++
// Copyright (C) 2015 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
|
|
|
|
///TODO: Réécrire une bonne partie des algorithmes employés (Relu jusqu'à 3538)
|
|
|
|
#include <Nazara/Core/String.hpp>
|
|
#include <Nazara/Core/AbstractHash.hpp>
|
|
#include <Nazara/Core/Config.hpp>
|
|
#include <Nazara/Core/Error.hpp>
|
|
#include <Nazara/Core/Unicode.hpp>
|
|
#include <Nazara/Math/Algorithm.hpp>
|
|
#include <algorithm>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <limits>
|
|
#include <sstream>
|
|
#include <Utfcpp/utf8.h>
|
|
#include <Nazara/Core/Debug.hpp>
|
|
|
|
// Cet algorithme est inspiré de la documentation de Qt
|
|
inline unsigned int nzGetNewSize(unsigned int newSize)
|
|
{
|
|
if (newSize < 20)
|
|
return newSize+4;
|
|
else
|
|
{
|
|
if (newSize < (1 << 12)-12)
|
|
return NzGetNearestPowerOfTwo(newSize << 1)-12;
|
|
else
|
|
return newSize + (1 << 11);
|
|
}
|
|
}
|
|
|
|
inline char nzToLower(char character)
|
|
{
|
|
if (character >= 'A' && character <= 'Z')
|
|
return character + ('a' - 'A');
|
|
else
|
|
return character;
|
|
}
|
|
|
|
inline char nzToUpper(char character)
|
|
{
|
|
if (character >= 'a' && character <= 'z')
|
|
return character + ('A' - 'a');
|
|
else
|
|
return character;
|
|
}
|
|
|
|
inline int nzStrcasecmp(const char* s1, const char* s2)
|
|
{
|
|
int ret = 0;
|
|
|
|
while (!(ret = static_cast<unsigned char>(nzToLower(*s1)) - static_cast<unsigned char>(nzToLower(*s2))) && *s2)
|
|
++s1, ++s2;
|
|
|
|
return ret != 0 ? (ret > 0 ? 1 : -1) : 0;
|
|
}
|
|
|
|
inline int nzUnicodecasecmp(const char* s1, const char* s2)
|
|
{
|
|
int ret = 0;
|
|
utf8::unchecked::iterator<const char*> it1(s1);
|
|
utf8::unchecked::iterator<const char*> it2(s2);
|
|
|
|
while (!(ret = NzUnicode::GetLowercase(*it1) - NzUnicode::GetLowercase(*it2)) && *it2)
|
|
++it1, ++it2;
|
|
|
|
return ret != 0 ? (ret > 0 ? 1 : -1) : 0;
|
|
}
|
|
|
|
NzString::NzString() :
|
|
m_sharedString(&emptyString)
|
|
{
|
|
}
|
|
|
|
NzString::NzString(char character)
|
|
{
|
|
if (character != '\0')
|
|
{
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = 1;
|
|
m_sharedString->size = 1;
|
|
m_sharedString->string = new char[2];
|
|
m_sharedString->string[0] = character;
|
|
m_sharedString->string[1] = '\0';
|
|
}
|
|
else
|
|
m_sharedString = &emptyString;
|
|
}
|
|
|
|
NzString::NzString(unsigned int rep, char character)
|
|
{
|
|
if (rep > 0)
|
|
{
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = rep;
|
|
m_sharedString->size = rep;
|
|
m_sharedString->string = new char[rep+1];
|
|
|
|
if (character != '\0')
|
|
std::memset(m_sharedString->string, character, rep);
|
|
|
|
m_sharedString->string[rep] = '\0';
|
|
}
|
|
else
|
|
m_sharedString = &emptyString;
|
|
}
|
|
|
|
NzString::NzString(unsigned int rep, const char* string) :
|
|
NzString(rep, string, (string) ? std::strlen(string) : 0)
|
|
{
|
|
}
|
|
|
|
NzString::NzString(unsigned int rep, const char* string, unsigned int length)
|
|
{
|
|
unsigned int totalSize = rep*length;
|
|
|
|
if (totalSize > 0)
|
|
{
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = totalSize;
|
|
m_sharedString->size = totalSize;
|
|
m_sharedString->string = new char[totalSize+1];
|
|
|
|
for (unsigned int i = 0; i < rep; ++i)
|
|
std::memcpy(&m_sharedString->string[i*length], string, length);
|
|
|
|
m_sharedString->string[totalSize] = '\0';
|
|
}
|
|
else
|
|
m_sharedString = &emptyString;
|
|
}
|
|
|
|
NzString::NzString(unsigned int rep, const NzString& string) :
|
|
NzString(rep, string.m_sharedString->string, string.m_sharedString->size)
|
|
{
|
|
}
|
|
|
|
NzString::NzString(const char* string) :
|
|
NzString(string, (string) ? std::strlen(string) : 0)
|
|
{
|
|
}
|
|
|
|
NzString::NzString(const char* string, unsigned int length)
|
|
{
|
|
if (length > 0)
|
|
{
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = length;
|
|
m_sharedString->size = length;
|
|
m_sharedString->string = new char[length+1];
|
|
std::memcpy(m_sharedString->string, string, length);
|
|
m_sharedString->string[length] = '\0';
|
|
}
|
|
else
|
|
m_sharedString = &emptyString;
|
|
}
|
|
|
|
NzString::NzString(const std::string& string)
|
|
{
|
|
if (string.size() > 0)
|
|
{
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = string.capacity();
|
|
m_sharedString->size = string.size();
|
|
m_sharedString->string = new char[string.capacity()+1];
|
|
std::memcpy(m_sharedString->string, string.c_str(), string.size()+1);
|
|
}
|
|
else
|
|
m_sharedString = &emptyString;
|
|
}
|
|
|
|
NzString::NzString(const NzString& string) :
|
|
m_sharedString(string.m_sharedString)
|
|
{
|
|
if (m_sharedString != &emptyString)
|
|
m_sharedString->refCount++;
|
|
}
|
|
|
|
NzString::NzString(NzString&& string) noexcept :
|
|
m_sharedString(string.m_sharedString)
|
|
{
|
|
string.m_sharedString = &emptyString;
|
|
}
|
|
|
|
NzString::NzString(SharedString* sharedString) :
|
|
m_sharedString(sharedString)
|
|
{
|
|
}
|
|
|
|
NzString::~NzString()
|
|
{
|
|
ReleaseString();
|
|
}
|
|
|
|
NzString& NzString::Append(char character)
|
|
{
|
|
return Insert(m_sharedString->size, character);
|
|
}
|
|
|
|
NzString& NzString::Append(const char* string)
|
|
{
|
|
return Insert(m_sharedString->size, string);
|
|
}
|
|
|
|
NzString& NzString::Append(const char* string, unsigned int length)
|
|
{
|
|
return Insert(m_sharedString->size, string, length);
|
|
}
|
|
|
|
NzString& NzString::Append(const NzString& string)
|
|
{
|
|
return Insert(m_sharedString->size, string);
|
|
}
|
|
|
|
void NzString::Clear(bool keepBuffer)
|
|
{
|
|
if (keepBuffer)
|
|
{
|
|
EnsureOwnership(true);
|
|
m_sharedString->size = 0;
|
|
}
|
|
else
|
|
ReleaseString();
|
|
}
|
|
|
|
bool NzString::Contains(char character, int start, nzUInt32 flags) const
|
|
{
|
|
return Find(character, start, flags) != npos;
|
|
}
|
|
|
|
bool NzString::Contains(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
return Find(string, start, flags) != npos;
|
|
}
|
|
|
|
bool NzString::Contains(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
return Find(string, start, flags) != npos;
|
|
}
|
|
|
|
unsigned int NzString::Count(char character, int start, nzUInt32 flags) const
|
|
{
|
|
if (character == '\0' || m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return 0;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
unsigned int count = 0;
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char character_lower = nzToLower(character);
|
|
char character_upper = nzToUpper(character);
|
|
do
|
|
{
|
|
if (*str == character_lower || *str == character_upper)
|
|
count++;
|
|
}
|
|
while (*++str);
|
|
}
|
|
else
|
|
{
|
|
while ((str = std::strchr(str, character)))
|
|
{
|
|
count++;
|
|
str++;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::Count(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return 0;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
unsigned int count = 0;
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
const char* t = string;
|
|
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
++it;
|
|
|
|
utf8::unchecked::iterator<const char*> it2(t);
|
|
while (true)
|
|
{
|
|
if (*it2 == '\0')
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
|
|
if (*it == '\0')
|
|
return count;
|
|
|
|
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
|
|
break;
|
|
|
|
++it;
|
|
++it2;
|
|
}
|
|
}
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
char c = nzToLower(string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*str) == c)
|
|
{
|
|
str++;
|
|
|
|
const char* ptr = &string[1];
|
|
while (true)
|
|
{
|
|
if (*ptr == '\0')
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
|
|
if (*str == '\0')
|
|
return count;
|
|
|
|
if (nzToLower(*str) != nzToLower(*ptr))
|
|
break;
|
|
|
|
ptr++;
|
|
str++;
|
|
}
|
|
}
|
|
}
|
|
while (*++str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while ((str = std::strstr(str, string)))
|
|
{
|
|
count++;
|
|
str++;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::Count(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
return Count(string.m_sharedString->string, start, flags);
|
|
}
|
|
|
|
unsigned int NzString::CountAny(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return 0;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
unsigned int count = 0;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == NzUnicode::GetLowercase(*it2))
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (*++str);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
do
|
|
{
|
|
if (*it == *it2)
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (*++str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
const char* c = string;
|
|
do
|
|
{
|
|
if (nzToLower(*str) == nzToLower(*c))
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (*++str);
|
|
}
|
|
else
|
|
{
|
|
while ((str = std::strpbrk(str, string)))
|
|
{
|
|
count++;
|
|
str++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::CountAny(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
return CountAny(string.m_sharedString->string, start, flags);
|
|
}
|
|
|
|
bool NzString::EndsWith(char character, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
if (flags & CaseInsensitive)
|
|
return nzToLower(m_sharedString->string[m_sharedString->size-1]) == nzToLower(character);
|
|
else
|
|
return m_sharedString->string[m_sharedString->size-1] == character; // character == '\0' sera toujours faux
|
|
}
|
|
|
|
bool NzString::EndsWith(const char* string, nzUInt32 flags) const
|
|
{
|
|
return EndsWith(string, std::strlen(string), flags);
|
|
}
|
|
|
|
bool NzString::EndsWith(const char* string, unsigned int length, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0 || length > m_sharedString->size)
|
|
return false;
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
return nzUnicodecasecmp(&m_sharedString->string[m_sharedString->size - length], string) == 0;
|
|
else
|
|
return nzStrcasecmp(&m_sharedString->string[m_sharedString->size - length], string) == 0;
|
|
}
|
|
else
|
|
return std::strcmp(&m_sharedString->string[m_sharedString->size - length], string) == 0;
|
|
}
|
|
|
|
bool NzString::EndsWith(const NzString& string, nzUInt32 flags) const
|
|
{
|
|
return EndsWith(string.m_sharedString->string, string.m_sharedString->size, flags);
|
|
}
|
|
|
|
unsigned int NzString::Find(char character, int start, nzUInt32 flags) const
|
|
{
|
|
if (character == '\0' || m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char ch = nzToLower(character);
|
|
const char* str = m_sharedString->string;
|
|
do
|
|
{
|
|
if (nzToLower(*str) == ch)
|
|
return static_cast<unsigned int>(str - m_sharedString->string);
|
|
}
|
|
while (*++str);
|
|
|
|
return npos;
|
|
}
|
|
else
|
|
{
|
|
char* ch = std::strchr(&m_sharedString->string[pos], character);
|
|
if (ch)
|
|
return static_cast<unsigned int>(ch - m_sharedString->string);
|
|
else
|
|
return npos;
|
|
}
|
|
}
|
|
|
|
unsigned int NzString::Find(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
const char* t = string;
|
|
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
const char* ptrPos = it.base();
|
|
++it;
|
|
|
|
utf8::unchecked::iterator<const char*> it2(t);
|
|
while (true)
|
|
{
|
|
if (*it2 == '\0')
|
|
return static_cast<unsigned int>(ptrPos - m_sharedString->string);
|
|
|
|
if (*it == '\0')
|
|
return npos;
|
|
|
|
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
|
|
break;
|
|
|
|
++it;
|
|
++it2;
|
|
}
|
|
}
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
char c = nzToLower(string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*str) == c)
|
|
{
|
|
char* ptrPos = str;
|
|
str++;
|
|
|
|
const char* ptr = &string[1];
|
|
while (true)
|
|
{
|
|
if (*ptr == '\0')
|
|
return static_cast<unsigned int>(ptrPos - m_sharedString->string);
|
|
|
|
if (*str == '\0')
|
|
return npos;
|
|
|
|
if (nzToLower(*str) != nzToLower(*ptr))
|
|
break;
|
|
|
|
ptr++;
|
|
str++;
|
|
}
|
|
}
|
|
}
|
|
while (*++str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char* ch = std::strstr(&m_sharedString->string[pos], string);
|
|
if (ch)
|
|
return static_cast<unsigned int>(ch - m_sharedString->string);
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::Find(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
return Find(string.m_sharedString->string, start, flags);
|
|
}
|
|
|
|
unsigned int NzString::FindAny(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0 || !string || !string[0])
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size+start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
char32_t character = NzUnicode::GetLowercase(*it);
|
|
do
|
|
{
|
|
if (character == NzUnicode::GetLowercase(*it2))
|
|
return it.base() - m_sharedString->string;
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
do
|
|
{
|
|
if (*it == *it2)
|
|
return it.base() - m_sharedString->string;
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (*++it);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
const char* c = string;
|
|
char character = nzToLower(*str);
|
|
do
|
|
{
|
|
if (character == nzToLower(*c))
|
|
return str - m_sharedString->string;
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (*++str);
|
|
}
|
|
else
|
|
{
|
|
str = std::strpbrk(str, string);
|
|
if (str)
|
|
return str - m_sharedString->string;
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindAny(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
return FindAny(string.m_sharedString->string, start, flags);
|
|
}
|
|
|
|
unsigned int NzString::FindLast(char character, int start, nzUInt32 flags) const
|
|
{
|
|
if (character == '\0' || m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* ptr = &m_sharedString->string[m_sharedString->size-1];
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
character = nzToLower(character);
|
|
do
|
|
{
|
|
if (nzToLower(*ptr) == character)
|
|
return static_cast<unsigned int>(ptr - m_sharedString->string);
|
|
}
|
|
while (ptr-- != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (*ptr == character)
|
|
return static_cast<unsigned int>(ptr - m_sharedString->string);
|
|
}
|
|
while (ptr-- != m_sharedString->string);
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindLast(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
///Algo 1.FindLast#3 (Taille du pattern inconnue)
|
|
const char* ptr = &m_sharedString->string[pos];
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
if (utf8::internal::is_trail(*ptr))
|
|
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
|
|
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
const char* t = string;
|
|
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(t);
|
|
utf8::unchecked::iterator<const char*> tIt(it);
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*it2 == '\0')
|
|
return it.base() - m_sharedString->string;
|
|
|
|
if (tIt.base() > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*it2))
|
|
break;
|
|
|
|
++it2;
|
|
++tIt;
|
|
}
|
|
}
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
char c = nzToLower(string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*ptr) == c)
|
|
{
|
|
const char* p = &string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
return ptr - m_sharedString->string;
|
|
|
|
if (tPtr > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (nzToLower(*tPtr) != nzToLower(*p))
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (ptr-- != m_sharedString->string);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (*ptr == string[0])
|
|
{
|
|
const char* p = &string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
return ptr - m_sharedString->string;
|
|
|
|
if (tPtr > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (*tPtr != *p)
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (ptr-- != m_sharedString->string);
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindLast(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size || string.m_sharedString->size > m_sharedString->size)
|
|
return npos;
|
|
|
|
const char* ptr = &m_sharedString->string[pos];
|
|
const char* limit = &m_sharedString->string[string.m_sharedString->size-1];
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
///Algo 1.FindLast#3 (Itérateur non-adapté)
|
|
if (utf8::internal::is_trail(*ptr))
|
|
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
|
|
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
const char* t = string.m_sharedString->string;
|
|
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(t);
|
|
utf8::unchecked::iterator<const char*> tIt(it);
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*it2 == '\0')
|
|
return it.base() - m_sharedString->string;
|
|
|
|
if (tIt.base() > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*it2))
|
|
break;
|
|
|
|
++it2;
|
|
++tIt;
|
|
}
|
|
}
|
|
}
|
|
while (it--.base() != limit);
|
|
}
|
|
else
|
|
{
|
|
///Algo 1.FindLast#4 (Taille du pattern connue)
|
|
char c = nzToLower(string.m_sharedString->string[string.m_sharedString->size-1]);
|
|
while (true)
|
|
{
|
|
if (nzToLower(*ptr) == c)
|
|
{
|
|
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
|
|
for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
|
|
{
|
|
if (nzToLower(*ptr) != nzToLower(*p))
|
|
break;
|
|
|
|
if (p == &string.m_sharedString->string[0])
|
|
return ptr-m_sharedString->string;
|
|
|
|
if (ptr == m_sharedString->string)
|
|
return npos;
|
|
}
|
|
}
|
|
else if (ptr-- <= limit)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
///Algo 1.FindLast#4 (Taille du pattern connue)
|
|
while (true)
|
|
{
|
|
if (*ptr == string.m_sharedString->string[string.m_sharedString->size-1])
|
|
{
|
|
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
|
|
for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
|
|
{
|
|
if (*ptr != *p)
|
|
break;
|
|
|
|
if (p == &string.m_sharedString->string[0])
|
|
return ptr-m_sharedString->string;
|
|
|
|
if (ptr == m_sharedString->string)
|
|
return npos;
|
|
}
|
|
}
|
|
else if (ptr-- <= limit)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindLastAny(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size+start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
char32_t character = NzUnicode::GetLowercase(*it);
|
|
do
|
|
{
|
|
if (character == NzUnicode::GetLowercase(*it2))
|
|
return it.base() - m_sharedString->string;
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
do
|
|
{
|
|
if (*it == *it2)
|
|
return it.base() - m_sharedString->string;
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
const char* c = string;
|
|
char character = nzToLower(*str);
|
|
do
|
|
{
|
|
if (character == nzToLower(*c))
|
|
return str - m_sharedString->string;
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (str-- != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
const char* c = string;
|
|
do
|
|
{
|
|
if (*str == *c)
|
|
return str - m_sharedString->string;
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (str-- != m_sharedString->string);
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindLastAny(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
return FindLastAny(string.m_sharedString->string, start, flags);
|
|
}
|
|
|
|
unsigned int NzString::FindLastWord(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
///Algo 2.FindLastWord#1 (Taille du pattern inconnue)
|
|
const char* ptr = &m_sharedString->string[pos];
|
|
|
|
if (flags & HandleUtf8)
|
|
{
|
|
if (utf8::internal::is_trail(*ptr))
|
|
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
|
|
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
const char* t = string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*tIt) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tIt.base() > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*p))
|
|
break;
|
|
|
|
++p;
|
|
++tIt;
|
|
}
|
|
}
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
const char* t = string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = utf8::unchecked::next(t);
|
|
do
|
|
{
|
|
if (*it == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*tIt) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tIt.base() > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (*tIt != *p)
|
|
break;
|
|
|
|
++p;
|
|
++tIt;
|
|
}
|
|
}
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char c = nzToLower(string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*ptr) == c)
|
|
{
|
|
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
|
|
continue;
|
|
|
|
const char* p = &string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tPtr == '\0' || std::isspace(*tPtr))
|
|
return ptr-m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tPtr > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (nzToLower(*tPtr) != nzToLower(*p))
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (ptr-- != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (*ptr == string[0])
|
|
{
|
|
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
|
|
continue;
|
|
|
|
const char* p = &string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tPtr == '\0' || std::isspace(*tPtr))
|
|
return ptr-m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tPtr > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (*tPtr != *p)
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (ptr-- != m_sharedString->string);
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindLastWord(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
const char* ptr = &m_sharedString->string[pos];
|
|
const char* limit = &m_sharedString->string[string.m_sharedString->size-1];
|
|
|
|
if (flags & HandleUtf8)
|
|
{
|
|
if (utf8::internal::is_trail(*ptr))
|
|
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
|
|
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
const char* t = string.m_sharedString->string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*tIt) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tIt.base() > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*p))
|
|
break;
|
|
|
|
++p;
|
|
++tIt;
|
|
}
|
|
}
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
const char* t = string.m_sharedString->string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = utf8::unchecked::next(t);
|
|
do
|
|
{
|
|
if (*it == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*tIt) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tIt.base() > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (*tIt != *p)
|
|
break;
|
|
|
|
++p;
|
|
++tIt;
|
|
}
|
|
}
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
///Algo 2.FindLastWord#2 (Taille du pattern connue)
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char c = nzToLower(string.m_sharedString->string[string.m_sharedString->size-1]);
|
|
do
|
|
{
|
|
if (nzToLower(*ptr) == c)
|
|
{
|
|
if (*(ptr+1) != '\0' && !std::isspace(*(ptr+1)))
|
|
continue;
|
|
|
|
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
|
|
for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
|
|
{
|
|
if (nzToLower(*ptr) != nzToLower(*p))
|
|
break;
|
|
|
|
if (p == &string.m_sharedString->string[0])
|
|
{
|
|
if (ptr == m_sharedString->string || std::isspace(*(ptr-1)))
|
|
return ptr-m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (ptr == m_sharedString->string)
|
|
return npos;
|
|
}
|
|
}
|
|
}
|
|
while (ptr-- > limit);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (*ptr == string.m_sharedString->string[string.m_sharedString->size-1])
|
|
{
|
|
if (*(ptr+1) != '\0' && !std::isspace(*(ptr+1)))
|
|
continue;
|
|
|
|
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
|
|
for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
|
|
{
|
|
if (*ptr != *p)
|
|
break;
|
|
|
|
if (p == &string.m_sharedString->string[0])
|
|
{
|
|
if (ptr == m_sharedString->string || std::isspace(*(ptr-1)))
|
|
return ptr-m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (ptr == m_sharedString->string)
|
|
return npos;
|
|
}
|
|
}
|
|
}
|
|
while (ptr-- > limit);
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindWord(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
///Algo 3.FindWord#3 (Taille du pattern inconnue)
|
|
const char* ptr = m_sharedString->string;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
if (utf8::internal::is_trail(*ptr))
|
|
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
|
|
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
const char* t = string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
|
|
do
|
|
{
|
|
if (*it == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*p))
|
|
break;
|
|
|
|
p++;
|
|
tIt++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
const char* t = string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
|
|
do
|
|
{
|
|
if (*it == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (*tIt != *p)
|
|
break;
|
|
|
|
p++;
|
|
tIt++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char c = nzToLower(string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*ptr) == c)
|
|
{
|
|
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
|
|
continue;
|
|
|
|
const char* p = &string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tPtr == '\0' || std::isspace(*tPtr))
|
|
return ptr - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (nzToLower(*tPtr) != nzToLower(*p))
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (*ptr == string[0])
|
|
{
|
|
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
|
|
continue;
|
|
|
|
const char* p = &string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tPtr == '\0' || std::isspace(*tPtr))
|
|
return ptr - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (*tPtr != *p)
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindWord(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* ptr = m_sharedString->string;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
///Algo 3.FindWord#3 (Itérateur trop lent pour #2)
|
|
if (utf8::internal::is_trail(*ptr))
|
|
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
|
|
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
const char* t = string.m_sharedString->string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
|
|
do
|
|
{
|
|
if (*it == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*p))
|
|
break;
|
|
|
|
p++;
|
|
tIt++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
const char* t = string.m_sharedString->string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
|
|
do
|
|
{
|
|
if (*it == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (*tIt != *p)
|
|
break;
|
|
|
|
p++;
|
|
tIt++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
///Algo 3.FindWord#2 (Taille du pattern connue)
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char c = nzToLower(string.m_sharedString->string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*ptr) == c)
|
|
{
|
|
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
|
|
continue;
|
|
|
|
const char* p = &string.m_sharedString->string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tPtr == '\0' || std::isspace(*tPtr))
|
|
return ptr - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (nzToLower(*tPtr) != nzToLower(*p))
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
while ((ptr = std::strstr(ptr, string.m_sharedString->string)))
|
|
{
|
|
// Si le mot est bien isolé
|
|
if ((ptr == m_sharedString->string || std::isspace(*(ptr-1))) && (*(ptr+m_sharedString->size) == '\0' || std::isspace(*(ptr+m_sharedString->size))))
|
|
return ptr - m_sharedString->string;
|
|
|
|
ptr++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
char* NzString::GetBuffer()
|
|
{
|
|
EnsureOwnership();
|
|
|
|
return m_sharedString->string;
|
|
}
|
|
|
|
unsigned int NzString::GetCapacity() const
|
|
{
|
|
return m_sharedString->capacity;
|
|
}
|
|
|
|
const char* NzString::GetConstBuffer() const
|
|
{
|
|
return m_sharedString->string;
|
|
}
|
|
|
|
unsigned int NzString::GetLength() const
|
|
{
|
|
return utf8::distance(m_sharedString->string, &m_sharedString->string[m_sharedString->size]);
|
|
}
|
|
|
|
unsigned int NzString::GetSize() const
|
|
{
|
|
return m_sharedString->size;
|
|
}
|
|
|
|
std::string NzString::GetUtf8String() const
|
|
{
|
|
return std::string(m_sharedString->string, m_sharedString->size);
|
|
}
|
|
|
|
std::u16string NzString::GetUtf16String() const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return std::u16string();
|
|
|
|
std::u16string str;
|
|
str.reserve(m_sharedString->size);
|
|
|
|
utf8::utf8to16(begin(), end(), std::back_inserter(str));
|
|
|
|
return str;
|
|
}
|
|
|
|
std::u32string NzString::GetUtf32String() const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return std::u32string();
|
|
|
|
std::u32string str;
|
|
str.reserve(m_sharedString->size);
|
|
|
|
utf8::utf8to32(begin(), end(), std::back_inserter(str));
|
|
|
|
return str;
|
|
}
|
|
|
|
std::wstring NzString::GetWideString() const
|
|
{
|
|
static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "wchar_t size is not supported");
|
|
if (m_sharedString->size == 0)
|
|
return std::wstring();
|
|
|
|
std::wstring str;
|
|
str.reserve(m_sharedString->size);
|
|
|
|
if (sizeof(wchar_t) == 4) // Je veux du static_if :(
|
|
utf8::utf8to32(begin(), end(), std::back_inserter(str));
|
|
else
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
|
|
do
|
|
{
|
|
char32_t cp = *it;
|
|
if (cp <= 0xFFFF && (cp < 0xD800 || cp > 0xDFFF)) // @Laurent Gomila
|
|
str.push_back(static_cast<wchar_t>(cp));
|
|
else
|
|
str.push_back(L'?');
|
|
}
|
|
while (*it++);
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
NzString NzString::GetWord(unsigned int index, nzUInt32 flags) const
|
|
{
|
|
unsigned int startPos = GetWordPosition(index, flags);
|
|
if (startPos == npos)
|
|
return NzString();
|
|
|
|
int endPos = -1;
|
|
const char* ptr = &m_sharedString->string[startPos];
|
|
if (flags & HandleUtf8)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
do
|
|
{
|
|
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
|
|
{
|
|
endPos = static_cast<int>(it.base() - m_sharedString->string - 1);
|
|
break;
|
|
}
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (std::isspace(*ptr))
|
|
{
|
|
endPos = static_cast<int>(ptr - m_sharedString->string - 1);
|
|
break;
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
|
|
return SubString(startPos, endPos);
|
|
}
|
|
|
|
unsigned int NzString::GetWordPosition(unsigned int index, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
unsigned int currentWord = 0;
|
|
bool inWord = false;
|
|
|
|
const char* ptr = m_sharedString->string;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
do
|
|
{
|
|
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
|
|
inWord = false;
|
|
else
|
|
{
|
|
if (!inWord)
|
|
{
|
|
inWord = true;
|
|
if (++currentWord > index)
|
|
return static_cast<unsigned int>(it.base() - m_sharedString->string);
|
|
}
|
|
}
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (std::isspace(*ptr))
|
|
inWord = false;
|
|
else
|
|
{
|
|
if (!inWord)
|
|
{
|
|
inWord = true;
|
|
if (++currentWord > index)
|
|
return ptr - m_sharedString->string;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
NzString& NzString::Insert(int pos, char character)
|
|
{
|
|
return Insert(pos, &character, 1);
|
|
}
|
|
|
|
NzString& NzString::Insert(int pos, const char* string)
|
|
{
|
|
return Insert(pos, string, std::strlen(string));
|
|
}
|
|
|
|
NzString& NzString::Insert(int pos, const char* string, unsigned int length)
|
|
{
|
|
if (length == 0)
|
|
return *this;
|
|
|
|
if (pos < 0)
|
|
pos = std::max(m_sharedString->size + pos, 0U);
|
|
|
|
unsigned int start = std::min(static_cast<unsigned int>(pos), m_sharedString->size);
|
|
|
|
// Si le buffer est déjà suffisamment grand
|
|
if (m_sharedString->capacity >= m_sharedString->size + length)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
std::memmove(&m_sharedString->string[start+length], &m_sharedString->string[start], m_sharedString->size - start);
|
|
std::memcpy(&m_sharedString->string[start], string, length);
|
|
|
|
m_sharedString->size += length;
|
|
m_sharedString->string[m_sharedString->size] = '\0';
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize = m_sharedString->size + length;
|
|
char* newString = new char[newSize+1];
|
|
|
|
char* ptr = newString;
|
|
|
|
if (start > 0)
|
|
{
|
|
std::memcpy(ptr, m_sharedString->string, start*sizeof(char));
|
|
ptr += start;
|
|
}
|
|
|
|
std::memcpy(ptr, string, length*sizeof(char));
|
|
ptr += length;
|
|
|
|
if (m_sharedString->size > start)
|
|
std::memcpy(ptr, &m_sharedString->string[start], m_sharedString->size - start + 1);
|
|
else
|
|
*ptr = '\0';
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = newSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::Insert(int pos, const NzString& string)
|
|
{
|
|
return Insert(pos, string.m_sharedString->string, string.m_sharedString->size);
|
|
}
|
|
|
|
bool NzString::IsEmpty() const
|
|
{
|
|
return m_sharedString->size == 0;
|
|
}
|
|
|
|
bool NzString::IsNull() const
|
|
{
|
|
return m_sharedString == &emptyString;
|
|
}
|
|
|
|
bool NzString::IsNumber(nzUInt8 base, nzUInt32 flags) const
|
|
{
|
|
#if NAZARA_CORE_SAFE
|
|
if (base < 2 || base > 36)
|
|
{
|
|
NazaraError("Base must be between 2 and 36");
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
NzString check = Simplified();
|
|
if (check.m_sharedString->size == 0)
|
|
return false;
|
|
|
|
char* ptr = (check.m_sharedString->string[0] == '-') ? &check.m_sharedString->string[1] : check.m_sharedString->string;
|
|
|
|
if (base > 10)
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char limitLower = 'a' + base-10 - 1;
|
|
char limitUpper = 'A' + base-10 - 1;
|
|
|
|
do
|
|
{
|
|
char c = *ptr;
|
|
if (c != ' ' && (c < '0' || (c > '9' && c < 'A') || (c > limitUpper && c < 'a') || c > limitLower))
|
|
return false;
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
char limit = 'a' + base-10 - 1;
|
|
do
|
|
{
|
|
char c = *ptr;
|
|
if (c != ' ' && (c < '0' || (c > '9' && c < 'a') || c > limit))
|
|
return false;
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char limit = '0' + base - 1;
|
|
|
|
do
|
|
{
|
|
char c = *ptr;
|
|
if (c != ' ' && (c < '0' || c > limit))
|
|
return false;
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NzString::Match(const char* pattern) const
|
|
{
|
|
if (m_sharedString->size == 0 || !pattern)
|
|
return false;
|
|
|
|
// Par Jack Handy - akkhandy@hotmail.com
|
|
// From : http://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing
|
|
const char* str = m_sharedString->string;
|
|
while (*str && *pattern != '*')
|
|
{
|
|
if (*pattern != *str && *pattern != '?')
|
|
return false;
|
|
|
|
pattern++;
|
|
str++;
|
|
}
|
|
|
|
const char* cp = nullptr;
|
|
const char* mp = nullptr;
|
|
while (*str)
|
|
{
|
|
if (*pattern == '*')
|
|
{
|
|
if (!*++pattern)
|
|
return true;
|
|
|
|
mp = pattern;
|
|
cp = str+1;
|
|
}
|
|
else if (*pattern == *str || *pattern == '?')
|
|
{
|
|
pattern++;
|
|
str++;
|
|
}
|
|
else
|
|
{
|
|
pattern = mp;
|
|
str = cp++;
|
|
}
|
|
}
|
|
|
|
while (*pattern == '*')
|
|
pattern++;
|
|
|
|
return !*pattern;
|
|
}
|
|
|
|
bool NzString::Match(const NzString& pattern) const
|
|
{
|
|
return Match(pattern.m_sharedString->string);
|
|
}
|
|
|
|
NzString& NzString::Prepend(char character)
|
|
{
|
|
return Insert(0, character);
|
|
}
|
|
|
|
NzString& NzString::Prepend(const char* string)
|
|
{
|
|
return Insert(0, string);
|
|
}
|
|
|
|
NzString& NzString::Prepend(const char* string, unsigned int length)
|
|
{
|
|
return Insert(0, string, length);
|
|
}
|
|
|
|
NzString& NzString::Prepend(const NzString& string)
|
|
{
|
|
return Insert(0, string);
|
|
}
|
|
|
|
unsigned int NzString::Replace(char oldCharacter, char newCharacter, int start, nzUInt32 flags)
|
|
{
|
|
if (oldCharacter == '\0' || oldCharacter == newCharacter)
|
|
return 0;
|
|
|
|
if (newCharacter == '\0') // Dans ce cas, il faut passer par un algorithme plus complexe
|
|
return Replace(NzString(oldCharacter), NzString(), start);
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
unsigned int count = 0;
|
|
char* ptr = &m_sharedString->string[pos];
|
|
bool found = false;
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char character_lower = nzToLower(oldCharacter);
|
|
char character_upper = nzToUpper(oldCharacter);
|
|
do
|
|
{
|
|
if (*ptr == character_lower || *ptr == character_upper)
|
|
{
|
|
if (!found)
|
|
{
|
|
unsigned int offset = ptr-m_sharedString->string;
|
|
|
|
EnsureOwnership();
|
|
|
|
ptr = &m_sharedString->string[offset];
|
|
found = true;
|
|
}
|
|
|
|
*ptr = newCharacter;
|
|
++count;
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
while ((ptr = std::strchr(ptr, oldCharacter)))
|
|
{
|
|
if (!found)
|
|
{
|
|
unsigned int offset = ptr-m_sharedString->string;
|
|
|
|
EnsureOwnership();
|
|
|
|
ptr = &m_sharedString->string[offset];
|
|
found = true;
|
|
}
|
|
|
|
*ptr = newCharacter;
|
|
++count;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::Replace(const char* oldString, const char* replaceString, int start, nzUInt32 flags)
|
|
{
|
|
return Replace(oldString, std::strlen(oldString), replaceString, std::strlen(replaceString), start, flags);
|
|
}
|
|
|
|
unsigned int NzString::Replace(const char* oldString, unsigned int oldLength, const char* replaceString, unsigned int replaceLength, int start, nzUInt32 flags)
|
|
{
|
|
if (oldLength == 0)
|
|
return 0;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return 0;
|
|
|
|
unsigned int count = 0;
|
|
if (oldLength == replaceLength)
|
|
{
|
|
bool found = false;
|
|
|
|
// Si aucun changement de taille n'est nécessaire, nous pouvons alors utiliser un algorithme bien plus rapide
|
|
while ((pos = Find(oldString, pos, flags)) != npos)
|
|
{
|
|
if (!found)
|
|
{
|
|
EnsureOwnership();
|
|
found = true;
|
|
}
|
|
|
|
std::memcpy(&m_sharedString->string[pos], replaceString, oldLength);
|
|
pos += oldLength;
|
|
|
|
++count;
|
|
}
|
|
}
|
|
else ///TODO: Algorithme de remplacement sans changement de buffer (si replaceLength < oldLength)
|
|
{
|
|
unsigned int newSize = m_sharedString->size + Count(oldString)*(replaceLength - oldLength);
|
|
if (newSize == m_sharedString->size) // Alors c'est que Count(oldString) == 0
|
|
return 0;
|
|
|
|
char* newString = new char[newSize+1];
|
|
|
|
///Algo 4.Replace#2
|
|
char* ptr = newString;
|
|
const char* p = m_sharedString->string;
|
|
|
|
while ((pos = Find(oldString, pos, flags)) != npos)
|
|
{
|
|
const char* r = &m_sharedString->string[pos];
|
|
|
|
std::memcpy(ptr, p, r-p);
|
|
ptr += r-p;
|
|
std::memcpy(ptr, replaceString, replaceLength);
|
|
ptr += replaceLength;
|
|
p = r+oldLength;
|
|
pos += oldLength;
|
|
|
|
count++;
|
|
}
|
|
|
|
std::strcpy(ptr, p); // Ajoute le caractère de fin par la même occasion
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = newSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::Replace(const NzString& oldString, const NzString& replaceString, int start, nzUInt32 flags)
|
|
{
|
|
return Replace(oldString.m_sharedString->string, oldString.m_sharedString->size, replaceString.m_sharedString->string, replaceString.m_sharedString->size, start, flags);
|
|
}
|
|
|
|
unsigned int NzString::ReplaceAny(const char* oldCharacters, char replaceCharacter, int start, nzUInt32 flags)
|
|
{
|
|
///FIXME: Ne gère pas l'UTF-8
|
|
if (!oldCharacters || !oldCharacters[0])
|
|
return 0;
|
|
|
|
/*if (replaceCharacter == '\0') // Dans ce cas, il faut passer par un algorithme plus complexe
|
|
return ReplaceAny(NzString(oldCharacters), NzString(), start);*/
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
unsigned int count = 0;
|
|
char* ptr = &m_sharedString->string[pos];
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
const char* c = oldCharacters;
|
|
char character = nzToLower(*ptr);
|
|
bool found = false;
|
|
do
|
|
{
|
|
if (character == nzToLower(*c))
|
|
{
|
|
if (!found)
|
|
{
|
|
unsigned int offset = ptr-m_sharedString->string;
|
|
|
|
EnsureOwnership();
|
|
|
|
ptr = &m_sharedString->string[offset];
|
|
found = true;
|
|
}
|
|
|
|
*ptr = replaceCharacter;
|
|
++count;
|
|
break;
|
|
}
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
bool found = false;
|
|
while ((ptr = std::strpbrk(ptr, oldCharacters)))
|
|
{
|
|
if (!found)
|
|
{
|
|
unsigned int offset = ptr-m_sharedString->string;
|
|
|
|
EnsureOwnership();
|
|
|
|
ptr = &m_sharedString->string[offset];
|
|
found = true;
|
|
}
|
|
|
|
*ptr++ = replaceCharacter;
|
|
++count;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
/*
|
|
unsigned int NzString::ReplaceAny(const char* oldCharacters, const char* replaceString, int start, nzUInt32 flags)
|
|
{
|
|
if (start < 0)
|
|
{
|
|
start = m_sharedString->size+start;
|
|
if (start < 0)
|
|
start = 0;
|
|
}
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
unsigned int oSize = (oldCharacters) ? std::strlen(oldCharacters) : 0;
|
|
unsigned int rSize = (replaceString) ? std::strlen(replaceString) : 0;
|
|
|
|
if (pos >= m_sharedString->size || m_sharedString->size == 0 || oSize == 0)
|
|
return 0;
|
|
|
|
unsigned int count = 0;
|
|
|
|
if (rSize == 1) // On utilise un algorithme optimisé
|
|
{
|
|
EnsureOwnership();
|
|
|
|
f or (; pos < m_sharedString->size; ++pos)
|
|
{
|
|
for (unsigned int i = 0; i < oSize; ++i)
|
|
{
|
|
if (m_sharedString->string[pos] == oldCharacters[i])
|
|
{
|
|
m_sharedString->string[pos] = replaceString[0];
|
|
++count;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize;
|
|
{
|
|
unsigned int count = CountAny(oldCharacters);
|
|
newSize = m_sharedString->size - count + count*rSize;
|
|
}
|
|
char* newString = new char[newSize+1];
|
|
|
|
unsigned int j = 0;
|
|
for (unsigned int i = 0; i < m_sharedString->size; ++i)
|
|
{
|
|
if (i < pos) // Avant la position où on est censé commencer à remplacer, on ne fait que recopier
|
|
newString[j++] = m_sharedString->string[i];
|
|
else
|
|
{
|
|
bool found = false;
|
|
for (unsigned int l = 0; l < oSize; ++l)
|
|
{
|
|
if (m_sharedString->string[i] == oldCharacters[l])
|
|
{
|
|
for (unsigned int k = 0; k < rSize; ++k)
|
|
newString[j++] = replaceString[k];
|
|
|
|
++count;
|
|
found = true;
|
|
break; // Simple façon d'éviter la ligne après la boucle
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
newString[j++] = m_sharedString->string[i];
|
|
}
|
|
}
|
|
newString[newSize] = '\0';
|
|
|
|
ReleaseString();
|
|
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::ReplaceAny(const NzString& oldCharacters, const NzString& replaceString, int start, nzUInt32 flags)
|
|
{
|
|
if (start < 0)
|
|
{
|
|
start = m_sharedString->size+start;
|
|
if (start < 0)
|
|
start = 0;
|
|
}
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
|
|
if (pos >= m_sharedString->size || m_sharedString->size == 0 || oldCharacters.m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
unsigned int count = 0;
|
|
|
|
if (replaceString.m_sharedString->size == 1) // On utilise un algorithme optimisé
|
|
{
|
|
EnsureOwnership();
|
|
|
|
char character = replaceString[0];
|
|
for (; pos < m_sharedString->size; ++pos)
|
|
{
|
|
for (unsigned int i = 0; i < oldCharacters.m_sharedString->size; ++i)
|
|
{
|
|
if (m_sharedString->string[pos] == oldCharacters[i])
|
|
{
|
|
m_sharedString->string[pos] = character;
|
|
++count;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize;
|
|
{
|
|
unsigned int count = CountAny(oldCharacters);
|
|
newSize = m_sharedString->size - count + count*replaceString.m_sharedString->size;
|
|
}
|
|
char* newString = new char[newSize+1];
|
|
|
|
unsigned int j = 0;
|
|
for (unsigned int i = 0; i < m_sharedString->size; ++i)
|
|
{
|
|
if (i < pos) // Avant la position où on est censé commencer à remplacer, on ne fait que recopier
|
|
newString[j++] = m_sharedString->string[i];
|
|
else
|
|
{
|
|
bool found = false;
|
|
for (unsigned int l = 0; l < oldCharacters.m_sharedString->size; ++l)
|
|
{
|
|
if (m_sharedString->string[i] == oldCharacters[l])
|
|
{
|
|
for (unsigned int k = 0; k < replaceString.m_sharedString->size; ++k)
|
|
newString[j++] = replaceString[k];
|
|
|
|
++count;
|
|
found = true;
|
|
break; // Simple façon d'éviter la ligne après la boucle
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
newString[j++] = m_sharedString->string[i];
|
|
}
|
|
}
|
|
newString[newSize] = '\0';
|
|
|
|
ReleaseString();
|
|
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
*/
|
|
void NzString::Reserve(unsigned int bufferSize)
|
|
{
|
|
if (m_sharedString->capacity >= bufferSize)
|
|
return;
|
|
|
|
char* ptr = new char[bufferSize+1];
|
|
if (m_sharedString->size > 0)
|
|
std::memcpy(ptr, m_sharedString->string, m_sharedString->size+1);
|
|
|
|
unsigned int size = m_sharedString->size;
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = bufferSize;
|
|
m_sharedString->size = size;
|
|
m_sharedString->string = ptr;
|
|
}
|
|
|
|
NzString& NzString::Resize(int size, char character)
|
|
{
|
|
if (size == 0)
|
|
{
|
|
Clear(true);
|
|
return *this;
|
|
}
|
|
|
|
if (size < 0)
|
|
size = std::max(m_sharedString->size + size, 0U);
|
|
|
|
unsigned int newSize = static_cast<unsigned int>(size);
|
|
|
|
if (m_sharedString->capacity >= newSize)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
// Nous avons déjà la place requise, contentons-nous de remplir le buffer
|
|
if (character != '\0' && newSize > m_sharedString->size)
|
|
std::memset(&m_sharedString->string[m_sharedString->size], character, newSize-m_sharedString->size);
|
|
|
|
m_sharedString->size = newSize;
|
|
}
|
|
else // On veut forcément agrandir la chaine
|
|
{
|
|
char* newString = new char[newSize+1];
|
|
std::memcpy(newString, m_sharedString->string, m_sharedString->size);
|
|
|
|
if (character != '\0')
|
|
std::memset(&newString[m_sharedString->size], character, newSize-m_sharedString->size);
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = newSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
// On rajoute le caractère de fin
|
|
m_sharedString->string[newSize] = '\0';
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString NzString::Resized(int size, char character) const
|
|
{
|
|
if (size < 0)
|
|
size = m_sharedString->size + size;
|
|
|
|
if (size <= 0)
|
|
return NzString();
|
|
|
|
unsigned int newSize = static_cast<unsigned int>(size);
|
|
if (newSize == m_sharedString->size)
|
|
return *this;
|
|
|
|
char* str = new char[newSize+1];
|
|
if (newSize > m_sharedString->size)
|
|
{
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
if (character != '\0')
|
|
std::memset(&str[m_sharedString->size], character, newSize-m_sharedString->size);
|
|
}
|
|
else
|
|
std::memcpy(str, m_sharedString->string, newSize);
|
|
|
|
str[newSize] = '\0';
|
|
|
|
return NzString(new SharedString(1, newSize, newSize, str));
|
|
}
|
|
|
|
NzString& NzString::Reverse()
|
|
{
|
|
if (m_sharedString->size != 0)
|
|
{
|
|
unsigned int i = 0;
|
|
unsigned int j = m_sharedString->size-1;
|
|
|
|
while (i < j)
|
|
std::swap(m_sharedString->string[i++], m_sharedString->string[j--]);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString NzString::Reversed() const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return NzString();
|
|
|
|
char* str = new char[m_sharedString->size+1];
|
|
|
|
char* ptr = &str[m_sharedString->size-1];
|
|
char* p = m_sharedString->string;
|
|
|
|
do
|
|
*ptr-- = *p;
|
|
while (*(++p));
|
|
|
|
str[m_sharedString->size] = '\0';
|
|
|
|
return NzString(new SharedString(1, m_sharedString->size, m_sharedString->size, str));
|
|
}
|
|
|
|
NzString& NzString::Set(char character)
|
|
{
|
|
if (character != '\0')
|
|
{
|
|
if (m_sharedString->capacity >= 1)
|
|
EnsureOwnership(true);
|
|
else
|
|
{
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = 1;
|
|
m_sharedString->string = new char[2];
|
|
}
|
|
|
|
m_sharedString->size = 1;
|
|
m_sharedString->string[0] = character;
|
|
m_sharedString->string[1] = '\0';
|
|
}
|
|
else
|
|
ReleaseString();
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::Set(unsigned int rep, char character)
|
|
{
|
|
if (rep > 0)
|
|
{
|
|
if (m_sharedString->capacity >= rep)
|
|
EnsureOwnership(true);
|
|
else
|
|
{
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = rep;
|
|
m_sharedString->string = new char[rep+1];
|
|
}
|
|
|
|
m_sharedString->size = rep;
|
|
|
|
if (character != '\0')
|
|
std::memset(m_sharedString->string, character, rep);
|
|
|
|
m_sharedString->string[rep] = '\0';
|
|
}
|
|
else
|
|
ReleaseString();
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::Set(unsigned int rep, const char* string)
|
|
{
|
|
return Set(rep, string, (string) ? std::strlen(string) : 0);
|
|
}
|
|
|
|
NzString& NzString::Set(unsigned int rep, const char* string, unsigned int length)
|
|
{
|
|
unsigned int totalSize = rep*length;
|
|
|
|
if (totalSize > 0)
|
|
{
|
|
if (m_sharedString->capacity >= totalSize)
|
|
EnsureOwnership(true);
|
|
else
|
|
{
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = totalSize;
|
|
m_sharedString->string = new char[totalSize+1];
|
|
}
|
|
|
|
m_sharedString->size = totalSize;
|
|
|
|
for (unsigned int i = 0; i < rep; ++i)
|
|
std::memcpy(&m_sharedString->string[i*length], string, length);
|
|
|
|
m_sharedString->string[totalSize] = '\0';
|
|
}
|
|
else
|
|
ReleaseString();
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::Set(unsigned int rep, const NzString& string)
|
|
{
|
|
return Set(rep, string.m_sharedString->string, string.m_sharedString->size);
|
|
}
|
|
|
|
NzString& NzString::Set(const char* string)
|
|
{
|
|
return Set(string, (string) ? std::strlen(string) : 0);
|
|
}
|
|
|
|
NzString& NzString::Set(const char* string, unsigned int length)
|
|
{
|
|
if (length > 0)
|
|
{
|
|
if (m_sharedString->capacity >= length)
|
|
EnsureOwnership(true);
|
|
else
|
|
{
|
|
ReleaseString();
|
|
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = length;
|
|
m_sharedString->string = new char[length+1];
|
|
}
|
|
|
|
m_sharedString->size = length;
|
|
std::memcpy(m_sharedString->string, string, length);
|
|
m_sharedString->string[length] = '\0';
|
|
}
|
|
else
|
|
ReleaseString();
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::Set(const std::string& string)
|
|
{
|
|
return Set(string.data(), string.size());
|
|
}
|
|
|
|
NzString& NzString::Set(const NzString& string)
|
|
{
|
|
if (this != &string)
|
|
{
|
|
ReleaseString();
|
|
|
|
m_sharedString = string.m_sharedString;
|
|
if (m_sharedString != &emptyString)
|
|
m_sharedString->refCount++;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::Set(NzString&& string) noexcept
|
|
{
|
|
std::swap(m_sharedString, string.m_sharedString);
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::Set(SharedString* sharedString)
|
|
{
|
|
ReleaseString();
|
|
m_sharedString = sharedString;
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString NzString::Simplified(nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return NzString();
|
|
|
|
char* str = new char[m_sharedString->size+1];
|
|
char* p = str;
|
|
|
|
const char* ptr = m_sharedString->string;
|
|
bool inword = false;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
do
|
|
{
|
|
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
|
|
{
|
|
if (inword)
|
|
{
|
|
*p++ = ' ';
|
|
inword = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
p = utf8::append(*it, p);
|
|
inword = true;
|
|
}
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
const char* limit = &m_sharedString->string[m_sharedString->size];
|
|
do
|
|
{
|
|
if (std::isspace(*ptr))
|
|
{
|
|
if (inword)
|
|
{
|
|
*p++ = ' ';
|
|
inword = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*p++ = *ptr;
|
|
inword = true;
|
|
}
|
|
}
|
|
while (++ptr != limit);
|
|
}
|
|
|
|
if (!inword && p != str)
|
|
p--;
|
|
|
|
*p = '\0';
|
|
|
|
return NzString(new SharedString(1, m_sharedString->size, p-str, str));
|
|
}
|
|
|
|
NzString& NzString::Simplify(nzUInt32 flags)
|
|
{
|
|
return Set(Simplified(flags));
|
|
}
|
|
|
|
unsigned int NzString::Split(std::vector<NzString>& result, char separation, int start, nzUInt32 flags) const
|
|
{
|
|
if (separation == '\0' || m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
unsigned int lastSep = Find(separation, start, flags);
|
|
if (lastSep == npos)
|
|
{
|
|
result.push_back(*this);
|
|
return 1;
|
|
}
|
|
else if (lastSep != 0)
|
|
result.push_back(SubString(0, lastSep-1));
|
|
|
|
while (true)
|
|
{
|
|
unsigned int sep = Find(separation, lastSep+1, flags);
|
|
if (sep == npos)
|
|
break;
|
|
|
|
if (sep-lastSep > 1)
|
|
result.push_back(SubString(lastSep+1, sep-1));
|
|
|
|
lastSep = sep;
|
|
}
|
|
|
|
if (lastSep != m_sharedString->size-1)
|
|
result.push_back(SubString(lastSep+1));
|
|
|
|
return result.size();
|
|
}
|
|
|
|
unsigned int NzString::Split(std::vector<NzString>& result, const char* separation, int start, nzUInt32 flags) const
|
|
{
|
|
return Split(result, separation, std::strlen(separation), start, flags);
|
|
}
|
|
|
|
unsigned int NzString::Split(std::vector<NzString>& result, const char* separation, unsigned int length, int start, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return 0;
|
|
else if (length == 0)
|
|
{
|
|
result.reserve(m_sharedString->size);
|
|
for (unsigned int i = 0; i < m_sharedString->size; ++i)
|
|
result.push_back(NzString(m_sharedString->string[i]));
|
|
|
|
return m_sharedString->size;
|
|
}
|
|
else if (length > m_sharedString->size)
|
|
{
|
|
result.push_back(*this);
|
|
return 1;
|
|
}
|
|
|
|
unsigned int lastSep = Find(separation, start, flags);
|
|
unsigned int oldSize = result.size();
|
|
if (lastSep == npos)
|
|
{
|
|
result.push_back(*this);
|
|
return 1;
|
|
}
|
|
else if (lastSep != 0)
|
|
result.push_back(SubString(0, lastSep-1));
|
|
|
|
unsigned int sep;
|
|
while ((sep = Find(separation, lastSep + length, flags)) != npos)
|
|
{
|
|
if (sep-lastSep > length)
|
|
result.push_back(SubString(lastSep + length, sep-1));
|
|
|
|
lastSep = sep;
|
|
}
|
|
|
|
if (lastSep != m_sharedString->size - length)
|
|
result.push_back(SubString(lastSep + length));
|
|
|
|
return result.size()-oldSize;
|
|
}
|
|
|
|
unsigned int NzString::Split(std::vector<NzString>& result, const NzString& separation, int start, nzUInt32 flags) const
|
|
{
|
|
return Split(result, separation.m_sharedString->string, separation.m_sharedString->size, start, flags);
|
|
}
|
|
|
|
unsigned int NzString::SplitAny(std::vector<NzString>& result, const char* separations, int start, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
unsigned int oldSize = result.size();
|
|
|
|
unsigned int lastSep = FindAny(separations, start, flags);
|
|
if (lastSep == npos)
|
|
{
|
|
result.push_back(*this);
|
|
return 1;
|
|
}
|
|
else if (lastSep != 0)
|
|
result.push_back(SubString(0, lastSep-1));
|
|
|
|
unsigned int sep;
|
|
while ((sep = FindAny(separations, lastSep+1, flags)) != npos)
|
|
{
|
|
if (sep-lastSep > 1)
|
|
result.push_back(SubString(lastSep+1, sep-1));
|
|
|
|
lastSep = sep;
|
|
}
|
|
|
|
if (lastSep != m_sharedString->size-1)
|
|
result.push_back(SubString(lastSep+1));
|
|
|
|
return result.size()-oldSize;
|
|
}
|
|
|
|
unsigned int NzString::SplitAny(std::vector<NzString>& result, const NzString& separations, int start, nzUInt32 flags) const
|
|
{
|
|
return SplitAny(result, separations.m_sharedString->string, start, flags);
|
|
}
|
|
|
|
bool NzString::StartsWith(char character, nzUInt32 flags) const
|
|
{
|
|
if (character == '\0' || m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (flags & CaseInsensitive)
|
|
return nzToLower(m_sharedString->string[0]) == nzToLower(character);
|
|
else
|
|
return m_sharedString->string[0] == character;
|
|
}
|
|
|
|
bool NzString::StartsWith(const char* string, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
do
|
|
{
|
|
if (*it2 == '\0')
|
|
return true;
|
|
|
|
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
|
|
return false;
|
|
|
|
++it2;
|
|
}
|
|
while (*it++);
|
|
}
|
|
else
|
|
{
|
|
char* ptr = m_sharedString->string;
|
|
const char* s = string;
|
|
do
|
|
{
|
|
if (*s == '\0')
|
|
return true;
|
|
|
|
if (nzToLower(*ptr) != nzToLower(*s))
|
|
return false;
|
|
|
|
s++;
|
|
}
|
|
while (*ptr++);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char* ptr = m_sharedString->string;
|
|
const char* s = string;
|
|
do
|
|
{
|
|
if (*s == '\0')
|
|
return true;
|
|
|
|
if (*ptr != *s)
|
|
return false;
|
|
|
|
s++;
|
|
}
|
|
while (*ptr++);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool NzString::StartsWith(const NzString& string, nzUInt32 flags) const
|
|
{
|
|
if (string.m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (m_sharedString->size < string.m_sharedString->size)
|
|
return false;
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
|
|
utf8::unchecked::iterator<const char*> it2(string.m_sharedString->string);
|
|
do
|
|
{
|
|
if (*it2 == '\0')
|
|
return true;
|
|
|
|
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
|
|
return false;
|
|
|
|
++it2;
|
|
}
|
|
while (*it++);
|
|
}
|
|
else
|
|
{
|
|
char* ptr = m_sharedString->string;
|
|
const char* s = string.m_sharedString->string;
|
|
do
|
|
{
|
|
if (*s == '\0')
|
|
return true;
|
|
|
|
if (nzToLower(*ptr) != nzToLower(*s))
|
|
return false;
|
|
|
|
s++;
|
|
}
|
|
while (*ptr++);
|
|
}
|
|
}
|
|
else
|
|
return std::memcmp(m_sharedString->string, string.m_sharedString->string, string.m_sharedString->size) == 0;
|
|
|
|
return false;
|
|
}
|
|
|
|
NzString NzString::SubString(int startPos, int endPos) const
|
|
{
|
|
if (startPos < 0)
|
|
startPos = std::max(m_sharedString->size+startPos, 0U);
|
|
|
|
unsigned int start = static_cast<unsigned int>(startPos);
|
|
|
|
if (endPos < 0)
|
|
{
|
|
endPos = m_sharedString->size+endPos;
|
|
if (endPos < 0)
|
|
return NzString();
|
|
}
|
|
|
|
unsigned int minEnd = std::min(static_cast<unsigned int>(endPos), m_sharedString->size-1);
|
|
|
|
if (start > minEnd || start >= m_sharedString->size)
|
|
return NzString();
|
|
|
|
unsigned int size = minEnd-start+1;
|
|
char* str = new char[size+1];
|
|
std::memcpy(str, &m_sharedString->string[start], size);
|
|
str[size] = '\0';
|
|
|
|
return NzString(new SharedString(1, size, size, str));
|
|
}
|
|
|
|
NzString NzString::SubStringFrom(char character, int startPos, bool fromLast, bool include, nzUInt32 flags) const
|
|
{
|
|
if (character == '\0')
|
|
return *this;
|
|
|
|
unsigned int pos;
|
|
if (fromLast)
|
|
pos = FindLast(character, startPos, flags);
|
|
else
|
|
pos = Find(character, startPos, flags);
|
|
|
|
if (pos == 0 && include)
|
|
return *this;
|
|
else if (pos == npos)
|
|
return NzString();
|
|
|
|
return SubString(pos + ((include) ? 0 : 1));
|
|
}
|
|
|
|
NzString NzString::SubStringFrom(const char* string, int startPos, bool fromLast, bool include, nzUInt32 flags) const
|
|
{
|
|
return SubStringFrom(string, std::strlen(string), startPos, fromLast, include, flags);
|
|
}
|
|
|
|
NzString NzString::SubStringFrom(const char* string, unsigned int length, int startPos, bool fromLast, bool include, nzUInt32 flags) const
|
|
{
|
|
unsigned int pos;
|
|
if (fromLast)
|
|
pos = FindLast(string, startPos, flags);
|
|
else
|
|
pos = Find(string, startPos, flags);
|
|
|
|
if (pos == 0 && include)
|
|
return *this;
|
|
else if (pos == npos)
|
|
return NzString();
|
|
|
|
return SubString(pos + ((include) ? 0 : length));
|
|
}
|
|
|
|
NzString NzString::SubStringFrom(const NzString& string, int startPos, bool fromLast, bool include, nzUInt32 flags) const
|
|
{
|
|
return SubStringFrom(string.m_sharedString->string, string.m_sharedString->size, startPos, fromLast, include, flags);
|
|
}
|
|
|
|
NzString NzString::SubStringTo(char character, int startPos, bool toLast, bool include, nzUInt32 flags) const
|
|
{
|
|
if (character == '\0')
|
|
return *this;
|
|
|
|
unsigned int pos;
|
|
if (toLast)
|
|
pos = FindLast(character, startPos);
|
|
else
|
|
pos = Find(character, startPos, flags);
|
|
|
|
if (pos == 0)
|
|
return (include) ? NzString(character) : NzString();
|
|
else if (pos == npos)
|
|
return *this;
|
|
|
|
return SubString(0, pos+((include) ? 1 : 0)-1);
|
|
}
|
|
|
|
NzString NzString::SubStringTo(const char* string, int startPos, bool toLast, bool include, nzUInt32 flags) const
|
|
{
|
|
return SubStringTo(string, std::strlen(string), startPos, toLast, include, flags);
|
|
}
|
|
|
|
NzString NzString::SubStringTo(const char* string, unsigned int length, int startPos, bool toLast, bool include, nzUInt32 flags) const
|
|
{
|
|
unsigned int pos;
|
|
if (toLast)
|
|
pos = FindLast(string, startPos, flags);
|
|
else
|
|
pos = Find(string, startPos, flags);
|
|
|
|
if (pos == 0)
|
|
return (include) ? string : NzString();
|
|
else if (pos == npos)
|
|
return *this;
|
|
|
|
return SubString(0, pos+((include) ? length : 0)-1);
|
|
}
|
|
|
|
NzString NzString::SubStringTo(const NzString& string, int startPos, bool toLast, bool include, nzUInt32 flags) const
|
|
{
|
|
return SubStringTo(string.m_sharedString->string, string.m_sharedString->size, startPos, toLast, include, flags);
|
|
}
|
|
|
|
void NzString::Swap(NzString& str)
|
|
{
|
|
std::swap(m_sharedString, str.m_sharedString);
|
|
}
|
|
|
|
bool NzString::ToBool(bool* value, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
NzString word = GetWord(0);
|
|
|
|
if (word[0] == '1')
|
|
{
|
|
if (value)
|
|
*value = true;
|
|
}
|
|
else if (word[0] == '0')
|
|
{
|
|
if (value)
|
|
*value = false;
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
word = word.ToLower(); // Les mots identifiés sont en ASCII, inutile de passer le flag unicode
|
|
|
|
if (word == "true")
|
|
{
|
|
if (value)
|
|
*value = true;
|
|
}
|
|
else if (word == "false")
|
|
{
|
|
if (value)
|
|
*value = false;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NzString::ToDouble(double* value) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (value)
|
|
*value = std::atof(m_sharedString->string);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NzString::ToInteger(long long* value, nzUInt8 base) const
|
|
{
|
|
if (value)
|
|
{
|
|
bool ok;
|
|
*value = NzStringToNumber(*this, base, &ok);
|
|
|
|
return ok;
|
|
}
|
|
else
|
|
return IsNumber(base);
|
|
}
|
|
|
|
NzString NzString::ToLower(nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
if (flags & HandleUtf8)
|
|
{
|
|
NzString lower;
|
|
lower.Reserve(m_sharedString->size);
|
|
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
|
|
do
|
|
utf8::append(NzUnicode::GetLowercase(*it), std::back_inserter(lower));
|
|
while (*++it);
|
|
|
|
return lower;
|
|
}
|
|
else
|
|
{
|
|
char* str = new char[m_sharedString->size+1];
|
|
|
|
char* ptr = m_sharedString->string;
|
|
char* s = str;
|
|
do
|
|
*s++ = nzToLower(*ptr);
|
|
while (*++ptr);
|
|
|
|
*s = '\0';
|
|
|
|
return NzString(new SharedString(1, m_sharedString->size, m_sharedString->size, str));
|
|
}
|
|
}
|
|
|
|
NzString NzString::ToUpper(nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
if (flags & HandleUtf8)
|
|
{
|
|
NzString upper;
|
|
upper.Reserve(m_sharedString->size);
|
|
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
|
|
do
|
|
utf8::append(NzUnicode::GetUppercase(*it), std::back_inserter(upper));
|
|
while (*++it);
|
|
|
|
return upper;
|
|
}
|
|
else
|
|
{
|
|
char* str = new char[m_sharedString->size+1];
|
|
|
|
char* ptr = m_sharedString->string;
|
|
char* s = str;
|
|
do
|
|
*s++ = nzToUpper(*ptr);
|
|
while (*++ptr);
|
|
|
|
*s = '\0';
|
|
|
|
return NzString(new SharedString(1, m_sharedString->size, m_sharedString->size, str));
|
|
}
|
|
}
|
|
|
|
NzString& NzString::Trim(nzUInt32 flags)
|
|
{
|
|
return Set(Trimmed(flags));
|
|
}
|
|
|
|
NzString& NzString::Trim(char character, nzUInt32 flags)
|
|
{
|
|
return Set(Trimmed(character, flags));
|
|
}
|
|
|
|
NzString NzString::Trimmed(nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
unsigned int startPos;
|
|
unsigned int endPos;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
if ((flags & TrimOnlyRight) == 0)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
|
|
do
|
|
{
|
|
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
|
|
break;
|
|
}
|
|
while (*++it);
|
|
|
|
startPos = it.base() - m_sharedString->string;
|
|
}
|
|
else
|
|
startPos = 0;
|
|
|
|
if ((flags & TrimOnlyLeft) == 0)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(&m_sharedString->string[m_sharedString->size]);
|
|
while ((it--).base() != m_sharedString->string)
|
|
{
|
|
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
|
|
break;
|
|
}
|
|
|
|
endPos = it.base() - m_sharedString->string;
|
|
}
|
|
else
|
|
endPos = m_sharedString->size-1;
|
|
}
|
|
else
|
|
{
|
|
startPos = 0;
|
|
if ((flags & TrimOnlyRight) == 0)
|
|
{
|
|
for (; startPos < m_sharedString->size; ++startPos)
|
|
{
|
|
if (!std::isspace(m_sharedString->string[startPos]))
|
|
break;
|
|
}
|
|
}
|
|
|
|
endPos = m_sharedString->size-1;
|
|
if ((flags & TrimOnlyLeft) == 0)
|
|
{
|
|
for (; endPos > 0; --endPos)
|
|
{
|
|
if (!std::isspace(m_sharedString->string[endPos]))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return SubString(startPos, endPos);
|
|
}
|
|
|
|
NzString NzString::Trimmed(char character, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
unsigned int startPos = 0;
|
|
unsigned int endPos = m_sharedString->size-1;
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char ch = nzToLower(character);
|
|
if ((flags & TrimOnlyRight) == 0)
|
|
{
|
|
for (; startPos < m_sharedString->size; ++startPos)
|
|
{
|
|
if (nzToLower(m_sharedString->string[startPos]) != ch)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((flags & TrimOnlyLeft) == 0)
|
|
{
|
|
for (; endPos > 0; --endPos)
|
|
{
|
|
if (nzToLower(m_sharedString->string[endPos]) != ch)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((flags & TrimOnlyRight) == 0)
|
|
{
|
|
for (; startPos < m_sharedString->size; ++startPos)
|
|
{
|
|
if (m_sharedString->string[startPos] != character)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((flags & TrimOnlyLeft) == 0)
|
|
{
|
|
for (; endPos > 0; --endPos)
|
|
{
|
|
if (m_sharedString->string[endPos] != character)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return SubString(startPos, endPos);
|
|
}
|
|
|
|
char* NzString::begin()
|
|
{
|
|
return m_sharedString->string;
|
|
}
|
|
|
|
const char* NzString::begin() const
|
|
{
|
|
return m_sharedString->string;
|
|
}
|
|
|
|
char* NzString::end()
|
|
{
|
|
return &m_sharedString->string[m_sharedString->size];
|
|
}
|
|
|
|
const char* NzString::end() const
|
|
{
|
|
return &m_sharedString->string[m_sharedString->size];
|
|
}
|
|
|
|
void NzString::push_front(char c)
|
|
{
|
|
Prepend(c);
|
|
}
|
|
|
|
void NzString::push_back(char c)
|
|
{
|
|
Append(c);
|
|
}
|
|
/*
|
|
char* NzString::rbegin()
|
|
{
|
|
return &m_sharedString->string[m_sharedString->size-1];
|
|
}
|
|
|
|
const char* NzString::rbegin() const
|
|
{
|
|
return &m_sharedString->string[m_sharedString->size-1];
|
|
}
|
|
|
|
char* NzString::rend()
|
|
{
|
|
return &m_sharedString->string[-1];
|
|
}
|
|
|
|
const char* NzString::rend() const
|
|
{
|
|
return &m_sharedString->string[-1];
|
|
}
|
|
*/
|
|
|
|
NzString::operator std::string() const
|
|
{
|
|
return std::string(m_sharedString->string, m_sharedString->size);
|
|
}
|
|
|
|
char& NzString::operator[](unsigned int pos)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
if (pos >= m_sharedString->size)
|
|
Resize(pos+1);
|
|
|
|
return m_sharedString->string[pos];
|
|
}
|
|
|
|
char NzString::operator[](unsigned int pos) const
|
|
{
|
|
#if NAZARA_CORE_SAFE
|
|
if (pos >= m_sharedString->size)
|
|
{
|
|
NazaraError("Index out of range (" + Number(pos) + " >= " + Number(m_sharedString->size) + ')');
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
return m_sharedString->string[pos];
|
|
}
|
|
|
|
NzString& NzString::operator=(char character)
|
|
{
|
|
return Set(character);
|
|
}
|
|
|
|
NzString& NzString::operator=(const char* string)
|
|
{
|
|
return Set(string);
|
|
}
|
|
|
|
NzString& NzString::operator=(const std::string& string)
|
|
{
|
|
return Set(string);
|
|
}
|
|
|
|
NzString& NzString::operator=(const NzString& string)
|
|
{
|
|
return Set(string);
|
|
}
|
|
|
|
NzString& NzString::operator=(NzString&& string) noexcept
|
|
{
|
|
return Set(string);
|
|
}
|
|
|
|
NzString NzString::operator+(char character) const
|
|
{
|
|
if (character == '\0')
|
|
return *this;
|
|
|
|
unsigned int totalSize = m_sharedString->size+1;
|
|
char* str = new char[totalSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
|
|
str[m_sharedString->size] = character;
|
|
str[totalSize] = '\0';
|
|
|
|
return NzString(new SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
NzString NzString::operator+(const char* string) const
|
|
{
|
|
if (!string || !string[0])
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return string;
|
|
|
|
unsigned int length = std::strlen(string);
|
|
if (length == 0)
|
|
return *this;
|
|
|
|
unsigned int totalSize = m_sharedString->size + length;
|
|
char* str = new char[totalSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
std::memcpy(&str[m_sharedString->size], string, length+1);
|
|
|
|
return NzString(new SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
NzString NzString::operator+(const std::string& string) const
|
|
{
|
|
if (string.empty())
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return string;
|
|
|
|
unsigned int totalSize = m_sharedString->size + string.size();
|
|
char* str = new char[totalSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
std::memcpy(&str[m_sharedString->size], string.c_str(), string.size()+1);
|
|
|
|
return NzString(new SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
NzString NzString::operator+(const NzString& string) const
|
|
{
|
|
if (string.m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return string;
|
|
|
|
unsigned int totalSize = m_sharedString->size + string.m_sharedString->size;
|
|
char* str = new char[totalSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
std::memcpy(&str[m_sharedString->size], string.m_sharedString->string, string.m_sharedString->size+1);
|
|
|
|
return NzString(new SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
NzString& NzString::operator+=(char character)
|
|
{
|
|
return Insert(m_sharedString->size, character);
|
|
}
|
|
|
|
NzString& NzString::operator+=(const char* string)
|
|
{
|
|
return Insert(m_sharedString->size, string);
|
|
}
|
|
|
|
NzString& NzString::operator+=(const std::string& string)
|
|
{
|
|
return Insert(m_sharedString->size, string.c_str(), string.size());
|
|
}
|
|
|
|
NzString& NzString::operator+=(const NzString& string)
|
|
{
|
|
return Insert(m_sharedString->size, string);
|
|
}
|
|
|
|
bool NzString::operator==(char character) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return character == '\0';
|
|
|
|
if (m_sharedString->size > 1)
|
|
return false;
|
|
|
|
return m_sharedString->string[0] == character;
|
|
}
|
|
|
|
bool NzString::operator==(const char* string) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return !string || !string[0];
|
|
|
|
if (!string || !string[0])
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string) == 0;
|
|
}
|
|
|
|
bool NzString::operator==(const std::string& string) const
|
|
{
|
|
if (m_sharedString->size == 0 || string.empty())
|
|
return m_sharedString->size == string.size();
|
|
|
|
if (m_sharedString->size != string.size())
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string.c_str()) == 0;
|
|
}
|
|
|
|
bool NzString::operator!=(char character) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return character != '\0';
|
|
|
|
if (character == '\0' || m_sharedString->size != 1)
|
|
return true;
|
|
|
|
if (m_sharedString->size != 1)
|
|
return true;
|
|
|
|
return m_sharedString->string[0] != character;
|
|
}
|
|
|
|
bool NzString::operator!=(const char* string) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return string && string[0];
|
|
|
|
if (!string || !string[0])
|
|
return true;
|
|
|
|
return std::strcmp(m_sharedString->string, string) != 0;
|
|
}
|
|
|
|
bool NzString::operator!=(const std::string& string) const
|
|
{
|
|
if (m_sharedString->size == 0 || string.empty())
|
|
return m_sharedString->size == string.size();
|
|
|
|
if (m_sharedString->size != string.size())
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string.c_str()) != 0;
|
|
}
|
|
|
|
bool NzString::operator<(char character) const
|
|
{
|
|
if (character == '\0')
|
|
return false;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return true;
|
|
|
|
return m_sharedString->string[0] < character;
|
|
}
|
|
|
|
bool NzString::operator<(const char* string) const
|
|
{
|
|
if (!string || !string[0])
|
|
return false;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return true;
|
|
|
|
return std::strcmp(m_sharedString->string, string) < 0;
|
|
}
|
|
|
|
bool NzString::operator<(const std::string& string) const
|
|
{
|
|
if (string.empty())
|
|
return false;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return true;
|
|
|
|
return std::strcmp(m_sharedString->string, string.c_str()) < 0;
|
|
}
|
|
|
|
bool NzString::operator<=(char character) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return true;
|
|
|
|
if (character == '\0')
|
|
return false;
|
|
|
|
return m_sharedString->string[0] < character || (m_sharedString->string[0] == character && m_sharedString->size == 1);
|
|
}
|
|
|
|
bool NzString::operator<=(const char* string) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return true;
|
|
|
|
if (!string || !string[0])
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string) <= 0;
|
|
}
|
|
|
|
bool NzString::operator<=(const std::string& string) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return true;
|
|
|
|
if (string.empty())
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string.c_str()) <= 0;
|
|
}
|
|
|
|
bool NzString::operator>(char character) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (character == '\0')
|
|
return true;
|
|
|
|
return m_sharedString->string[0] > character;
|
|
}
|
|
|
|
bool NzString::operator>(const char* string) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (!string || !string[0])
|
|
return true;
|
|
|
|
return std::strcmp(m_sharedString->string, string) > 0;
|
|
}
|
|
|
|
bool NzString::operator>(const std::string& string) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (string.empty())
|
|
return true;
|
|
|
|
return std::strcmp(m_sharedString->string, string.c_str()) > 0;
|
|
}
|
|
|
|
bool NzString::operator>=(char character) const
|
|
{
|
|
if (character == '\0')
|
|
return true;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
return m_sharedString->string[0] > character || (m_sharedString->string[0] == character && m_sharedString->size == 1);
|
|
}
|
|
|
|
bool NzString::operator>=(const char* string) const
|
|
{
|
|
if (!string || !string[0])
|
|
return true;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string) >= 0;
|
|
}
|
|
|
|
bool NzString::operator>=(const std::string& string) const
|
|
{
|
|
if (string.empty())
|
|
return true;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string.c_str()) >= 0;
|
|
}
|
|
|
|
NzString NzString::Boolean(bool boolean)
|
|
{
|
|
unsigned int size = (boolean) ? 4 : 5;
|
|
char* str = new char[size+1];
|
|
std::memcpy(str, (boolean) ? "true" : "false", size+1);
|
|
|
|
return NzString(new SharedString(1, size, size, str));
|
|
}
|
|
|
|
int NzString::Compare(const NzString& first, const NzString& second)
|
|
{
|
|
if (first.m_sharedString->size == 0)
|
|
return (second.m_sharedString->size == 0) ? 0 : -1;
|
|
|
|
if (second.m_sharedString->size == 0)
|
|
return 1;
|
|
|
|
return std::strcmp(first.m_sharedString->string, second.m_sharedString->string);
|
|
}
|
|
|
|
NzString NzString::Number(float number)
|
|
{
|
|
std::ostringstream oss;
|
|
oss.precision(NAZARA_CORE_DECIMAL_DIGITS);
|
|
oss << number;
|
|
|
|
return NzString(oss.str());
|
|
}
|
|
|
|
NzString NzString::Number(double number)
|
|
{
|
|
std::ostringstream oss;
|
|
oss.precision(NAZARA_CORE_DECIMAL_DIGITS);
|
|
oss << number;
|
|
|
|
return NzString(oss.str());
|
|
}
|
|
|
|
NzString NzString::Number(long double number)
|
|
{
|
|
std::ostringstream oss;
|
|
oss.precision(NAZARA_CORE_DECIMAL_DIGITS);
|
|
oss << number;
|
|
|
|
return NzString(oss.str());
|
|
}
|
|
|
|
NzString NzString::Number(signed char number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(unsigned char number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(short number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(unsigned short number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(int number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(unsigned int number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(long number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(unsigned long number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(long long number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(unsigned long long number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Pointer(const void* ptr)
|
|
{
|
|
const unsigned int size = sizeof(void*)*2 + 2;
|
|
|
|
char* str = new char[size+1];
|
|
std::sprintf(str, "0x%p", ptr);
|
|
|
|
return NzString(new SharedString(1, size, size, str));
|
|
}
|
|
|
|
NzString NzString::Unicode(char32_t character)
|
|
{
|
|
if (character == '\0')
|
|
return NzString();
|
|
|
|
unsigned int count = 0;
|
|
if (character < 0x80)
|
|
count = 1;
|
|
else if (character < 0x800)
|
|
count = 2;
|
|
else if (character < 0x10000)
|
|
count = 3;
|
|
else
|
|
count = 4;
|
|
|
|
char* str = new char[count+1];
|
|
utf8::append(character, str);
|
|
str[count] = '\0';
|
|
|
|
return NzString(new SharedString(1, count, count, str));
|
|
}
|
|
|
|
NzString NzString::Unicode(const char* u8String)
|
|
{
|
|
return NzString(u8String);
|
|
}
|
|
|
|
NzString NzString::Unicode(const char16_t* u16String)
|
|
{
|
|
if (!u16String || !u16String[0])
|
|
return NzString();
|
|
|
|
const char16_t* ptr = u16String;
|
|
unsigned int count = 0;
|
|
do
|
|
count++;
|
|
while (*++ptr);
|
|
|
|
count *= 2; // On s'assure d'avoir la place suffisante
|
|
|
|
char* str = new char[count+1];
|
|
char* r = utf8::utf16to8(u16String, ptr, str);
|
|
*r = '\0';
|
|
|
|
return NzString(new SharedString(1, count, r-str, str));
|
|
}
|
|
|
|
NzString NzString::Unicode(const char32_t* u32String)
|
|
{
|
|
if (!u32String || !u32String[0])
|
|
return NzString();
|
|
|
|
const char32_t* ptr = u32String;
|
|
unsigned int count = 0;
|
|
do
|
|
{
|
|
char32_t cp = *ptr;
|
|
if (cp < 0x80)
|
|
count += 1;
|
|
else if (cp < 0x800)
|
|
count += 2;
|
|
else if (cp < 0x10000)
|
|
count += 3;
|
|
else
|
|
count += 4;
|
|
}
|
|
while (*++ptr);
|
|
|
|
char* str = new char[count+1];
|
|
char* r = utf8::utf32to8(u32String, ptr, str);
|
|
*r = '\0';
|
|
|
|
return NzString(new SharedString(1, count, count, str));
|
|
}
|
|
|
|
NzString NzString::Unicode(const wchar_t* wString)
|
|
{
|
|
if (!wString || !wString[0])
|
|
return NzString();
|
|
|
|
const wchar_t* ptr = wString;
|
|
unsigned int count = 0;
|
|
do
|
|
{
|
|
char32_t cp = *ptr;
|
|
if (cp < 0x80)
|
|
count += 1;
|
|
else if (cp < 0x800)
|
|
count += 2;
|
|
else if (cp < 0x10000)
|
|
count += 3;
|
|
else
|
|
count += 4;
|
|
}
|
|
while (*++ptr);
|
|
|
|
char* str = new char[count+1];
|
|
char* r = utf8::utf32to8(wString, ptr, str);
|
|
*r = '\0';
|
|
|
|
return NzString(new SharedString(1, count, count, str));
|
|
}
|
|
|
|
std::istream& operator>>(std::istream& is, NzString& str)
|
|
{
|
|
str.Clear();
|
|
|
|
char c;
|
|
do
|
|
{
|
|
is.get(c);
|
|
if (c == '\0')
|
|
break;
|
|
else if (std::isspace(c))
|
|
{
|
|
if (str.IsNull())
|
|
continue;
|
|
else
|
|
break;
|
|
}
|
|
else
|
|
str += c;
|
|
}
|
|
while (true);
|
|
|
|
return is;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, const NzString& str)
|
|
{
|
|
if (str.IsEmpty())
|
|
return os;
|
|
|
|
return operator<<(os, str.m_sharedString->string);
|
|
}
|
|
|
|
NzString operator+(char character, const NzString& string)
|
|
{
|
|
if (character == '\0')
|
|
return string;
|
|
|
|
if (string.IsEmpty())
|
|
return NzString(character);
|
|
|
|
unsigned int totalSize = string.m_sharedString->size+1;
|
|
char* str = new char[totalSize+1];
|
|
str[0] = character;
|
|
std::memcpy(&str[1], string.m_sharedString->string, string.m_sharedString->size+1);
|
|
|
|
return NzString(new NzString::SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
NzString operator+(const char* string, const NzString& nstring)
|
|
{
|
|
if (!string || !string[0])
|
|
return nstring;
|
|
|
|
if (nstring.IsEmpty())
|
|
return string;
|
|
|
|
unsigned int size = std::strlen(string);
|
|
unsigned int totalSize = size + nstring.m_sharedString->size;
|
|
char* str = new char[totalSize+1];
|
|
std::memcpy(str, string, size);
|
|
std::memcpy(&str[size], nstring.m_sharedString->string, nstring.m_sharedString->size+1);
|
|
|
|
return NzString(new NzString::SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
NzString operator+(const std::string& string, const NzString& nstring)
|
|
{
|
|
if (string.empty())
|
|
return nstring;
|
|
|
|
if (nstring.m_sharedString->size == 0)
|
|
return string;
|
|
|
|
unsigned int totalSize = string.size() + nstring.m_sharedString->size;
|
|
char* str = new char[totalSize+1];
|
|
std::memcpy(str, string.c_str(), string.size());
|
|
std::memcpy(&str[string.size()], nstring.m_sharedString->string, nstring.m_sharedString->size+1);
|
|
|
|
return NzString(new NzString::SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
bool operator==(const NzString& first, const NzString& second)
|
|
{
|
|
if (first.m_sharedString->size == 0 || second.m_sharedString->size == 0)
|
|
return first.m_sharedString->size == second.m_sharedString->size;
|
|
|
|
if (first.m_sharedString->size != second.m_sharedString->size)
|
|
return false;
|
|
|
|
if (first.m_sharedString == second.m_sharedString)
|
|
return true;
|
|
|
|
return std::strcmp(first.m_sharedString->string, second.m_sharedString->string) == 0;
|
|
}
|
|
|
|
bool operator!=(const NzString& first, const NzString& second)
|
|
{
|
|
return !operator==(first, second);
|
|
}
|
|
|
|
bool operator<(const NzString& first, const NzString& second)
|
|
{
|
|
if (second.m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (first.m_sharedString->size == 0)
|
|
return true;
|
|
|
|
return std::strcmp(first.m_sharedString->string, second.m_sharedString->string) < 0;
|
|
}
|
|
|
|
bool operator<=(const NzString& first, const NzString& second)
|
|
{
|
|
return !operator<(second, first);
|
|
}
|
|
|
|
bool operator>(const NzString& first, const NzString& second)
|
|
{
|
|
return second < first;
|
|
}
|
|
|
|
bool operator>=(const NzString& first, const NzString& second)
|
|
{
|
|
return !operator<(first, second);
|
|
}
|
|
|
|
bool operator==(char character, const NzString& nstring)
|
|
{
|
|
return nstring == character;
|
|
}
|
|
|
|
bool operator==(const char* string, const NzString& nstring)
|
|
{
|
|
return nstring == string;
|
|
}
|
|
|
|
bool operator==(const std::string& string, const NzString& nstring)
|
|
{
|
|
return nstring == string;
|
|
}
|
|
|
|
bool operator!=(char character, const NzString& nstring)
|
|
{
|
|
return !operator==(character, nstring);
|
|
}
|
|
|
|
bool operator!=(const char* string, const NzString& nstring)
|
|
{
|
|
return !operator==(string, nstring);
|
|
}
|
|
|
|
bool operator!=(const std::string& string, const NzString& nstring)
|
|
{
|
|
return !operator==(string, nstring);
|
|
}
|
|
|
|
bool operator<(char character, const NzString& nstring)
|
|
{
|
|
return nstring > character;
|
|
}
|
|
|
|
bool operator<(const char* string, const NzString& nstring)
|
|
{
|
|
return nstring > string;
|
|
}
|
|
|
|
bool operator<(const std::string& string, const NzString& nstring)
|
|
{
|
|
return nstring > string;
|
|
}
|
|
|
|
bool operator<=(char character, const NzString& nstring)
|
|
{
|
|
return !operator<(nstring, NzString(character));
|
|
}
|
|
|
|
bool operator<=(const char* string, const NzString& nstring)
|
|
{
|
|
return !operator<(nstring, string);
|
|
}
|
|
|
|
bool operator<=(const std::string& string, const NzString& nstring)
|
|
{
|
|
return !operator<(nstring, string);
|
|
}
|
|
|
|
bool operator>(char character, const NzString& nstring)
|
|
{
|
|
return nstring < character;
|
|
}
|
|
|
|
bool operator>(const char* string, const NzString& nstring)
|
|
{
|
|
return nstring < string;
|
|
}
|
|
|
|
bool operator>(const std::string& string, const NzString& nstring)
|
|
{
|
|
return nstring < string;
|
|
}
|
|
|
|
bool operator>=(char character, const NzString& nstring)
|
|
{
|
|
return !operator<(character, nstring);
|
|
}
|
|
|
|
bool operator>=(const char* string, const NzString& nstring)
|
|
{
|
|
return !operator<(string, nstring);
|
|
}
|
|
|
|
bool operator>=(const std::string& string, const NzString& nstring)
|
|
{
|
|
return !operator<(string, nstring);
|
|
}
|
|
|
|
void NzString::EnsureOwnership(bool discardContent)
|
|
{
|
|
if (m_sharedString == &emptyString)
|
|
return;
|
|
|
|
if (m_sharedString->refCount > 1)
|
|
{
|
|
m_sharedString->refCount--;
|
|
|
|
char* string = new char[m_sharedString->capacity+1];
|
|
if (!discardContent)
|
|
std::memcpy(string, m_sharedString->string, m_sharedString->size+1);
|
|
|
|
m_sharedString = new SharedString(1, m_sharedString->capacity, m_sharedString->size, string);
|
|
}
|
|
}
|
|
|
|
bool NzString::FillHash(NzAbstractHash* hash) const
|
|
{
|
|
hash->Append(reinterpret_cast<const nzUInt8*>(m_sharedString->string), m_sharedString->size);
|
|
|
|
return true;
|
|
}
|
|
|
|
void NzString::ReleaseString()
|
|
{
|
|
if (m_sharedString == &emptyString)
|
|
return;
|
|
|
|
if (--m_sharedString->refCount == 0)
|
|
{
|
|
delete[] m_sharedString->string;
|
|
delete m_sharedString;
|
|
}
|
|
|
|
m_sharedString = &emptyString;
|
|
}
|
|
|
|
NzString::SharedString NzString::emptyString(0, 0, 0, nullptr);
|
|
const unsigned int NzString::npos(std::numeric_limits<unsigned int>::max());
|
|
|
|
namespace std
|
|
{
|
|
istream& getline(istream& is, NzString& str)
|
|
{
|
|
str.Clear();
|
|
|
|
char c;
|
|
do
|
|
{
|
|
is.get(c);
|
|
if (c != '\n' && c != '\0')
|
|
str += c;
|
|
else
|
|
break;
|
|
}
|
|
while (true);
|
|
|
|
return is;
|
|
}
|
|
|
|
istream& getline(istream& is, NzString& str, char delim)
|
|
{
|
|
str.Clear();
|
|
|
|
char c;
|
|
do
|
|
{
|
|
is.get(c);
|
|
if (c != delim && c != '\0')
|
|
str += c;
|
|
else
|
|
break;
|
|
}
|
|
while (true);
|
|
|
|
return is;
|
|
}
|
|
|
|
void swap(NzString& lhs, NzString& rhs)
|
|
{
|
|
lhs.Swap(rhs);
|
|
}
|
|
}
|