1427 lines
32 KiB
C++
1427 lines
32 KiB
C++
#ifndef N_STRING_H
|
|
#define N_STRING_H
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
@스트링 클래스
|
|
|
|
@author
|
|
- RadonLabs GmbH
|
|
|
|
@since
|
|
- 2005.6.13
|
|
@remarks
|
|
- 지완 추가
|
|
*/
|
|
//------------------------------------------------------------------------------
|
|
|
|
#pragma once
|
|
#include "../ProgramCommon/Define.h"
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
//#using <mscorlib.dll>
|
|
//using namespace System;
|
|
|
|
#include "Narray.h"
|
|
|
|
|
|
class nString
|
|
{
|
|
public:
|
|
/// constructor
|
|
nString();
|
|
/// constructor 1
|
|
nString(const char* str);
|
|
/// copy constructor
|
|
nString(const nString& rhs);
|
|
/// set to int val
|
|
nString(int intVal);
|
|
/// set to float val
|
|
nString(float floatVal);
|
|
/// destructor
|
|
~nString();
|
|
/// = operator
|
|
nString& operator=(const nString& rhs);
|
|
/// = operator with string
|
|
nString& operator=(const char* rhs);
|
|
/// += operator with char*
|
|
nString& operator+=(const char* rhs);
|
|
/// += operator with string
|
|
nString& operator+=(const nString& rhs);
|
|
/// Is `a' equal to `b'?
|
|
friend bool operator == (const nString& a, const nString& b);
|
|
/// Is `a' inequal to `b'?
|
|
friend bool operator != (const nString& a, const nString& b);
|
|
/// Is `a' > to `b'?
|
|
friend bool operator > (const nString& a, const nString& b);
|
|
/// Is `a' < to `b'?
|
|
friend bool operator < (const nString& a, const nString& b);
|
|
/// Is `a' >= to `b'?
|
|
friend bool operator >= (const nString& a, const nString& b);
|
|
/// Is `a' <= to `b'?
|
|
friend bool operator <= (const nString& a, const nString& b);
|
|
/// Subscript operator (read only).
|
|
const char operator[](int i) const;
|
|
/// Subscript operator (writeable).
|
|
char& operator[](int i);
|
|
/// set as char ptr, with explicit length
|
|
void Set(const char* ptr, int length);
|
|
/// set as char ptr
|
|
void Set(const char* str);
|
|
/// set as int value
|
|
void SetInt(int val);
|
|
/// set as float value
|
|
void SetFloat(float val);
|
|
/// get string as char ptr
|
|
const char* Get() const;
|
|
/// return content as integer
|
|
int AsInt() const;
|
|
/// return content as float
|
|
float AsFloat() const;
|
|
/// return length of string
|
|
int Length() const;
|
|
/// clear the string
|
|
void Clear();
|
|
/// return true if string object is empty
|
|
bool IsEmpty() const;
|
|
/// append character pointer
|
|
void Append(const char* str);
|
|
/// append string
|
|
void Append(const nString& str);
|
|
/// append a range of characters
|
|
void AppendRange(const char* str, uint numChars);
|
|
/// append int value
|
|
void AppendInt(int val);
|
|
/// append float value
|
|
void AppendFloat(float val);
|
|
/// convert string to lower case
|
|
void ToLower();
|
|
/// convert string to upper case
|
|
void ToUpper();
|
|
/// get first token (this will destroy the string)
|
|
const char* GetFirstToken(const char* whiteSpace);
|
|
/// get next token (this will destroy the string)
|
|
const char* GetNextToken(const char* whiteSpace);
|
|
/// tokenize string into a provided nString array
|
|
int Tokenize(const char* whiteSpace, nArray<nString>& tokens) const;
|
|
/// extract substring
|
|
nString ExtractRange(int from, int to) const;
|
|
/// terminate string at first occurence of character in set
|
|
void Strip(const char* charSet);
|
|
/// Index of first appearance of `v' starting from index `startIndex'.
|
|
int IndexOf(const nString& v, int startIndex) const;
|
|
/// return index of character in string
|
|
int FindChar(unsigned char c, int startIndex) const;
|
|
/// terminate string at given index
|
|
void TerminateAtIndex(int index);
|
|
/// strip slash at end of path, if exists
|
|
void StripTrailingSlash();
|
|
/// delete characters from charset at left side of string
|
|
nString TrimLeft(const char* charSet) const;
|
|
/// delete characters from charset at right side of string
|
|
nString TrimRight(const char* charSet) const;
|
|
/// trim characters from charset at both sides of string
|
|
nString Trim(const char* charSet) const;
|
|
/// substitute every occurance of a string with another string
|
|
nString Substitute(const char* str, const char* substStr) const;
|
|
/// convert string inplace from UTF-8 to 8-bit ANSI
|
|
void UTF8toANSI();
|
|
/// convert ANSI to UTF-8 in place
|
|
void ANSItoUTF8();
|
|
/// get pointer to extension (without the dot)
|
|
const char* GetExtension() const;
|
|
/// check if extension matches (no dot in the extension!)
|
|
bool CheckExtension(const char* ext) const;
|
|
/// convert backslashes to slashes
|
|
void ConvertBackslashes();
|
|
/// remove extension
|
|
void StripExtension();
|
|
/// extract the part after the last directory separator
|
|
nString ExtractFileName() const;
|
|
/// extract the last directory of the path
|
|
nString ExtractLastDirName() const;
|
|
/// extract the part before the last directory separator
|
|
nString ExtractDirName() const;
|
|
/// extract path until last slash
|
|
nString ExtractToLastSlash() const;
|
|
/// check if this string matches the given pattern
|
|
// bool MatchPattern(const nString& pattern) const;
|
|
/// 숫자 인지 검사
|
|
bool IsNumberic();
|
|
|
|
|
|
protected:
|
|
/// copy contents
|
|
void Copy(const nString& src);
|
|
/// delete contents
|
|
void Delete();
|
|
/// get pointer to last directory separator
|
|
char* GetLastSlash() const;
|
|
|
|
enum
|
|
{
|
|
LOCALSTRINGSIZE = 14,
|
|
};
|
|
char* string;
|
|
char localString[LOCALSTRINGSIZE];
|
|
ushort strLen;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** global
|
|
*/
|
|
/*
|
|
bool
|
|
n_strmatch(const char* str, const char* pat)
|
|
{
|
|
char c2;
|
|
|
|
while (true)
|
|
{
|
|
if (*pat == 0)
|
|
{
|
|
if (*str == 0) return true;
|
|
else return false;
|
|
}
|
|
if ((*str == 0) && (*pat != '*')) return false;
|
|
if (*pat=='*')
|
|
{
|
|
pat++;
|
|
if (*pat==0) return true;
|
|
while (true)
|
|
{
|
|
if (n_strmatch(str, pat)) return true;
|
|
if (*str==0) return false;
|
|
str++;
|
|
}
|
|
}
|
|
if (*pat=='?') goto match;
|
|
if (*pat=='[')
|
|
{
|
|
pat++;
|
|
while (true)
|
|
{
|
|
if ((*pat==']') || (*pat==0)) return false;
|
|
if (*pat==*str) break;
|
|
if (pat[1] == '-')
|
|
{
|
|
c2 = pat[2];
|
|
if (c2==0) return false;
|
|
if ((*pat<=*str) && (c2>=*str)) break;
|
|
if ((*pat>=*str) && (c2<=*str)) break;
|
|
pat+=2;
|
|
}
|
|
pat++;
|
|
}
|
|
while (*pat!=']')
|
|
{
|
|
if (*pat==0)
|
|
{
|
|
pat--;
|
|
break;
|
|
}
|
|
pat++;
|
|
}
|
|
goto match;
|
|
}
|
|
|
|
if (*pat=='\\')
|
|
{
|
|
pat++;
|
|
if (*pat==0) return false;
|
|
}
|
|
if (*pat!=*str) return false;
|
|
|
|
match:
|
|
pat++;
|
|
str++;
|
|
}
|
|
}
|
|
*/
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
nString::nString() :
|
|
string(0),
|
|
strLen(0)
|
|
{
|
|
this->localString[0] = 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::Delete()
|
|
{
|
|
if (this->string)
|
|
{
|
|
free((void*) this->string);
|
|
this->string = 0;
|
|
}
|
|
this->localString[0] = 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
nString::~nString()
|
|
{
|
|
this->Delete();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::Set(const char* str, int length)
|
|
{
|
|
this->Delete();
|
|
if (str)
|
|
{
|
|
this->strLen = length;
|
|
char* ptr = this->localString;
|
|
if (strLen >= LOCALSTRINGSIZE)
|
|
{
|
|
ptr = (char*) malloc(strLen + 1);
|
|
this->string = ptr;
|
|
}
|
|
else
|
|
{
|
|
ptr = this->localString;
|
|
}
|
|
int i;
|
|
for (i = 0; i < strLen; i++)
|
|
{
|
|
*ptr++ = *str++;
|
|
}
|
|
*ptr = 0;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::Set(const char* str)
|
|
{
|
|
size_t len = 0;
|
|
if (str)
|
|
{
|
|
len = strlen(str);
|
|
}
|
|
this->Set(str, static_cast<int>(len));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::SetInt(int val)
|
|
{
|
|
char buf[128];
|
|
_snprintf(buf, sizeof(buf), "%d", val);
|
|
this->Set(buf);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::SetFloat(float val)
|
|
{
|
|
char buf[128];
|
|
_snprintf(buf, sizeof(buf), "%.6f", val);
|
|
this->Set(buf);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::Copy(const nString& src)
|
|
{
|
|
ASSERT(0 == this->string);
|
|
const char* str = src.Get();
|
|
if (str)
|
|
{
|
|
this->Set(str);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
nString::nString(const char* str) :
|
|
string(0),
|
|
strLen(0)
|
|
{
|
|
this->localString[0] = 0;
|
|
this->Set(str);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
nString::nString(const nString& rhs) :
|
|
string(0),
|
|
strLen(0)
|
|
{
|
|
this->localString[0] = 0;
|
|
this->Copy(rhs);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
nString::nString(int intVal) :
|
|
string(0),
|
|
strLen(0)
|
|
{
|
|
this->SetInt(intVal);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
nString::nString(float floatVal) :
|
|
string(0),
|
|
strLen(0)
|
|
{
|
|
this->SetFloat(floatVal);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
const char*
|
|
nString::Get() const
|
|
{
|
|
if (this->string)
|
|
{
|
|
return this->string;
|
|
}
|
|
else if (this->localString[0])
|
|
{
|
|
return this->localString;
|
|
}
|
|
else
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
nString&
|
|
nString::operator=(const nString& rhs)
|
|
{
|
|
if (&rhs != this)
|
|
{
|
|
this->Delete();
|
|
this->Copy(rhs);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
nString&
|
|
nString::operator=(const char* rhs)
|
|
{
|
|
this->Set(rhs);
|
|
return *this;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::AppendRange(const char* str, uint numChars)
|
|
{
|
|
ASSERT(str);
|
|
if (numChars > 0)
|
|
{
|
|
ushort rlen = numChars;
|
|
ushort tlen = this->strLen + rlen;
|
|
if (this->string)
|
|
{
|
|
char* ptr = (char*) malloc(tlen + 1);
|
|
strcpy(ptr, this->string);
|
|
strncat(ptr, str, numChars);
|
|
free((void*) this->string);
|
|
this->string = ptr;
|
|
this->strLen = tlen;
|
|
}
|
|
else if (this->localString[0])
|
|
{
|
|
if (tlen >= LOCALSTRINGSIZE)
|
|
{
|
|
char* ptr = (char*) malloc(tlen + 1);
|
|
strcpy(ptr, this->localString);
|
|
strncat(ptr, str, numChars);
|
|
this->localString[0] = 0;
|
|
this->string = ptr;
|
|
}
|
|
else
|
|
{
|
|
strncat(this->localString, str, numChars);
|
|
}
|
|
this->strLen = tlen;
|
|
}
|
|
else
|
|
{
|
|
this->Set(str, numChars);
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::Append(const char* str)
|
|
{
|
|
ASSERT(str);
|
|
size_t len = strlen(str);
|
|
this->AppendRange(str, static_cast<uint>(len));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::Append(const nString& str)
|
|
{
|
|
this->Append(str.Get());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::AppendInt(int val)
|
|
{
|
|
nString str;
|
|
str.SetInt(val);
|
|
this->Append(str);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::AppendFloat(float val)
|
|
{
|
|
nString str;
|
|
str.SetFloat(val);
|
|
this->Append(str);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
nString&
|
|
nString::operator+=(const char* rhs)
|
|
{
|
|
this->Append(rhs);
|
|
return *this;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
nString&
|
|
nString::operator+=(const nString& rhs)
|
|
{
|
|
this->Append(rhs.Get());
|
|
return *this;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
bool
|
|
operator == (const nString& a, const nString& b)
|
|
{
|
|
return strcmp(a.Get(), b.Get()) == 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
bool
|
|
operator != (const nString& a, const nString& b)
|
|
{
|
|
return strcmp(a.Get(), b.Get()) != 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
bool
|
|
operator > (const nString& a, const nString& b)
|
|
{
|
|
return strcmp(a.Get(), b.Get()) > 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
bool
|
|
operator < (const nString& a, const nString& b)
|
|
{
|
|
return strcmp(a.Get(), b.Get()) < 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
bool
|
|
operator >= (const nString& a, const nString& b)
|
|
{
|
|
return strcmp(a.Get(), b.Get()) >= 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
bool
|
|
operator <= (const nString& a, const nString& b)
|
|
{
|
|
return strcmp(a.Get(), b.Get()) <= 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
const char
|
|
nString::operator[](int i) const
|
|
{
|
|
ASSERT((0 <= i) && (i <= (strLen - 1)));
|
|
if (this->string != 0)
|
|
{
|
|
return this->string[i];
|
|
}
|
|
else
|
|
{
|
|
return this->localString[i];
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
char&
|
|
nString::operator[](int i)
|
|
{
|
|
ASSERT((0 <= i) && (i <= (strLen - 1)));
|
|
if (this->string != 0)
|
|
{
|
|
return this->string[i];
|
|
}
|
|
else
|
|
{
|
|
return this->localString[i];
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
int
|
|
nString::Length() const
|
|
{
|
|
return this->strLen;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::Clear()
|
|
{
|
|
this->Delete();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
bool
|
|
nString::IsEmpty() const
|
|
{
|
|
if (this->string && (this->string[0] != 0))
|
|
{
|
|
return false;
|
|
}
|
|
else if (this->localString[0] != 0)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::ToLower()
|
|
{
|
|
char* str = (char*) (this->string ? this->string : this->localString);
|
|
if (str)
|
|
{
|
|
char c;
|
|
char* ptr = (char*) str;
|
|
while ((c = *ptr))
|
|
{
|
|
*ptr++ = tolower(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nString::ToUpper()
|
|
{
|
|
char* str = (char*) (this->string ? this->string : this->localString);
|
|
if (str)
|
|
{
|
|
char c;
|
|
char* ptr = (char*) str;
|
|
while ((c = *ptr))
|
|
{
|
|
*ptr++ = toupper(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
static
|
|
inline
|
|
nString
|
|
operator+(const nString& s0, const nString& s1)
|
|
{
|
|
nString newString = s0;
|
|
newString.Append(s1.Get());
|
|
return newString;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Get the first token in the string, delimited by one or more of the
|
|
character in 'whiteSpace'. This simply invokes the strtok() function
|
|
internally, and will destroy the contained string. After calling
|
|
GetFirstToken(), invoke GetNextToken() until 0 returns.
|
|
|
|
ATTENTION: if somebody else calls strtok() while GetFirstToken()/
|
|
GetNextToken() is underway, everything will break apart!
|
|
Check out the Tokenize() method for a better alternative.
|
|
|
|
@param whiteSpace string containing white space characters
|
|
*/
|
|
inline
|
|
const char*
|
|
nString::GetFirstToken(const char* whiteSpace)
|
|
{
|
|
ASSERT(whiteSpace);
|
|
return strtok((char*) this->Get(), whiteSpace);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Get the next token in the string. Call this after a GetFirstToken()
|
|
or GetNextToken(). Returns 0 if no more tokens in string. This method
|
|
will destroy the original string.
|
|
|
|
ATTENTION: if somebody else calls strtok() while GetFirstToken()/
|
|
GetNextToken() is underway, everything will break apart!
|
|
Check out the Tokenize() method for a better alternative.
|
|
|
|
@param whiteSpace string containing whitespace characters
|
|
*/
|
|
inline
|
|
const char*
|
|
nString::GetNextToken(const char* whiteSpace)
|
|
{
|
|
ASSERT(whiteSpace);
|
|
return strtok(0, whiteSpace);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Tokenize the string into a provided nString array. Returns the number
|
|
of tokens. This method is recommended over GetFirstToken()/GetNextToken(),
|
|
since it is atomic. This nString object will not be destroyed
|
|
(as is the case with GetFirstToken()/GetNextToken().
|
|
|
|
@param whiteSpace [in] a string containing the whitespace characters
|
|
@param tokens [out] nArray<nString> where tokens will be appended
|
|
@return number of tokens found
|
|
*/
|
|
inline
|
|
int
|
|
nString::Tokenize(const char* whiteSpace, nArray<nString>& tokens) const
|
|
{
|
|
int numTokens = 0;
|
|
|
|
// create a temporary string, which will be destroyed during the operation
|
|
nString str(*this);
|
|
char* ptr = (char*) str.Get();
|
|
const char* token;
|
|
while (0 != (token = strtok(ptr, whiteSpace)))
|
|
{
|
|
tokens.Append(nString(token));
|
|
ptr = 0;
|
|
numTokens++;
|
|
}
|
|
return numTokens;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Extract sub string.
|
|
*/
|
|
inline
|
|
nString
|
|
nString::ExtractRange(int from, int numChars) const
|
|
{
|
|
ASSERT(from <= this->strLen);
|
|
ASSERT((from + numChars) <= this->strLen);
|
|
const char* str = this->Get();
|
|
nString newString;
|
|
newString.Set(&(str[from]), numChars);
|
|
return newString;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Terminates the string at the first occurance of one of the characters
|
|
in charSet.
|
|
*/
|
|
inline
|
|
void
|
|
nString::Strip(const char* charSet)
|
|
{
|
|
ASSERT(charSet);
|
|
char* str = (char*) this->Get();
|
|
char* ptr = strpbrk(str, charSet);
|
|
if (ptr)
|
|
{
|
|
*ptr = 0;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
@result Index or -1 if not found.
|
|
*/
|
|
inline
|
|
int
|
|
nString::IndexOf(const nString& v, int startIndex) const
|
|
{
|
|
ASSERT(0 <= startIndex && startIndex <= Length() - 1);
|
|
ASSERT(!v.IsEmpty());
|
|
|
|
for (int i = startIndex; i < Length(); i++)
|
|
{
|
|
if (Length() - i < v.Length())
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (strncmp(&(Get()[i]), v.Get(), v.Length()) == 0)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Return index of character in string, or -1 if not found.
|
|
*/
|
|
inline
|
|
int
|
|
nString::FindChar(unsigned char c, int startIndex) const
|
|
{
|
|
if (this->Length() > 0)
|
|
{
|
|
ASSERT(startIndex < this->Length());
|
|
const char* ptr = strchr(this->Get() + startIndex, c);
|
|
if (ptr)
|
|
{
|
|
return static_cast<int>(ptr - this->Get());
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Terminates the string at the given index.
|
|
*/
|
|
inline
|
|
void
|
|
nString::TerminateAtIndex(int index)
|
|
{
|
|
ASSERT(index < this->Length());
|
|
char* ptr = (char*) this->Get();
|
|
ptr[index] = 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Strips last slash, if the path name ends on a slash.
|
|
*/
|
|
inline
|
|
void
|
|
nString::StripTrailingSlash()
|
|
{
|
|
if (this->strLen > 0)
|
|
{
|
|
int pos = strLen - 1;
|
|
char* str = (char*) this->Get();
|
|
if ((str[pos] == '/') || (str[pos] == '\\'))
|
|
{
|
|
str[pos] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Returns a new string which is this string, stripped on the left side
|
|
by all characters in the char set.
|
|
*/
|
|
inline
|
|
nString
|
|
nString::TrimLeft(const char* charSet) const
|
|
{
|
|
ASSERT(charSet);
|
|
if (this->IsEmpty())
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
int charSetLen = static_cast<int>(strlen(charSet));
|
|
int thisIndex = 0;
|
|
bool stopped = false;
|
|
while (!stopped && (thisIndex < this->strLen))
|
|
{
|
|
int charSetIndex;
|
|
bool match = false;
|
|
for (charSetIndex = 0; charSetIndex < charSetLen; charSetIndex++)
|
|
{
|
|
if ((*this)[thisIndex] == charSet[charSetIndex])
|
|
{
|
|
// a match
|
|
match = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!match)
|
|
{
|
|
// stop if no match
|
|
stopped = true;
|
|
}
|
|
else
|
|
{
|
|
// a match, advance to next character
|
|
++thisIndex;
|
|
}
|
|
}
|
|
nString trimmedString(&(this->Get()[thisIndex]));
|
|
return trimmedString;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Returns a new string, which is this string, stripped on the right side
|
|
by all characters in the char set.
|
|
*/
|
|
inline
|
|
nString
|
|
nString::TrimRight(const char* charSet) const
|
|
{
|
|
ASSERT(charSet);
|
|
if (this->IsEmpty())
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
int charSetLen = static_cast<int>(strlen(charSet));
|
|
int thisIndex = this->strLen - 1;
|
|
bool stopped = false;
|
|
while (!stopped && (thisIndex < this->strLen))
|
|
{
|
|
int charSetIndex;
|
|
bool match = false;
|
|
for (charSetIndex = 0; charSetIndex < charSetLen; charSetIndex++)
|
|
{
|
|
if ((*this)[thisIndex] == charSet[charSetIndex])
|
|
{
|
|
// a match
|
|
match = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!match)
|
|
{
|
|
// stop if no match
|
|
stopped = true;
|
|
}
|
|
else
|
|
{
|
|
// a match, advance to next character
|
|
--thisIndex;
|
|
}
|
|
}
|
|
nString trimmedString;
|
|
trimmedString.Set(this->Get(), thisIndex + 1);
|
|
return trimmedString;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Trim both sides of a string.
|
|
*/
|
|
inline
|
|
nString
|
|
nString::Trim(const char* charSet) const
|
|
{
|
|
return this->TrimLeft(charSet).TrimRight(charSet);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Substitute every occurance of origStr with substStr.
|
|
*/
|
|
inline
|
|
nString
|
|
nString::Substitute(const char* matchStr, const char* substStr) const
|
|
{
|
|
ASSERT(matchStr && substStr);
|
|
|
|
const char* ptr = this->Get();
|
|
int matchStrLen = static_cast<int>(strlen(matchStr));
|
|
nString dest;
|
|
|
|
// walk original string for occurances of str
|
|
const char* occur;
|
|
while ((occur = strstr(ptr, matchStr)))
|
|
{
|
|
// append string fragment until match
|
|
dest.AppendRange(ptr, static_cast<uint>(occur - ptr));
|
|
|
|
// append replacement string
|
|
dest.Append(substStr);
|
|
|
|
// adjust source pointer
|
|
ptr = occur + matchStrLen;
|
|
}
|
|
dest.Append(ptr);
|
|
return dest;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Returns content as integer.
|
|
*/
|
|
inline
|
|
int
|
|
nString::AsInt() const
|
|
{
|
|
const char* ptr = this->Get();
|
|
return atoi(ptr);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Returns content as float.
|
|
*/
|
|
inline
|
|
float
|
|
nString::AsFloat() const
|
|
{
|
|
const char* ptr = this->Get();
|
|
return float(atof(ptr));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
This converts an UTF-8 string to 8-bit-ANSI. Note that only characters
|
|
in the range 0 .. 255 are converted, all other characters will be converted
|
|
to a question mark.
|
|
|
|
For conversion rules see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
*/
|
|
inline
|
|
void
|
|
nString::UTF8toANSI()
|
|
{
|
|
uchar* src = (uchar*) this->Get();
|
|
uchar* dst = src;
|
|
uchar c;
|
|
while ((c = *src++))
|
|
{
|
|
if (c >= 0x80)
|
|
{
|
|
if ((c & 0xE0) == 0xC0)
|
|
{
|
|
// a 2 byte sequence with 11 bits of information
|
|
ushort wide = ((c & 0x1F) << 6) | (*src++ & 0x3F);
|
|
if (wide > 0xff)
|
|
{
|
|
c = '?';
|
|
}
|
|
else
|
|
{
|
|
c = (uchar) wide;
|
|
}
|
|
}
|
|
else if ((c & 0xF0) == 0xE0)
|
|
{
|
|
// a 3 byte sequence with 16 bits of information
|
|
c = '?';
|
|
src += 2;
|
|
}
|
|
else if ((c & 0xF8) == 0xF0)
|
|
{
|
|
// a 4 byte sequence with 21 bits of information
|
|
c = '?';
|
|
src += 3;
|
|
}
|
|
else if ((c & 0xFC) == 0xF8)
|
|
{
|
|
// a 5 byte sequence with 26 bits of information
|
|
c = '?';
|
|
src += 4;
|
|
}
|
|
else if ((c & 0xFE) == 0xFC)
|
|
{
|
|
// a 6 byte sequence with 31 bits of information
|
|
c = '?';
|
|
src += 5;
|
|
}
|
|
}
|
|
*dst++ = c;
|
|
}
|
|
*dst = 0;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Convert contained ANSI string to UTF-8 in place.
|
|
*/
|
|
inline
|
|
void
|
|
nString::ANSItoUTF8()
|
|
{
|
|
ASSERT(!this->IsEmpty());
|
|
int bufSize = this->Length() * 2 + 1;
|
|
char* buffer = new char[bufSize];
|
|
char* dstPtr = buffer;
|
|
const char* srcPtr = this->Get();
|
|
unsigned char c;
|
|
while ((c = *srcPtr++))
|
|
{
|
|
// note: this only covers the 2 cases that the character
|
|
// is between 0 and 127 and between 128 and 255
|
|
if (c < 128)
|
|
{
|
|
*dstPtr++ = c;
|
|
}
|
|
else
|
|
{
|
|
*dstPtr++ = 192 + (c / 64);
|
|
*dstPtr++ = 128 + (c % 64);
|
|
}
|
|
}
|
|
*dstPtr = 0;
|
|
this->Set(buffer);
|
|
delete[] buffer;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Converts backslashes to slashes.
|
|
*/
|
|
inline
|
|
void
|
|
nString::ConvertBackslashes()
|
|
{
|
|
char* ptr = (char*) this->Get();
|
|
int i;
|
|
for (i = 0; i <= this->strLen; i++)
|
|
{
|
|
if (ptr[i] == '\\')
|
|
{
|
|
ptr[i] = '/';
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
@return pointer to extension (without the dot), or 0
|
|
*/
|
|
inline
|
|
const char*
|
|
nString::GetExtension() const
|
|
{
|
|
const char* str = this->Get();
|
|
const char* ext = strrchr(str, '.');
|
|
if (ext)
|
|
{
|
|
ext++;
|
|
if (ext[0] != 0)
|
|
{
|
|
return ext;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Returns true if file extension matches.
|
|
|
|
@param ext extension string (without the dot)
|
|
@return true if extension matches
|
|
*/
|
|
inline
|
|
bool
|
|
nString::CheckExtension(const char* ext) const
|
|
{
|
|
ASSERT(ext);
|
|
const char* extStr = this->GetExtension();
|
|
if (0 == extStr)
|
|
{
|
|
return false;
|
|
}
|
|
return (0 == (strcmp(ext, extStr)));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Remove the file extension.
|
|
*/
|
|
inline
|
|
void
|
|
nString::StripExtension()
|
|
{
|
|
char* ext = (char*) this->GetExtension();
|
|
if (ext)
|
|
{
|
|
ext[-1] = 0;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Get a pointer to the last directory separator.
|
|
*/
|
|
inline
|
|
char*
|
|
nString::GetLastSlash() const
|
|
{
|
|
char* s = (char*) this->Get();
|
|
char* lastSlash = strrchr(s, '/');
|
|
if (0 == lastSlash) lastSlash = strrchr(s, '\\');
|
|
if (0 == lastSlash) lastSlash = strrchr(s, ':');
|
|
return lastSlash;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Return a nString object containing the part after the last
|
|
path separator.
|
|
*/
|
|
inline
|
|
nString
|
|
nString::ExtractFileName() const
|
|
{
|
|
nString pathString;
|
|
char* lastSlash = this->GetLastSlash();
|
|
if (lastSlash)
|
|
{
|
|
pathString = &(lastSlash[1]);
|
|
}
|
|
else
|
|
{
|
|
pathString = this->Get();
|
|
}
|
|
return pathString;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
해당 문자열이 숫자로 구성 되었는지 검사 한다-완
|
|
*/
|
|
inline
|
|
bool
|
|
nString::IsNumberic()
|
|
{
|
|
int len=this->Length();
|
|
nString str=this->Get();
|
|
|
|
for(int i=0;i<len;i++)
|
|
{
|
|
if(isdigit(str[i])==0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Return a nString object containing the last directory of the path, i.e.
|
|
a category.
|
|
|
|
- 17-Feb-04 floh fixed a bug when the path ended with a slash
|
|
*/
|
|
inline
|
|
nString
|
|
nString::ExtractLastDirName() const
|
|
{
|
|
nString pathString(*this);
|
|
char* lastSlash = pathString.GetLastSlash();
|
|
|
|
// special case if path ends with a slash
|
|
if (lastSlash)
|
|
{
|
|
if (0 == lastSlash[1])
|
|
{
|
|
*lastSlash = 0;
|
|
lastSlash = pathString.GetLastSlash();
|
|
}
|
|
|
|
char* secLastSlash = 0;
|
|
if (0 != lastSlash)
|
|
{
|
|
*lastSlash = 0; // cut filename
|
|
secLastSlash = pathString.GetLastSlash();
|
|
if (secLastSlash)
|
|
{
|
|
*secLastSlash = 0;
|
|
return nString(secLastSlash+1);
|
|
}
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Return a nString object containing the part before the last
|
|
directory separator.
|
|
|
|
NOTE: I left my fix in that returns the last slash (or colon), this was
|
|
necessary to tell if a dirname is a normal directory or an assign.
|
|
|
|
- 17-Feb-04 floh fixed a bug when the path ended with a slash
|
|
*/
|
|
inline
|
|
nString
|
|
nString::ExtractDirName() const
|
|
{
|
|
nString pathString(*this);
|
|
char* lastSlash = pathString.GetLastSlash();
|
|
|
|
// special case if path ends with a slash
|
|
if (lastSlash)
|
|
{
|
|
if (0 == lastSlash[1])
|
|
{
|
|
*lastSlash = 0;
|
|
lastSlash = pathString.GetLastSlash();
|
|
}
|
|
if (lastSlash)
|
|
{
|
|
*++lastSlash = 0;
|
|
}
|
|
}
|
|
return pathString;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Return a path string object which contains of the complete path
|
|
up to the last slash. Returns an empty string if there is no
|
|
slash in the path.
|
|
*/
|
|
inline
|
|
nString
|
|
nString::ExtractToLastSlash() const
|
|
{
|
|
nString pathString(*this);
|
|
char* lastSlash = pathString.GetLastSlash();
|
|
if (lastSlash)
|
|
{
|
|
lastSlash[1] = 0;
|
|
}
|
|
else
|
|
{
|
|
pathString = "";
|
|
}
|
|
return pathString;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
/*
|
|
inline
|
|
bool
|
|
nString::MatchPattern(const nString& pattern) const
|
|
{
|
|
return n_strmatch(this->Get(), pattern.Get());
|
|
}
|
|
*/
|
|
//------------------------------------------------------------------------------
|
|
#endif
|
|
|