现在的位置: 首页 > 综合 > 正文

AnsiString类

2014年11月09日 ⁄ 综合 ⁄ 共 12497字 ⁄ 字号 评论关闭

AnsiString类
2007-11-17 19:45:42    业界 |  评论(0) |  浏览(1405)

 AnsiString类是BCB中最常见类之一,了解它对以后深入学习BCB大有帮助原来关于这个类的提出的问题有很多,现总结如下。加上我个人的经验,凑出了一篇关于这个类的最常用方法属性的介绍,希望能对各位有所帮助

常用方法:
  1. char* c_str()
  返回一个字符串指针,他指向的内容和AnsiString中包含的字符串的内容一致(BCB帮助中就是是这样解释这个方法的,关于它更详细的讨论见后文)
  Example:
  AnsiString str = "Hello World!";
  MessageBox(NULL,str.c_str(),"",MB_OK);   //显示一个消息框

  2.AnsiCompare(AnsiString& rhs)
    operator == (AnsiString& rhs)
  都用来比较两个AnsiString的内容是否相同,两者的区别在于当内容相等的时候前者返回0,而后者返回true

  3.int Length()
  很简单,返回字符串长度

  4.char & operator [](const int idx)
   返回字符串中第idx个字符
  注意:这个地方不知道BCB怎么想的,可能是为了照顾Delphi程序员的习惯吧却给C程序员造成了一点小小的麻烦:和C中数组的用法不兼容,也就是说当idx为0的时候,BCB会抛出一个异常,而不是返回第一个字符!要得到第一个字符,idx应该为1
  Example:
  AnsiString str = "Hello World!";
  char byte = str[2];
  //byte等于'e' 而 不等于'l'
  ps.下面的介绍,只要是关于第X个字符的,都和这里一样,不再重复
   
  5.AnsiString SubString(int index, int count)
  返回从第index个字符开始,长度为count子串
  Example:
  AnsiString str = "Hello World!";
  MessageBox(NULL,str.SubString(7,5).c_str(),"",MB_OK);  //显示内容为 World

  6.int Pos(AnsiString& subStr)
  查找内容为subStr的字串,如果有,返回字串的第一个字符位置 如果没有,返回0

  7.int ToInt()
    int ToIntDef(int defaultValue)
  返回当前字符串转化为整数的结果,不同点在于,当不能转化时,前者抛出一个异常,而后者返回defaultValue,嘿嘿,偶喜欢后者

  8.AnsiString LowerCase()
    AnsiString UpperCase()
  返回当前字符串转化为小写/大写的结果
  注意,它们只是返回一个新的AnsiString,原来字符串的内容没有变化

  9.AnsiString& sprintf(char *, ...)
  利用sprintf强大功能格式化当前字符串,详细用法请参考sprintf或者printf

  其它一些操作符:+  +=  >=  >  <  <=  !=
  这些不用解释了吧……

深入探讨:

  1.关于c_str()的返回值问题.
  能否用这个返回值访问/修改字符串中的内容?
  Example:
  AnsiString a = "I want to modify this using pointer";
  char *p = a.c_str();
  p[0] = 'i';
  ........           //指针操作
  ShowMessage(a);
  虽然BCB的帮助表明 c_str()这个函数的返回值(char*)只在它所在表达式内有效,
  但是以上代码有时候却可以完成预期的目的
  个人极力反对用这种方法来改变字符串的内容,因为AnsiString自带的方法已经能够十
分有效的完成指针操作
  比如上面的例子中 p[0] 可以用 a[1] 来代替
  合并字符串可以用 + 或者 += 来替代
  还有查找,插入,删除等,都可以在帮助中找到AnsiString类中对应的方法来实现

  2.Unicode的支持
  由于AnsiString非模板类
  除了WideChar方法外,AnsiString好像不支持Unicode
  但是不知道为什么里面会有ByteType这个方法

  3.很有意思的方法
  Unique()
  LastDelimiter()
  不常用,但是我觉得是十分有意思的函数
  怎么用,可以参考帮助

Ansistring 转 char
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "哈哈";
    char *chr = Test.c_str();
}
   

char转Ansistring
代码:

#include
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString str = "Sample";
    char chr[MAX_PATH];
    strcpy( chr , str.c_str() );
}
 

Bool转AnsiString
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test=BoolToStr(CheckBox1->Checked);
}
 

Ansistring转bool
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{ AnsiString Test="-1"
    CheckBox1->Checked= StrToBool( Test );
}
 

 

int转ansistring
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    int i = 123;
    AnsiString str = IntToStr( i );
}
 

AnsiString转double
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "123";
    long double d = StrToFloat( Test );
}
 

double转AnsiString
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    double d = 123.456;
    AnsiString str = FloatToStr( d );
}
 

 

double转AnsiString并四舍五入

代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    long double d = 123.456121212;
    AnsiString str = FloatToStrF( d , ffFixed ,5 , 4 );
//说明FloatTostrF里5代表从第几个数字的后一位开始四舍五入,4代表取4位小数。
//执行后得到str是123.4600。:roll:
   
}

 

double转AnsiString使用类似vb的format函数

代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    double d = 123.456;
    AnsiString str = FormatFloat( "000000.00" , d );
}
//得到 000123.45,当然你可以使用"# . , ; E+ E- xx"等符号,你自己试试 :wink:
 

AnsiString转Tclor型
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "0x00FF8080";
    TColor Col = StringToColor( Test );
}

Tclor转AnsiString
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    TColor Col = 0x00FF8080;
    AnsiString str = ColorToString( Col );
}

消除AnsiString 中的一部分字符串 代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "ABCDEF";
    int First = 3;     // 消除制定开头
    int Length = 2;    // 消除制定长度
    AnsiString Dstr = Test.Delete( First , Length );
}//得到ABEF
 

在AnsiString 中插入字符串
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "ABCDEF";
    AnsiString Ins = "12345";     // 插入串
    int Pos = 3;                  // 在哪插
    AnsiString Istr = Test.Insert( Ins , Pos );
//得到AB12345CDEF
}

取得ansi某一位字符
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "ABCDEF";
    AnsiString Npos = Test[3];//得到C
}

取得AnsiString里最后一个字符
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "ABCDEF";
    char *Lstr = Test.AnsiLastChar();//得到F
}

取出AnsiString字符,这个类似vb的mid函数!
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "ABCDEF";
    int First = 3;     // 3开始取
    int Length = 2;    // 取2位
    AnsiString Getstr = Test.SubString( First , Length );
//得到CD
}

AnsiString的字母比较
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "ABCDEF";
    AnsiString Sample = "abcdef";
    int Result = Test.AnsiCompare( Sample );
返回1,不同!分大小写。
}

 

代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "ABCDEF";
    AnsiString Sample = "abcdef";
    int Result = Test.AnsiCompareIC( Sample );
//返回0,相同!没有分大小写,哈哈
}

在AnsiString中寻找字符
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "ABCDEF";
    AnsiString Sample = "E";
    int Result = Test.Pos( Sample );
//返回5,如果你写Sample="haha",就返回0,找不到,哈哈
}

在AnsiString中找字符串,和上一个类似
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "ABCDEF";
    AnsiString Sample = "EF";
    int Result = Test.Pos( Sample );
//返回5,即E字符的位置
}

判断字符串长度,类似vb的len
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "拿金币来";
    int Len = Test.Length();
//返回8
}

取得字符串,类似vb的left

代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "小苹果然看了这篇文章";
    AnsiString SLstr = Test.SetLength(6);
}//得到“小苹果”
 

检测双字节字串
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString ChkStr = "你好";
int ChkPos =  1  ;
if ( ByteType( ChkStr , ChkPos ) == mbSingleByte ){
    Edit1->Text="0";
    }
    else{
    Edit1->Text="1";
    }//返回1,如果你写ChkStr="fxxk",就返回0
}

检测空字符串
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "";
    bool chk = Test.IsEmpty();
    if (chk )
    Edit1->Text="1";//返回1
}

全部变小写vs全部变大写
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "ABCdef";
    AnsiString Lstr = Test.LowerCase();
}

代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "ABCdef";
    AnsiString Ustr = Test.UpperCase();
}

类似vb中Trim 的去空格函数
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "     ABCDEF      ";
    AnsiString TLstr = Test.TrimLeft();
   AnsiString TRstr = Test.TrimRight();
  AnsiString Tstr = Test.Trim();
}
 

但是,这个处理不了全角的空格 代码:

AnsiString __fastcall TForm1::TrimStr( AnsiString Tm , AnsiString LR )
{
    // LR … L:左除去   R:右除去   B:dou除去
    int len;
    // 左除去
    if ( LR == "L" || LR == "B" ){
        len = Tm.Length();
        while ( Tm.SubString(1,1) == " " || Tm.SubString(1,2) == " "){
            // 半角除去
            if ( Tm.SubString(1,1) == " " ){
                Tm = Tm.SubString(2,len);
                len = Tm.Length();
            }
            // 全角除去
            else if ( Tm.SubString(1,2) == " " ){
                Tm = Tm.SubString(3,len);
                len = Tm.Length();
            }
        }
    }
    // 右除去
    if ( LR == "R" || LR == "B" ){
        len = Tm.Length();
        while ( Tm.SubString(len,1) == " " || Tm.SubString(len-1,2) == " " ){
            // 半角除去
            if ( Tm.SubString(len,1) == " " ){
                len = Tm.Length();
                Tm = Tm.SubString(1,len-1);
                len = Tm.Length();
            }
            // 全角除去
            else if ( Tm.SubString(len-1,2) == " " ){
                len = Tm.Length();
                Tm = Tm.SubString(1,len-2);
                len = Tm.Length();
            }
        }
    }
    return Tm;
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Test = "  拳脚  ";
    AnsiString Ret = TrimStr(Test,"B")
}

 

相同字符重复输入

代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Soc = AnsiString::StringOfChar( '*' , 100 );
   Edit1->Text=Soc ;//显示100个*

}

字符串替换
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Str = "Borland C++ Builder is free"; 
    AnsiString From = "C++ Builder";                     
    AnsiString To = "Delphi";                             
    AnsiString Result;                                     
    Result = StringReplace( Str, From, To, TReplaceFlags() <<
rfReplaceAll << rfIgnoreCase );
//<<后是参数,得到Borland Delphi is free
}

全角变半角
代码:

    AnsiString Zen = "1234567890";
    int Len = Zen.Length();
    char buf[MAX_PATH];
    ZeroMemory( buf, sizeof( buf ) );
    LCMapString( GetUserDefaultLCID(), LCMAP_HALFWIDTH, Zen.c_str(), Len, buf, sizeof( buf ) );
    AnsiString Han = AnsiString( buf );
    Edit1->Text=Han;
 

半角变全角
代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString Han = "1234567890";
    int Len = Han.Length();
    char buf[MAX_PATH];
    ZeroMemory( buf, sizeof( buf ) );
    LCMapString( GetUserDefaultLCID(), LCMAP_FULLWIDTH, Han.c_str(), Len, buf, sizeof( buf ) );
    AnsiString Zen = AnsiString( buf );
}
 
AnsiString重载了“[]”运算符,可以将内容当做字符数组一样操作,不过和char[]不同的是AnsiString的[]运算符的下标是从1开始的,和Delphi的String 兼容。对于长度不大的AnsiString可以直接使用[]来操作,长度大的时候最好转换成char*在使用,因为重载是通过成员函数实现的,增加了系统的调用开销。
如:

代码:
AnsiString  Temp = "这是一个测试的AnsiString";
int Length = Temp.Length();
for(int i = 1; i <= Length;i++)
{
    if(Temp[i] > 128)
    {
         //........
         //筛选其中的汉字;
         i++;
    }
    else
    {
         //......非汉字的字符。
    }
}

对于长度小的AnsiString不必要使用c_str()转换成C的字符串来操作。

AnsiString的构造函数有一下几种:

代码:
__fastcall AnsiString();
__fastcall AnsiString(const char* src);
__fastcall AnsiString(const AnsiString& src);
__fastcall AnsiString(const char* src, unsigned char len);
__fastcall AnsiString(const wchar_t* src);
__fastcall AnsiString(int src);
__fastcall AnsiString(double src);

__fastcall AnsiString(char src);
__fastcall AnsiString(short);
__fastcall AnsiString(unsigned short);
__fastcall AnsiString(unsigned int);
__fastcall AnsiString(long);
__fastcall AnsiString(unsigned long);
__fastcall AnsiString(__int64);
__fastcall AnsiString(unsigned __int64);
__fastcall AnsiString(const WideString &src);

第一个是缺省构造函数,就是生命一个AnsiString的时候使用的,比如

代码:
AnsiString Str1;

第二个是将字符串常量或者字符数组或者字符指针转换成AnsiString的构造函数,他是根据C字符串的规则进行构造,即以第一个遇到的'/0'字符作为结束字符的。常见的应用是
代码:
AnsiString Str2 = "TestString";

第三个是标准的拷贝构造函数,当执行一个赋值操作的时候实际上就是使用了这个构造函数。
第四个是指定了长度和源的构造函数,他和第二个不同的是,不是以'/0'字符作为结束字符的,而是按照指定的长度为准,这个构造函数可以突破C语言中字符串的限制和不足,可能在实际中更具使用价值,大多数的API返回的都是char*,但并不一定都是可视的字符,也可能包含了'/0',就可以使用这个构造函数来实现对内容的拷贝,尽管第二个参数是unisgned char类型,但是实际中使用好像可以突破256的限制,在一定意义上将这个构造函数可以是我们在使用BCB的时候避免使用new来分配char类型的数组数据,在一个局部的应用中,使用AnsiString保存临时的char数组数据,不需要考虑在什么异常的情况下需要释放内存,因为超出作用域的时候,AnsiString是可以自己释放的。

第五个构造函数可以是的AnsiString可以直接和wchar_t*进行转换,就是可以直接将w_chart*使用=赋值给AnsiString类型。

第六个是将整型转换为字符串的构造函数,也就是可以直接将一个int类型的值赋给AnsiString,其结果和通过IntToStr赋值一样的。
如:
代码:
int Temp = 46573284;
AnsiString Str3 = IntToStr(Temp); 和
AnsiString Str4 = Temp;

结果是一样的。

第七个至第十五个和第六个类似,作用也相当。

第十六个是将Windows的WideString转换为AnsiString的构造函数,也就是可以直接将WideString赋值给AnsiString,而不需要使用其他的方法或者API进行转换,功能和AnsiString(wchar_t*)类似。

String和string是不同的,string是标准从c++支持的处理字符串的类,在c++里我们经常这样使用string
代码:

cout<

但我们不能直接把String像这样使用,但String其实重载了<<这个操作符,如果要这样使用我们必须在头部加入:
#define VCL_IOSTREAM

这样我们可以这样了:
代码:

String str="hello world";
cout<

同理,我们还可以这样:
代码:

String str;
cin>>str;
 

在使用stl的时候,我们经常需要string,但String没有提供直接转换为string的方法,但我们可以这样:
代码:

//---------------------------------------------------------------------------

#pragma hdrstop
#include
#include
#define VCL_IOSTREAM
#include

//---------------------------------------------------------------------------
using namespace std;
#pragma argsused
int main(int argc, char* argv[])
{
  String str="hello world";
  string ss(str.c_str());

  cout<  system("pause");
  return 0;
}
 

 

这时我们可以使用stl的强大能力来处理String了。

混用AnsiString和c_str()的安全问题by nethobo

  当你使用返回AnsiString类型变量的函数,当你要写一个返回AnsiString变量
(不是指针也不是引用)函数时,或者当你使用一个以AnsiString变量为参数的函数,
或者当你整天用VCL控件传入传出AnsiString属性变量时,当这个AnsiString变量
包含很长一个字符串时,你是否有些担心有些不安?担心对象的构造与析构,更担心
的是大字符串的复制(分配内存、内存复制、删除内存)所带来的效率问题?如果你
是一个完美主义者或者是一个比较负责的程序作者比较关系程序效率的话,我想你一
定在每次使用时都有与我一样的这种不安的感觉。
  另外当你想要对一个AnsiString变量所含的字符串进行c的char*裸字符串操作时,
你用AnsiString::c_str()获得char*的指针然后对其进行c字符串操作,这时你是否
会担心你所作的是否会与AnsiString冲突呢,当然前提是你不想一上来就用strcpy
自己作一拷贝(还是效率问题)。

  下面我就本人近来几天编程中发现的问题来探讨一下AnsiString的效率问题及
其c_str()的安全问题。

  BCB的提供了操作动态字符串的类AnsiString的unicode版的WideString,
而且在VCL类中凡用到字符串类型时都是使用的AnsiString。但有时用
c的char*裸字符串来处理一些问题更方便,尤其是在一些编码与解码算法中。
为此AnsiString提供了c_str()函数以返回其内部的char*指针供使用(WideString
中为c_bstr(),问题类似,以下只以AnsiString和c_str为例)。
  首先我们看看第二个问题(它和第一个问题直接相关),看下面的代码:

AnsiString src="test AnsiString";
AnsiString strTest=src; //拷贝构造
char* cp=strTest.c_str();
cp[0]='T';

运行完后,strTest和src的值是什么呢?结果可能与你所预想的大不相同,两都的值都
变成了"Test AnsiString"!也就是说cp[0]='T'的操作同时改变了两个AnsiString变量
的值。为什么会这样呢,执行时按下Ctrl鼠标单击两个变量名,你会发现它们两个所指
向内部字符串是同一个!也就是说在拷贝构造(赋值也一样)时并没有象我们想象的那
样进行内部字符串的复制!好了到现在为至我们至少不用为第一个问题担心了,没有了
字符串的复制,单单是对象的构造与析构算不了什么问题了(AnsiString只有一个Data
成员变量)。
  然而第二个问题就很严重了,再看下面的代码:

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变量的
函数也就没有严重的效率问题了。

  到目前为止,已经真象大白了,结论就是我们不用担心VCL中AnsiString变量传值的
效率问题,另外即使是传值得到的AnsiString对象,我们也不能对其内部数据直接进行
修改(否则你的程序的某些功能模块可以会出现第一次运行正常第二次后就乱七八糟),
尤其是在多线程环境下。原因就不必多说了,大不了复制一份了事。

抱歉!评论已关闭.