采用string.h标准函数strlen/strncmp,增强字符串比较
This commit is contained in:
parent
e2e3195c5a
commit
09b96680c9
|
@ -98,13 +98,15 @@ public:
|
||||||
bool operator !() const { return _Length == 0; }
|
bool operator !() const { return _Length == 0; }
|
||||||
//operator char*() const { return _Arr; }
|
//operator char*() const { return _Arr; }
|
||||||
int CompareTo(const String& s) const;
|
int CompareTo(const String& s) const;
|
||||||
|
int CompareTo(cstring cstr, int len = -1, bool ignoreCase = false) const;
|
||||||
bool Equals(const String& s) const;
|
bool Equals(const String& s) const;
|
||||||
bool Equals(cstring cstr) const;
|
bool Equals(cstring cstr) const;
|
||||||
bool EqualsIgnoreCase(const String& s) const;
|
bool EqualsIgnoreCase(const String& s) const;
|
||||||
bool operator == (const String& rhs) const {return Equals(rhs);}
|
bool EqualsIgnoreCase(cstring cstr) const;
|
||||||
bool operator == (cstring cstr) const {return Equals(cstr);}
|
bool operator == (const String& rhs) const {return Equals(rhs); }
|
||||||
bool operator != (const String& rhs) const {return !Equals(rhs);}
|
bool operator == (cstring cstr) const {return Equals(cstr); }
|
||||||
bool operator != (cstring cstr) const {return !Equals(cstr);}
|
bool operator != (const String& rhs) const {return !Equals(rhs); }
|
||||||
|
bool operator != (cstring cstr) const {return !Equals(cstr); }
|
||||||
bool operator < (const String& rhs) const;
|
bool operator < (const String& rhs) const;
|
||||||
bool operator > (const String& rhs) const;
|
bool operator > (const String& rhs) const;
|
||||||
bool operator <= (const String& rhs) const;
|
bool operator <= (const String& rhs) const;
|
||||||
|
@ -184,7 +186,7 @@ private:
|
||||||
using Array::CheckCapacity;
|
using Array::CheckCapacity;
|
||||||
bool CheckCapacity(uint size);
|
bool CheckCapacity(uint size);
|
||||||
virtual void* Alloc(int len);
|
virtual void* Alloc(int len);
|
||||||
|
|
||||||
int Search(cstring str, int len, int startIndex, bool rev) const;
|
int Search(cstring str, int len, int startIndex, bool rev) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -194,7 +196,7 @@ class StringSplit
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StringSplit(const String& str, const String& sep);
|
StringSplit(const String& str, const String& sep);
|
||||||
|
|
||||||
const String Next();
|
const String Next();
|
||||||
|
|
||||||
explicit operator bool() const { return _Position >= 0; }
|
explicit operator bool() const { return _Position >= 0; }
|
||||||
|
|
111
Core/String.cpp
111
Core/String.cpp
|
@ -1,5 +1,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
@ -18,8 +19,8 @@ extern char* ultoa(UInt64 value, char* string, int radix);
|
||||||
char* dtostrf(double val, char width, byte prec, char* sout);
|
char* dtostrf(double val, char width, byte prec, char* sout);
|
||||||
|
|
||||||
// C格式字符串函数
|
// C格式字符串函数
|
||||||
static int strnlen(cstring str, int max = 0xFFFF);
|
//static int strnlen(cstring str, int max = 0xFFFF);
|
||||||
static int strncmp(cstring s1, cstring s2, int n);
|
//static int strncmp(cstring s1, cstring s2, int n);
|
||||||
|
|
||||||
/******************************** String ********************************/
|
/******************************** String ********************************/
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ String::String(cstring cstr) : Array(Arr, ArrayLength(Arr))
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
|
||||||
_Length = strnlen(cstr);
|
_Length = strlen(cstr);
|
||||||
if(_Length)
|
if(_Length)
|
||||||
{
|
{
|
||||||
_Arr = (char*)cstr;
|
_Arr = (char*)cstr;
|
||||||
|
@ -130,7 +131,7 @@ String::String(char* str, int length) : Array(str, length)
|
||||||
_Capacity = length - 1;
|
_Capacity = length - 1;
|
||||||
|
|
||||||
// 计算外部字符串长度
|
// 计算外部字符串长度
|
||||||
int len = strnlen(str, length);
|
int len = strlen(str);
|
||||||
if(len >= length) len = length - 1;
|
if(len >= length) len = length - 1;
|
||||||
_Length = len;
|
_Length = len;
|
||||||
_Arr[_Length] = '\0';
|
_Arr[_Length] = '\0';
|
||||||
|
@ -324,7 +325,7 @@ String& String::operator = (String&& rval)
|
||||||
|
|
||||||
String& String::operator = (cstring cstr)
|
String& String::operator = (cstring cstr)
|
||||||
{
|
{
|
||||||
if (cstr) copy(cstr, strnlen(cstr));
|
if (cstr) copy(cstr, strlen(cstr));
|
||||||
else release();
|
else release();
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -359,7 +360,7 @@ bool String::Concat(cstring cstr, uint length)
|
||||||
bool String::Concat(cstring cstr)
|
bool String::Concat(cstring cstr)
|
||||||
{
|
{
|
||||||
if (!cstr) return 0;
|
if (!cstr) return 0;
|
||||||
return Concat(cstr, strnlen(cstr));
|
return Concat(cstr, strlen(cstr));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::Concat(char c)
|
bool String::Concat(char c)
|
||||||
|
@ -387,7 +388,7 @@ bool String::Concat(byte num, int radix)
|
||||||
char buf[1 + 3 * sizeof(byte)];
|
char buf[1 + 3 * sizeof(byte)];
|
||||||
itoa(num, buf, radix);
|
itoa(num, buf, radix);
|
||||||
|
|
||||||
return Concat(buf, strnlen(buf, sizeof(buf)));
|
return Concat(buf, strlen(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::Concat(short num, int radix)
|
bool String::Concat(short num, int radix)
|
||||||
|
@ -397,7 +398,7 @@ bool String::Concat(short num, int radix)
|
||||||
|
|
||||||
char buf[2 + 3 * sizeof(int)];
|
char buf[2 + 3 * sizeof(int)];
|
||||||
itoa(num, buf, radix);
|
itoa(num, buf, radix);
|
||||||
return Concat(buf, strnlen(buf, sizeof(buf)));
|
return Concat(buf, strlen(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::Concat(ushort num, int radix)
|
bool String::Concat(ushort num, int radix)
|
||||||
|
@ -415,7 +416,7 @@ bool String::Concat(ushort num, int radix)
|
||||||
|
|
||||||
char buf[2 + 3 * sizeof(int)];
|
char buf[2 + 3 * sizeof(int)];
|
||||||
utoa(num, buf, radix);
|
utoa(num, buf, radix);
|
||||||
return Concat(buf, strnlen(buf, sizeof(buf)));
|
return Concat(buf, strlen(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::Concat(int num, int radix)
|
bool String::Concat(int num, int radix)
|
||||||
|
@ -425,7 +426,7 @@ bool String::Concat(int num, int radix)
|
||||||
|
|
||||||
char buf[2 + 3 * sizeof(int)];
|
char buf[2 + 3 * sizeof(int)];
|
||||||
itoa(num, buf, radix);
|
itoa(num, buf, radix);
|
||||||
return Concat(buf, strnlen(buf, sizeof(buf)));
|
return Concat(buf, strlen(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::Concat(uint num, int radix)
|
bool String::Concat(uint num, int radix)
|
||||||
|
@ -443,7 +444,7 @@ bool String::Concat(uint num, int radix)
|
||||||
|
|
||||||
char buf[1 + 3 * sizeof(uint)];
|
char buf[1 + 3 * sizeof(uint)];
|
||||||
utoa(num, buf, radix);
|
utoa(num, buf, radix);
|
||||||
return Concat(buf, strnlen(buf, sizeof(buf)));
|
return Concat(buf, strlen(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::Concat(Int64 num, int radix)
|
bool String::Concat(Int64 num, int radix)
|
||||||
|
@ -453,7 +454,7 @@ bool String::Concat(Int64 num, int radix)
|
||||||
|
|
||||||
char buf[2 + 3 * sizeof(Int64)];
|
char buf[2 + 3 * sizeof(Int64)];
|
||||||
ltoa(num, buf, radix);
|
ltoa(num, buf, radix);
|
||||||
return Concat(buf, strnlen(buf, sizeof(buf)));
|
return Concat(buf, strlen(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::Concat(UInt64 num, int radix)
|
bool String::Concat(UInt64 num, int radix)
|
||||||
|
@ -473,21 +474,21 @@ bool String::Concat(UInt64 num, int radix)
|
||||||
|
|
||||||
char buf[1 + 3 * sizeof(UInt64)];
|
char buf[1 + 3 * sizeof(UInt64)];
|
||||||
ultoa(num, buf, radix);
|
ultoa(num, buf, radix);
|
||||||
return Concat(buf, strnlen(buf, sizeof(buf)));
|
return Concat(buf, strlen(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::Concat(float num, byte decimalPlaces)
|
bool String::Concat(float num, byte decimalPlaces)
|
||||||
{
|
{
|
||||||
char buf[20];
|
char buf[20];
|
||||||
auto string = dtostrf(num, (decimalPlaces + 2), decimalPlaces, buf);
|
auto string = dtostrf(num, (decimalPlaces + 2), decimalPlaces, buf);
|
||||||
return Concat(string, strnlen(buf, sizeof(buf)));
|
return Concat(string, strlen(string));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::Concat(double num, byte decimalPlaces)
|
bool String::Concat(double num, byte decimalPlaces)
|
||||||
{
|
{
|
||||||
char buf[20];
|
char buf[20];
|
||||||
auto string = dtostrf(num, (decimalPlaces + 2), decimalPlaces, buf);
|
auto string = dtostrf(num, (decimalPlaces + 2), decimalPlaces, buf);
|
||||||
return Concat(string, strnlen(buf, sizeof(buf)));
|
return Concat(string, strlen(string));
|
||||||
}
|
}
|
||||||
|
|
||||||
String& operator + (String& lhs, const Object& rhs)
|
String& operator + (String& lhs, const Object& rhs)
|
||||||
|
@ -508,7 +509,7 @@ String& operator + (String& lhs, const String& rhs)
|
||||||
String& operator + (String& lhs, cstring cstr)
|
String& operator + (String& lhs, cstring cstr)
|
||||||
{
|
{
|
||||||
auto& a = const_cast<String&>(lhs);
|
auto& a = const_cast<String&>(lhs);
|
||||||
if (!cstr || !a.Concat(cstr, strnlen(cstr))) a.release();
|
if (!cstr || !a.Concat(cstr, strlen(cstr))) a.release();
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,42 +571,58 @@ String& operator + (String& lhs, double num)
|
||||||
|
|
||||||
int String::CompareTo(const String& s) const
|
int String::CompareTo(const String& s) const
|
||||||
{
|
{
|
||||||
if (!_Arr || !s._Arr) {
|
/*if (!_Arr)
|
||||||
if (s._Arr && s._Length > 0) return 0 - *(byte*)s._Arr;
|
{
|
||||||
if (_Arr && _Length > 0) return *(byte*)_Arr;
|
if (s._Arr && s._Length > 0) return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return strncmp(_Arr, s._Arr, _Length);
|
if(!s._Arr && _Arr && _Length > 0) return 1;
|
||||||
|
|
||||||
|
return strncmp(_Arr, s._Arr, _Length);*/
|
||||||
|
return CompareTo(s._Arr, s._Length, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::Equals(const String& s2) const
|
int String::CompareTo(cstring cstr, int len, bool ignoreCase) const
|
||||||
{
|
{
|
||||||
return _Length == s2._Length && CompareTo(s2) == 0;
|
if(len < 0) len = strlen(cstr);
|
||||||
|
if (!_Arr)
|
||||||
|
{
|
||||||
|
if (cstr && len > 0) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(!cstr && _Arr && _Length > 0) return 1;
|
||||||
|
|
||||||
|
// 逐个比较字符,直到指定长度或者源字符串结束
|
||||||
|
if(ignoreCase)
|
||||||
|
return strncasecmp(_Arr, cstr, _Length);
|
||||||
|
else
|
||||||
|
return strncmp(_Arr, cstr, _Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::Equals(const String& str) const
|
||||||
|
{
|
||||||
|
return _Length == str._Length && CompareTo(str._Arr, str._Length, false) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::Equals(cstring cstr) const
|
bool String::Equals(cstring cstr) const
|
||||||
{
|
{
|
||||||
if (_Length == 0) return cstr == nullptr || *cstr == 0;
|
int len = strlen(cstr);
|
||||||
//if (cstr == nullptr) return _Arr[0] == 0;
|
|
||||||
if (cstr == nullptr) return false;
|
|
||||||
|
|
||||||
int len = strnlen(cstr, _Length + 1);
|
|
||||||
if(len != _Length) return false;
|
if(len != _Length) return false;
|
||||||
|
|
||||||
return strncmp(_Arr, cstr, len) == 0;
|
return CompareTo(cstr, len, false) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::EqualsIgnoreCase(const String &s2 ) const
|
bool String::EqualsIgnoreCase(const String &str) const
|
||||||
{
|
{
|
||||||
if (this == &s2) return true;
|
return _Length == str._Length && CompareTo(str._Arr, str._Length, true) == 0;
|
||||||
if (_Length != s2._Length) return false;
|
}
|
||||||
if (_Length == 0) return true;
|
|
||||||
auto p1 = _Arr;
|
bool String::EqualsIgnoreCase(cstring cstr) const
|
||||||
auto p2 = s2._Arr;
|
{
|
||||||
while (*p1) {
|
int len = strlen(cstr);
|
||||||
if (tolower(*p1++) != tolower(*p2++)) return false;
|
if(len != _Length) return false;
|
||||||
}
|
|
||||||
return true;
|
return CompareTo(cstr, len, true) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::operator<(const String& rhs) const
|
bool String::operator<(const String& rhs) const
|
||||||
|
@ -752,7 +769,7 @@ String& String::Format(cstring format, ...)
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
|
|
||||||
// 无法准确估计长度,大概乘以2处理
|
// 无法准确估计长度,大概乘以2处理
|
||||||
CheckCapacity(_Length + (strnlen(format) << 1));
|
CheckCapacity(_Length + (strlen(format) << 1));
|
||||||
|
|
||||||
//char* p = _Arr;
|
//char* p = _Arr;
|
||||||
int len2 = vsnprintf(_Arr + _Length, _Capacity - _Length, format, ap);
|
int len2 = vsnprintf(_Arr + _Length, _Capacity - _Length, format, ap);
|
||||||
|
@ -783,7 +800,7 @@ int String::IndexOf(const String& str, int startIndex) const
|
||||||
|
|
||||||
int String::IndexOf(cstring str, int startIndex) const
|
int String::IndexOf(cstring str, int startIndex) const
|
||||||
{
|
{
|
||||||
return Search(str, strnlen(str, _Length - startIndex + 1), startIndex, false);
|
return Search(str, strlen(str), startIndex, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int String::LastIndexOf(const char ch, int startIndex) const
|
int String::LastIndexOf(const char ch, int startIndex) const
|
||||||
|
@ -809,7 +826,7 @@ int String::LastIndexOf(const String& str, int startIndex) const
|
||||||
|
|
||||||
int String::LastIndexOf(cstring str, int startIndex) const
|
int String::LastIndexOf(cstring str, int startIndex) const
|
||||||
{
|
{
|
||||||
return Search(str, strnlen(str, _Length - startIndex + 1), startIndex, true);
|
return Search(str, strlen(str), startIndex, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int String::Search(cstring str, int len, int startIndex, bool rev) const
|
int String::Search(cstring str, int len, int startIndex, bool rev) const
|
||||||
|
@ -855,8 +872,7 @@ bool String::StartsWith(const String& str, int startIndex) const
|
||||||
bool String::StartsWith(cstring str, int startIndex) const
|
bool String::StartsWith(cstring str, int startIndex) const
|
||||||
{
|
{
|
||||||
if(!str) return false;
|
if(!str) return false;
|
||||||
|
int slen = strlen(str);
|
||||||
int slen = strnlen(str, _Length - startIndex + 1);
|
|
||||||
if (startIndex + slen > _Length || !_Arr) return false;
|
if (startIndex + slen > _Length || !_Arr) return false;
|
||||||
|
|
||||||
return strncmp(&_Arr[startIndex], str, slen) == 0;
|
return strncmp(&_Arr[startIndex], str, slen) == 0;
|
||||||
|
@ -873,8 +889,7 @@ bool String::EndsWith(const String& str) const
|
||||||
bool String::EndsWith(cstring str) const
|
bool String::EndsWith(cstring str) const
|
||||||
{
|
{
|
||||||
if(!str) return false;
|
if(!str) return false;
|
||||||
|
int slen = strlen(str);
|
||||||
int slen = strnlen(str, _Length + 1);
|
|
||||||
if(slen > _Length) return false;
|
if(slen > _Length) return false;
|
||||||
|
|
||||||
return strncmp(&_Arr[_Length - slen], str, slen) == 0;
|
return strncmp(&_Arr[_Length - slen], str, slen) == 0;
|
||||||
|
@ -1126,7 +1141,7 @@ strlen(const char *str)
|
||||||
;
|
;
|
||||||
return (s - str);
|
return (s - str);
|
||||||
}*/
|
}*/
|
||||||
int strnlen(cstring str, int max)
|
/*int strnlen(cstring str, int max)
|
||||||
{
|
{
|
||||||
cstring s = str;
|
cstring s = str;
|
||||||
|
|
||||||
|
@ -1145,4 +1160,4 @@ int strncmp(cstring s1, cstring s2, int n)
|
||||||
} while (--n);
|
} while (--n);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}*/
|
||||||
|
|
|
@ -292,6 +292,41 @@ static void TestMemory()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void TestCompare()
|
||||||
|
{
|
||||||
|
TS("TestCompare");
|
||||||
|
|
||||||
|
debug_printf("字符串比较测试\r\n");
|
||||||
|
|
||||||
|
String str = "abcd";
|
||||||
|
cstring cs = "abcdef";
|
||||||
|
|
||||||
|
auto err = "int CompareTo(cstring cstr) const";
|
||||||
|
|
||||||
|
// 因为按照左边长度来比较,所以返回0
|
||||||
|
assert(str.CompareTo(cs) == 0, err);
|
||||||
|
|
||||||
|
err = "bool operator != (cstring cstr) const";
|
||||||
|
assert(str != cs, err);
|
||||||
|
|
||||||
|
// 倒过来试试
|
||||||
|
String str2 = "abcdef";
|
||||||
|
cstring cs2 = "abcd";
|
||||||
|
|
||||||
|
assert(str2.CompareTo(cs2) > 0, err);
|
||||||
|
|
||||||
|
err = "bool operator != (cstring cstr) const";
|
||||||
|
assert(str2 != cs2, err);
|
||||||
|
|
||||||
|
// 不区分大小写
|
||||||
|
String str3 = "ABCD";
|
||||||
|
|
||||||
|
err = "bool EqualsIgnoreCase(cstring cstr) const";
|
||||||
|
assert(!str3.Equals(cs2), err);
|
||||||
|
assert(str3.EqualsIgnoreCase(cs2), err);
|
||||||
|
assert(str3.EqualsIgnoreCase(String(cs2)), err);
|
||||||
|
}
|
||||||
|
|
||||||
void String::Test()
|
void String::Test()
|
||||||
{
|
{
|
||||||
TS("TestString");
|
TS("TestString");
|
||||||
|
@ -309,6 +344,8 @@ void String::Test()
|
||||||
|
|
||||||
TestMemory();
|
TestMemory();
|
||||||
|
|
||||||
|
TestCompare();
|
||||||
|
|
||||||
debug_printf("字符串单元测试全部通过!");
|
debug_printf("字符串单元测试全部通过!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue