65.9K
CodeProject 正在变化。 阅读更多。
Home

一个 C++ 字符串类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (29投票s)

2012年11月24日

CPOL

13分钟阅读

viewsIcon

126678

downloadIcon

2688

一个快速、引用计数、写时复制的字符串类

更新

开发现在使用 Visual Studio 2013 进行。

现在库中有两个 string 类,AnsiStringWideString,而 String 现在是一个 typedef,它将 String 映射到 WideString

这两个类支持或多或少相同的接口。AnsiString 支持基于 charstring,而 WideString 支持基于 wchar_tstring

基本转换现在由一些 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 为空,并且在内部表示为 nullptrc_str() 现在将返回一个指向以零结尾的空 string 的指针 - 而 data() 将返回 nullptr

ICompareToicompare 执行不区分大小写的比较

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;
    }
};

这使得 AnsiStringWideString 可以用作诸如 std::unordred_map 之类的模板实例化的键。

引言

这是本系列关于 Windows C++ 开发的第五篇文章。

之前的文章可以在这里找到

String 类位于“\HarlinnWindows\hwinstring.h”。

为什么我们还需要另一个 C++ string 类?难道 CStringstd::stringstd::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( ) ); 分别输出了 stdstringString - 这几乎是我们期望的结果,而 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++ 开发者生涯少一些刺激。

这是你无法使用 CStringstd::stringstd::wstring 做到的事情,说到这里,我认为也应该公平地提到 String 类不执行小字符串优化,你也不能指定分配器。它的主要目的是作为 Windows API 工作时原始的以零结尾的 wchar_t string 的替代品,所以我想要的是我可以高效地传递、修改和返回的东西。

与使用 Windows API 的框架相关的 string 类最重要的三个特性是:

  1. 访问 string 的内容
  2. 访问 string 的长度
  3. 作为参数传递和作为结果返回

与 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::wstringCString 相比都足够好。

测试操作于包含 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 在“查找字符串”测试中优于 Stringstd::wstring,但它是通过将自身视为以零结尾的 string 来实现的,忽略了它自己的长度 - 因此,当它包含 '\x00' 字符时,它可能找不到搜索 string 的出现。

CString::FindOneOf 不允许我们指定字符串内的偏移量来开始搜索,这限制了该函数的使用性。

库中还包含一个 StringBuilder 类,使用该类运行“追加字符”测试需要 153.791 毫秒 - 优于所有 string 类。

由于 .NET string 是不可变类型,它在“追加字符”测试中表现不佳也就不足为奇了,它不是为此类用途设计的。令人惊讶的是它在搜索和排序测试中的表现,虽然我没想到它能与 C++ 类媲美,但我确实期望它表现得更好。

观察

String 类与 std::wstringCString 相比表现足够好 - 有一个值得注意的例外,追加字符对于 String 类来说比 CString 慢大约两倍。std::wstringCString 都存储它们分配的容量,而 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 类在这方面似乎比 CStringstd::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 将用 lengthpadCharacter 填充。

String(const wchar_t* str1,size_type length1, 
       const wchar_t* str2,size_type length2, 
       wchar_t padCharacter = defaultPadCharacter);

此构造函数通过连接两个 string 源来创建一个新的 String,如果 str1str2nullptr,则 padCharacter 将用于在新 String 中填充 length1length2 个字符,分别。

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,如果 str1str2str3nullptr,则 padCharacter 将分别用于在新 String 中填充 length1length2length3 个字符。

String(const wchar_t* str);

从以零结尾的 string 创建新的 String。如果 strnullptrlength0,则新 Stringdata 将设置为 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;

如果 datanullptr,则返回 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)

通过连接 str1str2 创建新的 string

friend String operator + (const String& str1,const wchar_t* str2)

通过连接 str1str2 创建新的 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 个字符大小的数组,或者在 newLength0 时为 nullptr

size_type length() const;
size_type Length() const;

返回 stringlength(以字符为单位),不包括终止零,或者在 datanullptr 时返回 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

编辑

所有编辑操作都确保 BufferString 是唯一的,一个最初与其他 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 日 - 添加了一些新类、一些更新和一些错误修复
© . All rights reserved.