一个 C++ 字符串类






4.96/5 (29投票s)
一个快速、引用计数、写时复制的字符串类
更新
开发现在使用 Visual Studio 2013 进行。
现在库中有两个 string
类,AnsiString
和 WideString
,而 String
现在是一个 typedef
,它将 String
映射到 WideString
。
这两个类支持或多或少相同的接口。AnsiString
支持基于 char
的 string
,而 WideString
支持基于 wchar_t
的 string
。
基本转换现在由一些 static
重载函数处理
HWIN_EXPORT static WideString From( const std::string& s );
HWIN_EXPORT static WideString From( const char* s );
HWIN_EXPORT static WideString From( const char* s, size_type theLength );
HWIN_EXPORT static WideString From( const AnsiString& s );
HWIN_EXPORT static WideString From( const WideString& s );
HWIN_EXPORT static WideString From( const std::wstring& s );
HWIN_EXPORT static WideString From( const wchar_t* s );
HWIN_EXPORT static WideString From( const wchar_t* s, size_type theLength );
HWIN_EXPORT static WideString From( char value, int radix = 10 );
HWIN_EXPORT static WideString From( unsigned char value, int radix = 10 );
HWIN_EXPORT static WideString From( short value, int radix = 10 );
HWIN_EXPORT static WideString From( unsigned short value, int radix = 10 );
HWIN_EXPORT static WideString From( int value, int radix = 10 );
HWIN_EXPORT static WideString From( unsigned int value, int radix = 10 );
HWIN_EXPORT static WideString From( long long value, int radix = 10 );
HWIN_EXPORT static WideString From( unsigned long long value, int radix = 10 );
HWIN_EXPORT static WideString From( float value, wchar_t* fmt = L"%g" );
HWIN_EXPORT static WideString From( double value, wchar_t* fmt = L"%g" );
HWIN_EXPORT static WideString From( DateTime value );
如果一个 string
为空,并且在内部表示为 nullptr
,c_str()
现在将返回一个指向以零结尾的空 string
的指针 - 而 data()
将返回 nullptr
。
ICompareTo
和 icompare
执行不区分大小写的比较
int ICompareTo( const WideString& other ) const;
int ICompareTo( const wchar_t* str ) const;
int icompare( const WideString& other ) const;
int icompare( const wchar_t* str ) const;
不区分大小写的匹配实际上得到了很大的改进
size_type IIndexOfAnyOf( const wchar_t *searchChars, size_type numberOfSearchChars,
size_type start ) const;
size_type IIndexOfAnyOf( const WideString& searchChars, size_type start = 0 ) const;
size_type IIndexOfAnyOf( const wchar_t* searchChars, size_type start = 0 ) const;
size_type IIndexOfAnyBut( const wchar_t *searchChars, size_type numberOfSearchChars,
size_type start ) const;
size_type IIndexOfAnyBut( const WideString& searchChars, size_type start = 0 ) const;
size_type IIndexOfAnyBut( const wchar_t* searchChars, size_type start = 0 ) const;
size_type ILastIndexOfAnyOf( const wchar_t *searchChars, size_type numberOfSearchChars,
size_type start ) const;
size_type ILastIndexOfAnyOf( const WideString& searchChars,
size_type start = npos ) const;
size_type ILastIndexOfAnyOf( const wchar_t* searchChars, size_type start = npos ) const;
size_type ILastIndexOfAnyBut( const wchar_t *searchChars, size_type numberOfSearchChars,
size_type start ) const;
size_type ILastIndexOfAnyBut( const WideString& searchChars, size_type start = npos ) const;
size_type ILastIndexOfAnyBut( const wchar_t* searchChars, size_type start = npos ) const;
size_type IIndexOf( const wchar_t *searchString, size_type searchStringLength,
size_type start ) const;
size_type IIndexOf( const WideString& searchString, size_type start = 0 ) const;
size_type IIndexOf( const wchar_t* searchString, size_type start = 0 ) const;
size_type ILastIndexOf( const wchar_t *searchString, size_type searchStringLength,
size_type start ) const;
size_type ILastIndexOf( const WideString& searchString, size_type start = npos ) const;
size_type ILastIndexOf( const wchar_t* searchString, size_type start = npos ) const;
size_type ILastIndexOf( wchar_t c, size_type start = npos ) const;
bool IStartsWith( const wchar_t* str ) const;
bool IStartsWith( const WideString& str ) const;
Split
是另一个新的成员函数,具有一些重载。
std::vector<widestring> Split( value_type delimiter ) const
std::vector<widestring> Split( value_type* delimiters ) const;
template<typename ForwardIterator>
std::vector<widestring> Split( ForwardIterator delimitersBegin, ForwardIterator delimitersEnd ) const;
std::vector<widestring> Split( std::initializer_list<value_type> delimiters ) const;
std::vector<widestring> Split( const std::vector<value_type>& delimiters ) const;
std::vector<widestring> Split( value_type delimiter, size_t max ) const;
然后是一些新的解析函数
HWIN_EXPORT bool ToBoolean( ) const;
HWIN_EXPORT char ToSByte( int radix = 0 ) const;
HWIN_EXPORT unsigned char ToByte( int radix = 0 ) const;
HWIN_EXPORT short ToInt16( int radix = 0 ) const;
HWIN_EXPORT unsigned short ToUInt16( int radix = 0 ) const;
HWIN_EXPORT int ToInt32( int radix = 0 ) const;
HWIN_EXPORT unsigned int ToUInt32( int radix = 0 ) const;
HWIN_EXPORT long long ToInt64( int radix = 0 ) const;
HWIN_EXPORT unsigned long long ToUInt64( int radix = 0 ) const;
HWIN_EXPORT float ToSingle( ) const;
HWIN_EXPORT double ToDouble( ) const;
HWIN_EXPORT DateTime ToDateTime( ) const;
HWIN_EXPORT TimeSpan ToTimeSpan( ) const;
HWIN_EXPORT Guid ToGuid( ) const;
还有哈希函子支持
template<>
struct hash<WideString> : public std::unary_function<WideString, size_t>
{
inline size_t operator()(const WideString& theString) const
{
auto result = _Hash_seq((const unsigned char*) theString.c_str(),
theString.Length()*2);
return result;
}
};
这使得 AnsiString
和 WideString
可以用作诸如 std::unordred_map
之类的模板实例化的键。
引言
这是本系列关于 Windows C++ 开发的第五篇文章。
之前的文章可以在这里找到
String
类位于“\HarlinnWindows\hwinstring.h”。
为什么我们还需要另一个 C++ string
类?难道 CString
、std::string
和 std::wstring
不够好吗?它们当然是设计良好的类,但事实证明,另一个 String
类是有充分理由的。
实现一个不错的 string
类本身也很有趣。
动机
String
是一个引用计数、写时复制的 string
类,它与以零结尾的 wchar_t*
二进制兼容。这样做的好处是,如果你有这样的代码
struct Foo1
{
int x;
int y;
wchar_t* pszText;
};
然后
struct Foo2
{
int x;
int y;
String Text;
};
将具有与 Foo1
相同的二进制布局,允许你将 Foo2
传递给期望 Foo1
的函数。
考虑以下内容
void Print( )
{
std::wstring stdstring(L"stdstring" );
wprintf( L"%s\n", stdstring );
wprintf( L"%s\n", stdstring.c_str() );
String s( L"String" );
wprintf( L"%s\n", s );
wprintf( L"%s\n", s.c_str( ) );
}
上面的代码输出到控制台的内容如下:
?8
stdstring
String
String
wprintf( L"%s\n", stdstring );
只在控制台输出了 78
,如果你仔细想想,我相信你也会同意我们只是碰巧运气好,程序没有崩溃。
wprintf( L"%s\n", stdstring.c_str() );
和 wprintf( L"%s\n", s.c_str( ) );
分别输出了 stdstring
和 String
- 这几乎是我们期望的结果,而 wprintf( L"%s\n", s );
输出 String
的行为与 wprintf( L"%s\n", s.c_str( ) );
类似。这是因为 wchar_t* data_;
是 String
类中唯一的非 static
数据成员。
void print(const Foo1* p);
void doprint(const String& s)
{
Foo2 foo2;
foo2.x = 5;
foo2.y = 5;
foo2.Text = s + L" Printed";
print( reinterpret_cast<Foo1*>(&foo2));
}
这意味着 String
变量 s
的大小是八字节,如果为 32 位架构编译,则是四字节。
String
基本上只是指向以下结构 data
字段的智能指针
struct Buffer
{
size_type referenceCount;
size_type length;
wchar_t data[128];
};
因此,需要以下操作才能将指向以零结尾的 string
的指针转换为指向 Buffer
的指针
Buffer* toBuffer() const
{
if(data)
{
return (Buffer*)(((char*)data) - offsetof(Buffer,data));
}
return nullptr;
}
由于 String
对象本质上是智能指针,用下面的代码替换像这样的代码
wchar_t* pointers[2];
pointers[0] = wcsdup(L"Some string");
pointers[1] = wcsdup(L"Some other string");
foo(pointers);
free(pointers[0]);
free(pointers[1]);
为...
std::vector<String> v;
v.push_back(String(L"Some string"));
v.push_back(String(L"Some other string"));
foo(reinterpret_cast<const wchar_t**> v.data());
...可能会让你的 C++ 开发者生涯少一些刺激。
这是你无法使用 CString
、std::string
和 std::wstring
做到的事情,说到这里,我认为也应该公平地提到 String
类不执行小字符串优化,你也不能指定分配器。它的主要目的是作为 Windows API 工作时原始的以零结尾的 wchar_t string
的替代品,所以我想要的是我可以高效地传递、修改和返回的东西。
与使用 Windows API 的框架相关的 string
类最重要的三个特性是:
- 访问
string
的内容 - 访问
string
的长度 - 作为参数传递和作为结果返回
与 Windows API 交互时的典型用法
HWIN_EXPORT String Path::GetLongPathName(const String& path)
{
if(path)
{
wchar_t buffer[MAX_PATH+1] = {0,};
auto length = ::GetLongPathNameW(path.c_str(),
buffer,sizeof(buffer)/sizeof(wchar_t));
if(length == 0)
{
ThrowLastOSError();
}
if(length > (sizeof(buffer)/sizeof(wchar_t)))
{
String result;
result.SetLength(length-1);
length = ::GetLongPathNameW(path.c_str(),result.c_str(),length);
if(length == 0)
{
ThrowLastOSError();
}
return result;
}
else
{
String result(buffer,length);
return result;
}
}
return String();
}
在第二次调用 ::GetLongPathNameW
时,数据将直接复制到 SetLength
调用分配的缓冲区中,这既方便又高效。
性能
String
类在大多数情况下表现都非常好,通常与 std::wstring
和 CString
相比都足够好。
测试操作于包含 100,000 个对象的 std::vector<T>
。
测试的源代码位于“Examples\Windows\Strings\StringsExample”目录。
测试结果以毫秒为单位
字符串 | std::wstring | CString | .NET 字符串 | |
---|---|---|---|---|
默认构造函数 | 0.2332 | 1.1048 | 0.9196 | 2.7119 |
从短 string 初始化 | 13.7469 | 13.6107 | 15.6871 | 15.6395 |
获取长度 | 2.9202 | 7.6847 | 2.3535 | 1.4666 |
获取 wchar_t* | 1425.2 | 1815.01 | 1485.07 | N/A |
赋值 | 2.5579 | 11.5627 | 2.7839 | 2.0621 |
使用 push_back 初始化向量 | 14.0322 | 15.0869 | 17.3816 | 10.8025 |
追加 string | 11.8091 | 15.6082 | 19.7568 | 2.4463 |
追加 char | 532.829 | 313.211 | 270.669 | 5102.9609 |
Sort | 129.842 | 133.492 | 138.224 | 12689.2583 |
简单查找任意一个 | 67.0268 | 71.8129 | 64.6829 | 44.737 |
查找任意一个 | 128.498 | 255.84 | N/A | 294.803 |
反向查找任意一个 | 144.412 | 211.391 | N/A | 445.1848 |
查找 string | 52.0553 | 67.0184 | 28.6715 | 2543.4774 |
反向查找 string | 132.073 | 162.209 | N/A | 3294.2206 |
插入 string | 30.8257 | 34.8904 | 37.9284 | 177.7181 |
删除字符 | 27.0146 | 24.288 | 25.2154 | 179.6267 |
递归 | 75.5416 | 298.694 | 257.099 | 190.6845 |
虽然 CString
在“查找字符串”测试中优于 String
和 std::wstring
,但它是通过将自身视为以零结尾的 string
来实现的,忽略了它自己的长度 - 因此,当它包含 '\x00
' 字符时,它可能找不到搜索 string
的出现。
CString::FindOneOf
不允许我们指定字符串内的偏移量来开始搜索,这限制了该函数的使用性。
库中还包含一个 StringBuilder
类,使用该类运行“追加字符”测试需要 153.791 毫秒 - 优于所有 string
类。
由于 .NET string
是不可变类型,它在“追加字符”测试中表现不佳也就不足为奇了,它不是为此类用途设计的。令人惊讶的是它在搜索和排序测试中的表现,虽然我没想到它能与 C++ 类媲美,但我确实期望它表现得更好。
观察
String
类与 std::wstring
和 CString
相比表现足够好 - 有一个值得注意的例外,追加字符对于 String
类来说比 CString
慢大约两倍。std::wstring
和 CString
都存储它们分配的容量,而 String
根据其长度计算容量,节省了八个字节的内存。
“追加字符”测试为每个 string
类型追加字符 38,250,000 次,所以目前我认为节省这 8 个字节是值得的性能损失,特别是 since String
类似乎在我们开始一次添加多个字符时,比其他两个类表现更好。
递归测试
我提到我想要一些我可以高效地传递、修改和返回的东西,递归测试试图展示我是否成功了。
递归函数将一个 String
arg
的引用作为其参数之一。它将参数与 string
L"Hi"
组合,并使用组合后的 string
作为 String
参数调用自身,直到 recursionLevel
达到 10000
,然后返回最终组合的 String
。
const size_t maxRecursion = 10000;
String StringRecursion(const String& arg,size_t recursionLevel)
{
String result = arg + L"Hi";
if(recursionLevel < maxRecursion)
{
recursionLevel++;
result = StringRecursion(result,recursionLevel);
}
return result;
}
正如结果所示,String
类在这方面似乎比 CString
和 std::wstring
显著更好。
与 /Qpar(自动并行化器)编译器选项相关的意外优势
/Qpar
编译器开关启用代码中循环的自动并行化。
其中一个 String
测试的代码
void StringVectorGetTotalLength(const std::vector<String>& v)
{
Stopwatch stopwatch;
size_t totalLength = 0;
stopwatch.Start();
for(size_t i = 0; i < 100000;i++)
{
totalLength += v[i].length();
}
stopwatch.Stop();
std::wcout
<< L"std::vector<String> Get total length ("
<< totalLength
<< L") : "
<< stopwatch.Elapsed().TotalMilliseconds()
<< std::endl;
}
std::wstring
测试的代码
void wstringVectorGetTotalLength(const std::vector<std::wstring>& v)
{
Stopwatch stopwatch;
size_t totalLength = 0;
stopwatch.Start();
for(size_t i = 0; i < 100000;i++)
{
totalLength += v[i].length();
}
stopwatch.Stop();
std::wcout
<< L"std::vector<std::wstring> Get total length ("
<< totalLength
<< L") : "
<< stopwatch.Elapsed().TotalMilliseconds()
<< std::endl;
}
当我们在上述测试代码上启用自动并行化时,我们会得到截然不同的结果
String
:1.8227 - 性能提升约 60%std::wstring
:0.5685 - 性能提升高达 1251%
最后一个结果有点令人费解 - 因为编译器并没有并行化上述循环,但结果确实如此 - 突然之间,编译器在优化标准 C++ 库代码方面能够创造奇迹。
看来指定 /Qpar 似乎启用了更积极的优化,即使最终没有发生并行化/向量化。
String 类
构造函数
String()
: data(nullptr)
{}
String s;
std::wcout << L"Empty string:" << (s?L"Not null" : L"null") << std::endl;
//Output:
//Empty string:null
默认构造函数仅将 data
设置为 nullptr
,使此操作非常快速。
String(const String& other);
如果 other
是一个空 string
,复制构造函数将 data
设置为 nullptr
,当不是时,它只是增加缓冲区的引用计数。
String(String&& other);
移动构造函数在将 nullptr
分配给 other.data
之前,将 other.data
分配给 data
。
String(size_type length, wchar_t c);
创建一个长度为 length
的新 string
,并用字符 c
填充。
String(const wchar_t* str,size_type length, wchar_t padCharacter = defaultPadCharacter );
创建一个长度为 length
的新 string
。如果 str
不为 nullptr
,它将从 str
复制 length
个字符到 string
,否则 string
将用 length
个 padCharacter
填充。
String(const wchar_t* str1,size_type length1,
const wchar_t* str2,size_type length2,
wchar_t padCharacter = defaultPadCharacter);
此构造函数通过连接两个 string
源来创建一个新的 String
,如果 str1
或 str2
为 nullptr
,则 padCharacter
将用于在新 String
中填充 length1
或 length2
个字符,分别。
String(const wchar_t* str1,size_type length1,
const wchar_t* str2,size_type length2,
const wchar_t* str3,size_type length3,
wchar_t padCharacter = defaultPadCharacter);
此构造函数通过连接三个 string
源来创建一个新的 String
,如果 str1
、str2
或 str3
为 nullptr
,则 padCharacter
将分别用于在新 String
中填充 length1
、length2
或 length3
个字符。
String(const wchar_t* str);
从以零结尾的 string
创建新的 String
。如果 str
为 nullptr
或 length
为 0
,则新 String
的 data
将设置为 nullptr
。
析构函数
~String();
递减 Buffer
的引用计数,并在新的引用计数变为 0
时销毁 Buffer
。
运算符
String& operator = (const String& other)
复制赋值将 data
设置为 other.data
,如果 data
不为 nullptr
,则增加 Buffer
的引用计数。处理自赋值。
String& operator = (String&& other)
移动赋值在将 other.data
设置为 nullptr
之前,将 data
赋值为 other.data
。处理自赋值。
String& operator = (const wchar_t* str);
将以零结尾的 string
复制到此 String
。处理特殊情况
String s1 = L"Hello";
s1 = s1.c_str() + 1;
bool operator == (const String& other) const;
bool operator != (const String& other) const;
bool operator <= (const String& other) const;
bool operator < (const String& other) const;
bool operator >= (const String& other) const;
bool operator > (const String& other) const;
bool operator == (const wchar_t* str) const;
bool operator != (const wchar_t* str) const;
bool operator <= (const wchar_t* str) const;
bool operator < (const wchar_t* str) const;
bool operator >= (const wchar_t* str) const;
bool operator > (const wchar_t* str) const;
完整的比较运算符集。
operator bool() const;
如果 data
为 nullptr
,则返回 false
,这允许我们使用简单的表达式测试空 string
String s(L"Hello");
if(s)
{
// The string is not empty
}
wchar_t& operator[](size_type index);
返回 index
处字符的引用。这使得可以向 String
对象中的特定位置分配字符
String s1(L"Hi!",3);
String s2 = s1;
s2[1] = L'o';
// The contents of the s2 String object is now "Ho!", while s1 is still "Hi!"
此运算符确保 s2
引用一个唯一的缓冲区。
wchar_t operator[](size_type index) const;
返回 index
处的字符。
String& operator += (const String& other);
将 String
other
追加到此 String
。
String& operator += (const wchar_t* str);
将以零结尾的字符串 str
追加到此 String
。
String& operator += (const wchar_t c);
将字符 c
追加到此 String
。
friend String operator + (const String& str1,const String& str2)
通过连接 str1
和 str2
创建新的 string
。
friend String operator + (const String& str1,const wchar_t* str2)
通过连接 str1
和 str2
创建新的 string
。
friend String operator + (const String& str,const wchar_t c)
通过连接 String
str 和字符 c
创建新的 string
。
比较
int CompareTo(const String& other) const;
int CompareTo(const wchar_t* str) const;
returns
< 0
参数大于此String
= 0
参数等于此String
> 0
参数小于此String
大小和字符数据访问
String& SetLength(size_type newLength)
确保 data
指向一个至少有 newLength
+1 个字符大小的数组,或者在 newLength
为 0
时为 nullptr
。
size_type length() const;
size_type Length() const;
返回 string
的 length
(以字符为单位),不包括终止零,或者在 data
为 nullptr
时返回 0
。
const wchar_t* c_str() const;
返回 data
,请注意 data
可能在多个 String
对象之间共享。
wchar_t* c_str();
返回 data
,如果 data
不为 nullptr
,则保证 data
只被此 String
对象引用。
const wchar_t* begin() const;
wchar_t* begin();
const wchar_t* cbegin() const;
const wchar_t* end() const;
const wchar_t* cend() const;
wchar_t* end();
提供对字符缓冲区的“类迭代器”访问。对于非 const
版本,当 data
不为 nullptr
时,保证 data
只被此 String
引用。
“类迭代器”的意思是,它足以提供基于范围的 for 循环所需的功能
String s1 = L"Hello";
for(auto c : s1)
{
std::wcout << L'\'' << c << L'\'' << std::endl;
}
// output:
// 'H'
// 'e'
// 'l'
// 'l'
// 'o'
for(auto& c : s1)
{
c = c+1;
}
for(auto& c : s1)
{
std::wcout << L'\'' << c << L'\'' << std::endl;
}
// output:
// 'I'
// 'f'
// 'm'
// 'm'
// 'p'
const String& CopyTo( wchar_t* buffer, size_type bufferSize,
size_type start = 0, wchar_t padCharacter = defaultPadCharacter ) const;
将此 String
中最多 bufferSize
个字符复制到 buffer
指定的缓冲区中,从 start
开始。如果 start
和此 String
的末尾之间剩余的字符不够,则缓冲区的其余部分将用 padCharacter
填充。
String SubString ( size_type start, size_type length = npos) const;
返回一个包含此 String
子字符串的 String
对象。如果 start
+ length
大于此 String
的长度,则返回的 String
包含 start
和此 String
末尾之间的字符。
搜索
size_type IndexOfAnyOf ( const wchar_t *searchChars,
size_type numberOfSearchChars, size_type start) const;
size_type IndexOfAnyOf ( const String& searchChars, size_type start = 0) const;
size_type IndexOfAnyOf( const wchar_t* searchChars, size_type start = 0) const;
返回 searchChars
中的任意字符的第一次出现索引,从 start
开始搜索。如果找不到这样的字符,则函数返回 String::npos
。
size_type IndexOfAnyBut ( const wchar_t *searchChars,
size_type numberOfSearchChars, size_type start) const;
size_type IndexOfAnyBut ( const String& searchChars, size_type start = 0) const;
size_type IndexOfAnyBut( const wchar_t* searchChars, size_type start = 0) const;
返回 searchChars
中 **不** 包含的任意字符的第一次出现索引,从 start
开始搜索。如果找不到这样的字符,则函数返回 String::npos
。
size_type LastIndexOfAnyOf ( const wchar_t *searchChars,
size_type numberOfSearchChars, size_type start) const;
size_type LastIndexOfAnyOf( const String& searchChars, size_type start = npos) const;
size_type LastIndexOfAnyOf( const wchar_t* searchChars, size_type start = npos) const;
从字符串末尾开始,向后搜索 searchChars
中的任意字符的出现,从 start
开始搜索。如果找到匹配项,则函数返回匹配字符的索引,或者在找不到这样的字符时返回 String::npos
。
size_type LastIndexOfAnyBut ( const wchar_t *searchChars,
size_type numberOfSearchChars, size_type start ) const;
size_type LastIndexOfAnyBut( const String& searchChars, size_type start = npos) const;
size_type LastIndexOfAnyBut( const wchar_t* searchChars, size_type start = npos) const;
从字符串末尾开始,向后搜索 **不** 包含 searchChars
中的任意字符的出现,从 start
开始搜索。如果找到匹配项,则函数返回匹配字符的索引,或者在找不到这样的字符时返回 String::npos
。
size_type IndexOf( const wchar_t *searchString, size_type searchStringLength, size_type start) const;
size_type IndexOf( const String& searchString, size_type start = 0) const;
size_type IndexOf( const wchar_t* searchString, size_type start = 0) const;
size_type IndexOf( const wchar_t c, size_type start = 0) const;
在 start
处开始搜索 String
,以查找 searchString
指定的内容或字符 c
的匹配项。返回第一个匹配项的索引,或者在找不到匹配项时返回 String::npos
。
size_type IndexOf( bool ( *test )(wchar_t ) , size_type start = 0) const;
size_type IndexOf( bool ( *test )(const wchar_t*, size_type length ) , size_type start = 0) const;
size_type IndexOf( bool ( *test )(const wchar_t*, const wchar_t* ) , size_type start = 0) const;
在 start
处开始搜索 String
,以查找由 test
评估的匹配项。返回第一个匹配项的索引,或者在找不到匹配项时返回 String::npos
。
void CheckInvalidPathChars(const String& path)
{
if(path.IndexOf([] (wchar_t c) -> bool
{
return (c == '\"' || c == '<' || c == '>' || c == '|' || c < 32);
}) != String::npos)
{
throw ArgumentException("Invalid path character");
}
}
size_type LastIndexOf( const wchar_t *searchString,
size_type searchStringLength, size_type start ) const;
size_type LastIndexOf( const String& searchString, size_type start = npos) const;
size_type LastIndexOf( const wchar_t* searchString, size_type start = npos) const;
size_type LastIndexOf( wchar_t c, size_type start = npos ) const;
在 start
处开始,向后搜索 String
,以查找 searchString
指定的内容或字符 c
的匹配项。返回第一个匹配项的索引,或者在找不到匹配项时返回 String::npos
。
size_type LastIndexOf( bool ( *test )(wchar_t ) , size_type start = npos) const;
size_type LastIndexOf( bool ( *test )(const wchar_t*, size_type length ) , size_type start = npos) const;
size_type LastIndexOf( bool ( *test )(const wchar_t*, const wchar_t*) , size_type start = npos) const;
在 start
处开始,向后搜索 String
,以查找由 test
评估的匹配项。返回第一个匹配项的索引,或者在找不到匹配项时返回 String::npos
。
bool StartsWith(const wchar_t* str) const;
bool StartsWith(const String& str) const;
如果 string
以与参数的完全匹配开始,则返回 true
。
编辑
所有编辑操作都确保 Buffer
对 String
是唯一的,一个最初与其他 String
对象共享的 Buffer
只会减少其引用计数,而修改将应用于新的 Buffer
。
String& UpperCase();
将此 String
中的所有字符转换为大写。
String& LowerCase();
将此 String
中的所有字符转换为小写。
String& Remove(size_type start, size_type length = npos);
从 start
开始,从此 String
中删除 length
个字符。
String& RemoveRange(size_type start, size_type end);
删除从索引 start 开始到不包括索引 end 的字符。
String& Keep(size_type start, size_type length = npos);
删除到索引 start
的所有字符,以及从索引 start
+length
到此 String
末尾的所有字符。
String& KeepRange(size_type start, size_type end);
删除到索引 start
的所有字符,以及从索引 end
到此 String
末尾的所有字符。
String& Insert( const wchar_t* text, size_type textLength, size_type position );
String& Insert( const String& text, size_type position = 0);
String& Insert( const wchar_t* text, size_type position = 0);
在指定位置插入文本。如果 position
大于此 String
的长度,则文本将追加到此 String
。
String& TrimRight(const wchar_t* charactersToRemove, size_type numberOfCharactersToRemove);
String& TrimRight(const String& charactersToRemove);
从此 String
的“右侧”修剪掉 charactersToRemove
指定的任何字符。
String& TrimRight();
从此 String
的“右侧”修剪掉任何“空白”字符。
String& TrimLeft();
从此 String
的“左侧”修剪掉任何“空白”字符。
String& Trim();
从此 String
的“左侧”和“右侧”修剪掉任何“空白”字符。
历史
- 2012 年 11 月 23 日 - 首次发布
- 2012 年 11 月 24 日 - 添加了性能信息
- 2012 年 11 月 28 日 - 添加了新的
StringBuilder
类 - 2012 年 11 月 30 日 - 库更新
- 2012 年 12 月 8 日 - 库更新
- 2012 年 12 月 15 日 - 库更新
- 2014 年 8 月 20 日 - 多次更新和错误修复
- 2015 年 1 月 3 日 - 添加了一些新类、一些更新和一些错误修复