AnsiString类是BCB中最常见类之一,了解它对以后深入学习BCB大有帮助。
介绍AnsiString类之前,先要介绍一些背景知识。VCL(Visual Component Library 可视化组件库)大量利用Pascal长字串数据类型,几乎所有基于文本的VCL属性都采用Pascal长字串。例如,Text、Name和Caption属性都是Pascal长字串属性。VCL的许多构件方法和事件处理函数也采用Pascal长字串。由于VCL大量使用Pascal长字串,而C++ Builder使用Pascal VCL,所以Borland生成一个C++类来近似Pascal长字串,这个类就是AnsiString类,可以代替Pascal长字串。
AnsiString类是功能很强的字串类。AnsiString类的内存空间是动态分配的,引用计数,并使用了更新前拷贝(copy­-on-write)技术。这类字符串长度没有限制,其字符类型是ANSIChar 类型。AnsiString类构造器可以从Char、Char*、int或double生成AnsiString类对象。这些构造器很容易将直接字串赋予AnsiString类并将整数或浮点数变成字串。
AnsiString重载了一系列操作符,如下:
· 赋值:“=”
· 字符串链接:“+”、“+=”
· 字符串比较:“==”、“>”、“<”、“<=”、“>=”、“!=”
· 访问:“[]”,用此操作符可以象数组一样访问字符串中的字符。注意:这个地方和C中数组的用法不兼容,第一个字符的下标是1,而不是0。当下标为0时,会抛出一个异常。下面的讨论中提及第index个字符的都是与此相同,不再说明。
方法:
1. char* c_str()
返回当前的对象的字符串空间的首指针,它指向的内容即AnsiString中包含的字符串。
Example:
AnsiString str = "Hello World!";
ShowMessage(str.c_str()); // 显示一个Hello World!的消息框
能否用这个返回值访问/修改字符串中的内容?
Example:
AnsiString a = "I want to modify this using pointer";
char *p = a.c_str();
p[0] = 'i';
........ //指针操作
ShowMessage(a);
可以,但不推荐!
因为AnsiString是动态分配的,所以该字符指针不是永远不变的,而是随时会变的,所以该指针只是一个临时的指针,不要永久的保存,因为说不定什么时候就“野”了。当需要修改字符串的内容时,用[]操作符或用类提供的方法(Insert、Delete等)完全可以实现。
2.AnsiString& Delete(int index, int count)
在字符串中删除从index开始的count个字符。如果index大于字符串的长度,则此方法不删除任何字符;如果count大于从index开始的剩余字符数目,则此方法删除从 index 开始的所有字符。
3.AnsiString& Insert(const AnsiString& str, int index)
在字符串的index位置插入字符串str。
4.int AnsiCompare(AnsiString& rhs)
比较两个AnsiString的内容是否相同,与“==”的区别在于当内容相等的时候前者返回0,而后者返回true。
int AnsiCompareIC(AnsiString& ths)
不区分大小写的比较。
5.int Length()
返回字符串长度,不包括终止符'\0'!
6.bool IsEmpty() const
判断字符串是否为空。
7.AnsiString SubString(int index, int count)
返回一个新的AnsiString, 内容为原字符串从第index个字符开始,长度为count子串。
Example:
AnsiString str = "Hello World!";
ShowMessage(str.SubString(7, 5)); // 显示内容为 World
8.int Pos(AnsiString& subStr)
查找内容为subStr的字串,如果有,返回字串的第一个字符位置 如果没有,返回0。
9.AnsiString LowerCase()
AnsiString UpperCase()
返回一个新的AnsiStirng, 为当前字符串转化为小写/大写的结果。
10. AnsiString& SetLength(int newLength)
返回字符串的Length属性为newLength,内容是原字符串中1-newLength的内容。
11.static AnsiString FormatFloat(const AnsiString& format, const long double& value)
将value用format指定的格式转换为字符串形式。
12.AnsiString& sprintf(char *, ...)
利用sprintf强大功能格式化当前字符串,详细用法请参考sprintf或者printf
13.int ToInt() const
int ToIntDef(int defaultValue) const
返回当前字符串转化为整数的结果,不同点在于,当不能转化时,前者抛出一个异常,而后者返回defaultValue。
double ToDouble() const
将字符串转换为一个浮点数。如果字符串无可用的转换字符,则产生异常。
14.static AnsiString IntToHex(int value, int digits)
将一个整数转换为16进制的字符串形式。
15.AnsiString Trim() const
返回一个新字符串,新字符串中删除了原字符串中前导和后随的空字符串,以及字符串中的控制字符。常用于输出字符串时删除前面和后面的空格。
AnsiString TrimLeft() const
AnsiString TrimRight() const
分别删除字符串前导和后随的空格字符以及控制字符。
注意:处理不了全角的空格。
16.char* AnsiLastChar()
返回字符串的最后一个字符。
17.static AnsiString StringOfChar(char ch, int count)
返回一个包含count个字符ch的字符串。
相关函数(详细的请参阅BCB help):
BoolToStr() // 将bool类型转换成AnsiString
StrToBoll()
IntToStr() // 将int转换成AnsiString
StrToFloat() // 将AnsiString转换成float
FloatToStr()
StringToColor() // 将AnsiString转换成Tcolor类
ColorToString
其他:
看下面的代码:
AnsiString src="test AnsiString";
AnsiString strTest=src; //拷贝构造
char* cp=strTest.c_str();
cp[0]='T';
运行完后,strTest和src的值是什么呢?结果可能与你所预想的大不相同,两都的值都变成了"TestAnsiString"!也就是说cp[0]='T'的操作同时改变了两个AnsiString变量的值。为什么会这样呢,执行时按下Ctrl鼠标单击两个变量名,你会发现它们两个所指 向内部字符串是同一个!也就是说在拷贝构造(赋值也一样)时并没有象我们想象的那样进行内部字符串的复制!
再看下面的代码:
AnsiString src="test AnsiString";
AnsiString strTest=src; //拷贝构造
strTest[1]='x';
char* cp=strTest.c_str();
cp[0]='T';
运行结果就是我们的预期了,为什么加了句strTest[1]='x';就"正常"了呢?很明显AnsiString为了我们第一个问题中的效率问题采用了copy on write技术,也就是只读共享,写时拷贝。这样只有在对象要改变其内部数据的值时才做一份自己的拷贝然后在自己的拷贝中进行修改(就种技术在操作系统中被广泛使用)。同时在对象析构时如果引用计数大于0,数据也不会被删除,它保证数据的有效性。这样返回AnsiString变量的函数也就没有严重的效率问题了。
参考资料:
http://www.newasp.net/tech/program/20747.html
http://baike.baidu.com/view/1206466.htm
http://hi.baidu.com/yuanyuan198737/blog/item/7334a01980dd9a0034fa416a.html