增强字符串分割类,支持中途修改分隔符,单元测试通过

This commit is contained in:
Stone 2016-06-08 10:18:53 +00:00
parent 4a5d2c746a
commit 858d1e49a1
4 changed files with 149 additions and 40 deletions

View File

@ -150,8 +150,9 @@ public:
bool EndsWith(cstring str) const; bool EndsWith(cstring str) const;
StringSplit Split(const String& sep) const; StringSplit Split(const String& sep) const;
StringSplit Split(cstring sep) const;
String Substring(int start, int _Length) const; String Substring(int start, int len = -1) const;
String TrimStart() const; String TrimStart() const;
String TrimEnd() const; String TrimEnd() const;
String Trim() const; String Trim() const;
@ -195,18 +196,22 @@ private:
class StringSplit class StringSplit
{ {
public: public:
StringSplit(const String& str, const String& sep); cstring Sep; // 分隔符。下一个要寻找的边界符
int Position; // 当前段位置。负数表示到了结尾。
int Length; // 当前段长度。
StringSplit(const String& str, cstring sep);
const String Next(); const String Next();
explicit operator bool() const { return _Position >= 0; } // 是否已经到达末尾
bool operator !() const { return _Position < 0; } bool End() const { return Position == -2; }
explicit operator bool() const { return Position >= 0; }
bool operator !() const { return Position < 0; }
private: private:
const String& _Str; const String& _Str;
const String& _Sep;
int _Position;
int _Length;
}; };
#endif #endif

View File

@ -882,15 +882,22 @@ bool String::EndsWith(cstring str) const
} }
StringSplit String::Split(const String& sep) const StringSplit String::Split(const String& sep) const
{
return StringSplit(*this, sep.GetBuffer());
}
StringSplit String::Split(cstring sep) const
{ {
return StringSplit(*this, sep); return StringSplit(*this, sep);
} }
String String::Substring(int start, int length) const String String::Substring(int start, int len) const
{ {
String str; String str;
if(len < 0) len = _Length - start;
//str.Copy(this, _Length, start); //str.Copy(this, _Length, start);
if(_Length && start < _Length) str.copy(_Arr + start, length); if(_Length && start < _Length) str.copy(_Arr + start, len);
return str; return str;
} }
@ -1077,41 +1084,61 @@ char *dtostrf (double val, char width, byte prec, char* sout)
/******************************** StringSplit ********************************/ /******************************** StringSplit ********************************/
StringSplit::StringSplit(const String& str, const String& sep) : StringSplit::StringSplit(const String& str, cstring sep) :
_Str(str), _Str(str)
_Sep(sep)
{ {
_Position = 0; Sep = sep;
_Length = 0; Position = -1;
Length = 0;
// 先算好第一段 // 先算好第一段
int p = _Str.IndexOf(_Sep); //int p = _Str.IndexOf(_Sep);
if(p >= 0) _Length = p; //if(p >= 0) _Length = p;
} }
const String StringSplit::Next() const String StringSplit::Next()
{ {
auto ptr = _Str.GetBuffer(); cstring ptr = nullptr;
int len = 0; int len = 0;
if(_Position < 0 || _Length == 0) if(Position >= -1 && Sep)
ptr = nullptr;
else
{ {
// 拿出当前段,然后提前计算下一段 String sp = Sep;
ptr += _Position;
len = _Length;
// 找到下一个位置 // 从当前段之后开始找一段
// 剩余全部长度,如果找不到下一个,那么这个就是最后长度 int s = Position + Length;
int end = _Str.Length(); // 除首次以外,每次都要跳过分隔符
_Position += _Length + _Sep.Length(); if(s < 0)
int p = _Str.IndexOf(_Sep, _Position); s = 0;
if(p > 0) end = p; else
s += sp.Length();
_Length = end - _Position; // 检查是否已经越界
if(s >= _Str.Length())
{
Position = -2;
Length = 0;
}
else
{
// 查找分隔符
int p = _Str.IndexOf(Sep, s);
int sz = 0;
// 剩余全部长度,如果找不到下一个,那么这个就是最后长度。不用跳过分隔符
if(p < 0)
sz = _Str.Length() - s;
else
sz = p - s;
Position = s;
Length = sz;
ptr = _Str.GetBuffer() + Position;
len = Length;
}
} }
// 包装一层指针 // 包装一层指针
return String((cstring)ptr, len); return String(ptr, len);
} }

View File

@ -56,11 +56,10 @@ IPAddress IPAddress::Parse(const String& ipstr)
if(ipstr == "255.255.255.255") return IPAddress::Broadcast(); if(ipstr == "255.255.255.255") return IPAddress::Broadcast();
// 这里不能在Split参数直接使用字符指针隐式构造的字符串对象在这个函数之后将会被销毁 // 这里不能在Split参数直接使用字符指针隐式构造的字符串对象在这个函数之后将会被销毁
String sep("."); auto sp = ipstr.Split(".");
auto ss = ipstr.Split(sep); for(int i=0; i<4 && sp; i++)
for(int i=0; i<4 && ss; i++)
{ {
auto item = ss.Next(); auto item = sp.Next();
if(item.Length() == 0 || item.Length() > 3) break; if(item.Length() == 0 || item.Length() > 3) break;
// 标准地址第一个不能是0唯一的Any例外已经在前面处理 // 标准地址第一个不能是0唯一的Any例外已经在前面处理

View File

@ -327,6 +327,77 @@ static void TestCompare()
assert(str3.EqualsIgnoreCase(String(cs2)), err); assert(str3.EqualsIgnoreCase(String(cs2)), err);
} }
static void TestSplit(cstring cstr)
{
TS("TestSplit");
debug_printf("字符串分割测试\r\n");
String str = cstr;
auto err = "StringSplit Split(cstring sep) const";
int p = -1;
auto sp = str.Split(",");
assert(sp.Position == p && sp.Length == 0, err);
assert(!sp.End(), err);
auto rs = sp.Next();
p = 0;
// 如果分隔符开头,则跳过它
if(cstr[0] == ',')
{
rs = sp.Next();
p++;
}
assert(sp.Position == p && sp.Length == 4, err);
assert(rs == "+IPD", err);
p += 4 + 1;
rs = sp.Next();
assert(sp.Position == p && sp.Length == 1, err);
assert(rs.ToInt() == 3, err);
p += 1 + 1;
rs = sp.Next();
assert(sp.Position == p && sp.Length == 2, err);
assert(rs.ToInt() == 96, err);
p += 2 + 1;
rs = sp.Next();
assert(sp.Position == p && sp.Length == rs.Length(), err);
assert(rs == "10.0.0.21", err);
p += rs.Length() + 1;
// 更换分隔符
sp.Sep = ":";
rs = sp.Next();
assert(sp.Position == p && sp.Length == 4, err);
assert(rs.ToInt() == 3377, err);
p += 4 + 1;
// 最后一组
rs = sp.Next();
assert(sp.Position == p && sp.Length == rs.Length(), err);
assert(rs == "abcdef", err);
//assert(sp.Position + sp.Length == str.Length(), err);
// 再来一组
rs = sp.Next();
assert(sp.End(), err);
assert(sp.Position == -2 && sp.Length == 0, err);
assert(!rs, err);
// 到了默认不再查找
rs = sp.Next();
assert(sp.End(), err);
assert(sp.Position == -2 && sp.Length == 0, err);
assert(!rs, err);
}
void String::Test() void String::Test()
{ {
TS("TestString"); TS("TestString");
@ -346,6 +417,13 @@ void String::Test()
TestCompare(); TestCompare();
// 分隔符
cstring cstr = "+IPD,3,96,10.0.0.21,3377:abcdef";
TestSplit(cstr);
// 以分隔符开头和结尾的情况
cstr = ",+IPD,3,96,10.0.0.21,3377:abcdef:";
TestSplit(cstr);
debug_printf("字符串单元测试全部通过!"); debug_printf("字符串单元测试全部通过!");
} }