精华内容
下载资源
问答
  • MySQL数据类型--字符串类型

    万次阅读 2016-03-22 12:05:17
    字符串类型是在数据库中存储字符串的数据类型,字符串类型包括char,varchar,text,enum和set。 OK,我们来一个一个的看下上面提到的几种类型。 char类型和varchar类型 char类型和varchar类型都是在...

    字符串类型是在数据库中存储字符串的数据类型,字符串类型包括char,varchar,text,enum和set。

    OK,我们来一个一个的看下上面提到的几种类型。

    • char类型和varchar类型

    char类型和varchar类型都是在创建表时指定了最大长度,其基本形式如下:字符串类型(M)。其中,字符串类型参数指定了数据类型是char类型还是varchar类型,M参数指定了该字符串的最大长度为M。举个例子,char(4)就是指数据类型是char类型,其最大长度为4。

    char类型的长度是固定的,在创建表时就指定了,其长度可以是0~~255的任意值。

    比如,char(100)就是指定char类型的长度为100。

    varchar类型的长度是可变的,在创建表时指定了最大长度。定义时,其最大值可以取0~~65525之间的任意值。指定了varchar类型的最大值以后,其长度可以在o到最大长度之间。

    比如,varchar(100)的最大长度是100,但是,不是每条记录都要占用100个字节。而是在这个最大值范围内,使用多少分配多少,varchar类型实际占用的空间为字符串的实际长度加一。这样,即可有效节约系统的空间。

    现在我们在这里举一个例子,我们向char(5)和varchar(5)中存入不同长度的字符串。现在我们将数据库中的存储形式和占用的字节数进行对比,如下图。


    关于上图的解释:

    1,不管我们插入的字符串是什么样子,char(5)所占用的空间都是5个字节。我们前面也说过了,char类型的长度固定

    2,varchar(5)所占的字节数是实际长度的基础上加1。因为字符串的结束标识符占用了一个字节呢。比如说上表中的第四行,varchar将字符串‘123 ’最后面的空格依然保留着。

    为了确认下空格是否保留,我们现在将数据后面模拟加上‘*’字符,然后来实际操作下数据库中的char类型和varchar类型。建表语句如下:
    CREATE TABLE `linkinframe`.`test` (
      `id` INT NOT NULL,
      `a` CHAR(5) NULL,
      `b` VARCHAR(5) NULL,
      PRIMARY KEY (`id`));
    现在我们往数据库中插入几条数据:
    INSERT INTO `linkinframe`.`test` (`id`, `a`, `b`) VALUES ('1','','');
    INSERT INTO `linkinframe`.`test` (`id`, `a`, `b`) VALUES ('2','1','1');
    INSERT INTO `linkinframe`.`test` (`id`, `a`, `b`) VALUES ('3','123','123');
    INSERT INTO `linkinframe`.`test` (`id`, `a`, `b`) VALUES ('4','123 ','123 ');
    INSERT INTO `linkinframe`.`test` (`id`, `a`, `b`) VALUES ('5','12345','12345');
    INSERT INTO `linkinframe`.`test` (`id`, `a`, `b`) VALUES ('6','1234567','1234567');
    模拟数据库数据显示如下:


    总结:上面的实践证明了一个结论,varchar类型将‘123 ’最后面的空格保留着,而char类型中‘123 ’后面的空格自动删除啦。


    char类型和varchar类型是我们最为常用的2种字符串类型,关于这2种类型有如下2点特殊说明:

    1,如果插入的字符串的长度已经大于了可以插入的最大值,那么这个时候数据库会报错,说data too long for column。
    比如说,现在我们定义2个char类型和varchar类型的字段,长度都为5,但是我们插入的值是‘123456’,那么系统就会阻止这个值的插入然后报错。
    关于插入的字符串长度大于数据定义的长度这个问题,资料上是上面这么说的,然后平时编码中使用ORM的时候也明确的遇见过这个错误。
    但是我实际sql实践中,比如上面的插入数据库中的最后一条数据,数据库做了截取操作,并没有报错,而是一个警告,控制台输出如下:

    Data truncated for column 'a' at row 1。 Data truncated for column 'b' at row 1

    2,我们定义长度的时候定义的数据长度,定义的长度就是字符串最大的长度,举个例子,我定义一个name字段,varchar(6),那么该字段最多可以容纳6个汉字。
    这点别和Oracle的varchar2类型的字段搞混淆了。Oracle中的字符串类型2个字节表示一个汉字。
    举个例子,还是上面的建表语句,现在往其中插入一条字符串的数据,一个超过了字符串定义的长度5,一个没有超过,结果超过的字符串被截断啦。
    INSERT INTO `linkinframe`.`test` (`id`, `a`, `b`) VALUES ('6','我爱你','我爱你我爱你');

    数据库现在显示如下:




    • text类型

    text类型是一种特殊的字符串类型。text只能保存字符数据,如新闻的内容等。

    text类型包括tinytext,text,mediumtext,longtext。现在将从4种text类型允许的长度和存储空间进行对比,如下图:


    text类型总结:

    这种字符串类型实际中使用并不是太多,一般用来直接存储一个比较大的文本,比如说一篇文章,一篇新闻。

    从上图也可以看出,各种text类型的区别在于允许的长度和存储空间不同。因此在这几种text类型中,根据需求选取技能满足需要又能节约空间的类型即可。

    • enum类型

    enum类型又称为枚举类型,在创建表时,enum类型的取值范围就以列表的形式指定了。其基本形式如下:属性名 enum('值1','值2',...,'值n'),其中属性名参数指定字段的名称,‘值n’参数表示列表中的第n个值,这些值末尾的空格将会被系统直接删除。注意:

    1,enum类型的值只能去列表中的一个元素,其取值列表中最多只能有65535个值。列表中的每个值都有一个顺序排列的编号,MySQL中存入的是这个编号,而不是列表中的值。
    2,如果enum类型加上了not null属性,其默认值为取值列表中的第一个元素。如果不加not null属性,enum类型将允许插入null,而且null为默认值。

    OK,现在我们来实际模拟下MySQL中这种数据类型。

    建表语句如下:

    CREATE TABLE `linkinframe`.`test` (
      `id` INT NOT NULL,
      `a` ENUM('man', 'woman') NULL,
      PRIMARY KEY (`id`));
    现在我们往数据库中插入几条数据:
    INSERT INTO `linkinframe`.`test` (`id`, `a`) VALUES ('1', 'man');
    INSERT INTO `linkinframe`.`test` (`id`, `a`) VALUES ('2', 'woman');
    INSERT INTO `linkinframe`.`test` (`id`, `a`) VALUES ('3', null);
    INSERT INTO `linkinframe`.`test` (`id`, `a`) VALUES ('4', '2');
    INSERT INTO `linkinframe`.`test` (`id`, `a`) VALUES ('5', '1');
    INSERT INTO `linkinframe`.`test` (`id`, `a`) VALUES ('6', 'huhu');
    现在数据库显示如下:




    OK,关于enum类型的总结:

    1,使用enum类型,数据库中实际存储的每个枚举的编号,而不是列表中的值,所以我们也可以直接插入每个枚举的编号。
    2,实际的实践中,如果我没有在该not null的枚举值上面插入值,或者是随便插入一个值,数据库存储的都为空。
    3,实际存储中,如果只能选取列表中的一个值,就选择enum类型,如果需要选取列表中多个值的组合,就需要选择set类型。

    • set类型

    上面也说到了,如果需要选取列表中多个值的组合,就要选择set类型。在创建表时,set类型的取值范围就以列表的形式指定了。其基本形式如下:属性名 set('值1','值2',....,'值n')。其中,‘属性名’属性指定字段的名称,‘值n’参数表示列表中的第n个值,这些值末尾的空格将会被系统直接删除。其基本形式与enum类型一样。注意:

    1,set类型的值可以去列表中的一个元素或者多个元素的组合。去多个元素时,不同元素之间用逗号隔开。set类型的值最多只能有64个元素构成。

    2,同enum类型一样,列表中的每个值都有一个顺序排列的编号,MySQL中实际存储的是这个编号,而不是列表中的值。

    3,插入记录时,set字段中的元素顺序无关紧要,存入MySQL数据库后,数据库系统会自动按照定义时的顺序显示。OK,现在我们来实际操作下数据库这种数据类型:
    建表语句如下:

    CREATE TABLE `linkinframe`.`test` (
      `id` INT NOT NULL,
      `a` SET('a', 'b', 'c', 'd') NOT NULL,
      PRIMARY KEY (`id`));
    插入几条语句:
    INSERT INTO `linkinframe`.`test` (`id`, `a`) VALUES ('1', 'a');
    INSERT INTO `linkinframe`.`test` (`id`, `a`) VALUES ('2', 'c');
    INSERT INTO `linkinframe`.`test` (`id`, `a`) VALUES ('3', 'a,b');
    INSERT INTO `linkinframe`.`test` (`id`, `a`) VALUES ('4', 'a,b,c,d');
    INSERT INTO `linkinframe`.`test` (`id`, `a`) VALUES ('5', 'a,e');
    数据库显示如下:


    关于set类型的总结:

    1,set类型和enum类型对于取值在一定范围的离散值很有效。enum类型只能在取值列表中取一个值,set类型可以在取值列表中去多个值。

    2,这两种类型的数据都不是直接将数据存入数据库,而是将其列表中的编号存入数据库。

    3,资料中说如果随便往这2种类型中插入数据,会报错,但是我自己的实践中并没有报错,而是插入一个null。

    4,对于set的话,如果插入多个值,其中有些值合法,有些值不合法,那么只会将合法的插入进去,不合法的不做处理。


    展开全文
  • 用C++ 开发,最让人头疼的莫过与跟数据类型打交道,我... ANSI:即 char,可用字符串处理函数:strcat( ),strcpy( ), strlen( )等以str打头的函数。  UNICODE:wchar_t是Unicode字符的数据类型,它实际定义在里:

    用C++ 开发,最让人头疼的莫过与跟数据类型打交道,我觉得微软应该简化这些转换,下面总结一下常用的数据转换。


    1.区别wchar_t,char,WCHAR

      ANSI:即 char,可用字符串处理函数:strcat( ),strcpy( ), strlen( )等以str打头的函数。
      UNICODE:wchar_t是Unicode字符的数据类型,它实际定义在里:
      typedef unsigned short wchar_t;
      另外,在头文件中有这样的定义:typedef wchar_t WCHAR; 所以WCHAR实际就是wchar_t
      wchar_t 可用字符串处理函数:wcscat(),wcscpy(),wcslen()等以wcs打头的函数。为了让编译器识别Unicode字符串,必须以在前面加一个“L”,例如: wchar_t *szTest=L"This is a Unicode string.";

    2.TCHAR

    在C语言里面提供了 _UNICODE宏(有下划线),在Windows里面提供了UNICODE宏(无下划线),只要定了_UNICODE宏和UNICODE宏,系统就会自 动切换到UNICODE版本,否则,系统按照ANSI的方式进行编译和运行。只定义了宏并不能实现自动的转换,他还需要一系列的字符定义支持。
       1. TCHAR
       如果定义了UNICODE宏则TCHAR被定义为wchar_t。
       typedef wchar_t TCHAR;
      否则TCHAR被定义为char typedef char TCHAR;
       2. LPTSTR
      如果定义了UNICODE宏则LPTSTR被定义为LPWSTR。
      typedef LPTSTR LPWSTR;
      否则TCHAR被定义为char typedef LPTSTR LPSTR;
      说明:在使用字符串常量的时候需要使用_TEXT(“MyStr”)或者_T("")来支持系统的自动转换。

    3.BSTR

      BSTR是一个带长度前缀的字符串,主要由操作系统来管理的,所以要用api.主要用来和VB打交道的(VB里的string就是指它)要操作它的API函数有很多.比如SysAllocString,SysFreeString等等.
      vc里封装它的类如_bstr_t,及ATL中的CComBSTR等.
      一个 BSTR 由头部和字符串组成,头部包含了字符串的长度信息,字符串中可以包含嵌入的 null 值。
      BSTR 是以指针的形式进行传递的。(指针是一个变量,包含另外一个变量的内存地址,而不是数据。) BSTR 是 Unicode 的,即每个字符需要两个字节。 BSTR 通常以两字节的 null 字符结束。 wstr是宽字符,以双字节表示一个字符 bstr是为了与原先的basic字符兼容,它的最前面的4个字节为其长度,以'/0'结束.

    4.更进一步的字符串以及其指针的类型定义 

    由于Win32 API文档的函数列表使用函数的常用名字(例如, "SetWindowText"),所有的字符串都是用TCHAR来定义的。(除了XP中引入的只适用于Unicode的API)。下面列出一些常用的typedefs,你可以在msdn中看到他们。

    typeMeaning in MBCS buildsMeaning in Unicode builds
    WCHARwchar_twchar_t
    LPSTRchar*char*
    LPCSTRconst char*const char*
    LPWSTRwchar_t*wchar_t*
    LPCWSTRwchar_t*wchar_t*
    TCHARTCHAR charwchar_t
    LPTSTRTCHAR*TCHAR*
    LPCTSTRconst TCHAR*const TCHAR*


    5.相互转换

    (1) char*转换成CString
      若将char*转换成CString,除了直接赋值外,还可使用CString::Format进行。例如:
    char chArray[] = "This is a test";
    char * p = "This is a test";
      或
    LPSTR p = "This is a test";
      或在已定义Unicode应的用程序中
    TCHAR * p = _T("This is a test");
      或
    LPTSTR p = _T("This is a test");
    CString theString = chArray;
    theString.Format(_T("%s"), chArray);
    theString = p;
      (2) CString转换成char*
      若将CString类转换成char*(LPSTR)类型,常常使用下列三种方法:
      方法一,使用强制转换。例如:
    CString theString( "This is a test" );
    LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString; 
      方法二,使用strcpy。例如:
    CString theString( "This is a test" );
    LPTSTR lpsz = new TCHAR[theString.GetLength()+1];
    _tcscpy(lpsz, theString);
      需要说明的是,strcpy(或可移值Unicode/MBCS的_tcscpy)的第二个参数是 const wchar_t* (Unicode)或const char* (ANSI),系统编译器将会自动对其进行转换。
      方法三,使用CString::GetBuffer。例如:
    CString s(_T("This is a test "));
    LPTSTR p = s.GetBuffer();
    // 在这里添加使用p的代码
    if(p != NULL) *p = _T('/0');
    s.ReleaseBuffer();
    // 使用完后及时释放,以便能使用其它的CString成员函数
      (3) BSTR转换成char*
      方法一,使用ConvertBSTRToString。例如:
    #include
    #pragma comment(lib, "comsupp.lib")
    int _tmain(int argc, _TCHAR* argv[]){
    BSTR bstrText = ::SysAllocString(L"Test");
    char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);
    SysFreeString(bstrText); // 用完释放
    delete[] lpszText2;
    return 0;

      方法二,使用_bstr_t的赋值运算符重载。例如:
    _bstr_t b = bstrText;
    char* lpszText2 = b;
      (4) char*转换成BSTR
      方法一,使用SysAllocString等API函数。例如:
    BSTR bstrText = ::SysAllocString(L"Test");
    BSTR bstrText = ::SysAllocStringLen(L"Test",4);
    BSTR bstrText = ::SysAllocStringByteLen("Test",4);
      方法二,使用COleVariant或_variant_t。例如:
    //COleVariant strVar("This is a test");
    _variant_t strVar("This is a test");
    BSTR bstrText = strVar.bstrVal;
      方法三,使用_bstr_t,这是一种最简单的方法。例如:
    BSTR bstrText = _bstr_t("This is a test");
      方法四,使用CComBSTR。例如:
    BSTR bstrText = CComBSTR("This is a test");
      或
    CComBSTR bstr("This is a test");
    BSTR bstrText = bstr.m_str;
      方法五,使用ConvertStringToBSTR。例如:
    char* lpszText = "Test";
    BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);
      (5) CString转换成BSTR
      通常是通过使用CStringT::AllocSysString来实现。例如:
    CString str("This is a test");
    BSTR bstrText = str.AllocSysString();

    SysFreeString(bstrText); // 用完释放 
      (6) BSTR转换成CString
      一般可按下列方法进行:
    BSTR bstrText = ::SysAllocString(L"Test");
    CStringA str;
    str.Empty();
    str = bstrText; 
      或
    CStringA str(bstrText);
      (7) ANSI、Unicode和宽字符之间的转换
      方法一,使用MultiByteToWideChar将ANSI字符转换成Unicode字符,使用WideCharToMultiByte将Unicode字符转换成ANSI字符。
      方法二,使用“_T”将ANSI转换成“一般”类型字符串,使用“L”将ANSI转换成Unicode,而在托管C++环境中还可使用S将ANSI字符串转换成String*对象。例如:
    TCHAR tstr[] = _T("this is a test");
    wchar_t wszStr[] = L"This is a test";
    String* str = S”This is a test”;
      方法三,使用ATL 7.0的转换宏和类。ATL7.0在原有3.0基础上完善和增加了许多字符串转换宏以及提供相应的类,它具有如图3所示的统一形式:
      其中,第一个C表示“类”,以便于ATL 3.0宏相区别,第二个C表示常量,2表示“to”,EX表示要开辟一定大小的缓冲。SourceType和DestinationType可以是A、 T、W和OLE,其含义分别是ANSI、Unicode、“一般”类型和OLE字符串。例如,CA2CT就是将ANSI转换成一般类型的字符串常量。下面 是一些示例代码:
    LPTSTR tstr= CA2TEX<16>("this is a test");
    LPCTSTR tcstr= CA2CT("this is a test");
    wchar_t wszStr[] = L"This is a test";
    char* chstr = CW2A(wszStr); 
    展开全文
  • Oracle中的字符串类型及相关函数详解

    万次阅读 多人点赞 2016-06-22 08:15:02
    下文将字符串简称为串。 Oracle函数的工作方式有两种: 1、根据旧的对象创建新的对象——他们对原来的信息进行修改,如改变字母的大小写。 2、告诉用户有关的信息,如一个单词或句子中有几个字符。 后续会更新...

    转载请注明出处:http://blog.csdn.net/anxpp/article/details/51550479,谢谢!

    1、概述

        本文介绍String类型及相关的函数,基于当前最新的Oracle 12c 为基础作介绍。

        下文将字符串简称为串。

        Oracle函数的工作方式有两种:

        1、根据旧的对象创建新的对象——他们对原来的信息进行修改,如改变字母的大小写。

        2、告诉用户有关的信息,如一个单词或句子中有几个字符。

        后续会更新另外两种处理文本的方式:Oracle中的正则表达式 和 Oracle Text工具,等文章编辑完成,会在此处添加链接。

        Oracle中主要有两种字符串类型:CHAR和VARCHAR2,他们以字母,标点,数字和空格的混合形式存在。

        CHAR串始终为定长的,如果设置的值长度小于CHAR列的串值,会自动填充空格。在比较CHAR串时,会为双方都补满空格后再进行比较。

        VARCHAR2数据类型为边长的串(VARCHAR与VARCHAR2为同义词)。

    2、字符串处理函数

        2.1、总览

        见下表:

        01

        2.2、连接符||及CONCAT函数

        可以连接两个列名或者常量。

        比如:

    
      
    1. SELECT firstName||lastName FROM USER;

        如果姓名为中文还好,但是如果是英文的,这样连接会导致读起来比较困难,所以可以在中间加上常量“空格”:

    
      
    1. SELECT firstName||' '||lastName FROM USER;

        使用CONCAT函数也能达到同样的效果:

    
      
    1. SELECT CONCAT(firstName,lastName) FROM USER;

        结果:

        02

        但是CONCAT函数符合ANSI SQL标准,所以适合更多不同的数据库,||是Oracle专有的,使用起来更简洁。

        2.3、格式统一:RPAD和LPAD

        RPAD允许在列的右边填充一组字符,填充的字符可以为任何字符。LPAD从左边添加。

        使用方式:

        RPAD(string,length[,'set'])

        LPAD(string,length[,'set'])

        这里的string是数据库中的字符串列或常量,length是填充后的长度,set是用来填充的字符串。如果方括号中的内容省略了,会默认使用空格填充。

        RPAD的使用:

    
      
    1. SELECT rpad(lastname,10,'_') as name from users;

        结果:

        03

        LPAD的使用:

    
      
    1. SELECT lpad(lastname,10) as name from users;

         结果:

        03

        2.4、修剪:LTRIM,RTRIM,TRIM

        LTRIM和RTRIM从串的左边或右边删除不需要的字符。

        使用方式:

        RTRIM(string[,'set'])

        LTRIM(string[,'set'])

        如果没有设置要删除的值,默认删除空格。

        还是用例子来解释,这里有一张存放书名的表,我们得到其书名列的值如下:

    
      
    1. SELECT name FROM BOOK;

        04

        这是因为录入数据的不是同一个人,导致了数据格式不一致,首先我们来试一下LTRIM函数:

    
      
    1. SELECT LTRIM(name,'《') FROM BOOK;

        05

        可以看到左边已经统一了,接下来就是右边,我们很容易就能组合使用LTRIM和RTRIM:

    
      
    1. SELECT RTRIM(LTRIM(name,'《'),'》') FROM BOOK;

        06

        可以看到,查询的结果已经统一了。可以一次删除多个字符,只需要把要删除的串设置进去即可。

        我们在看一个例子,如果某个字段内容为:“the easy way”:

    
      
    1. INSERT INTO BOOK(ID,NAME) VALUES(6,'the easy way');

        我们试着删除前面的the和多余的空格,于是我们执行如下脚本:

    
      
    1. select ltrim(name,'the ') from book where id = 6;

        结果:asy way

        发现并不是我们想要的,以为LTRIM在删除我们指定的字符串时,查找的不是这个字符串,而是里面的一个个字符,只有在第一次发现不属于我们指定的字符串中的字符时才会退出。RTRIM和TRIM的原理也是一样的。为了达到上面的目的,我们可以这样做:

    
      
    1. select ltrim(ltrim(name,'the'),' ') from book where id = 6;

        这样就会输出我们想要的结果。但是还有更为简单的方式就是使用INSTR、SUBTR和DECODE函数,这在后面的文章中会介绍。

        当我们两边要删除的字符是相同的的时候,就可以使用TRIM函数,如果上例中,书名也可能是"think in java"(两边都是单引号)这样的形式的话,如果想直接获取单纯的书名,就可以使用TRIM('"' from name):

    
      
    1. select trim('"' from name) from book where id=7;

        注意TRIM中要删除的只能是单个字符,形如TRIM('《》' from name)是错误的!

        如果要从串的某一段删除,可以使用LEADING和TRAILING字句,这时他们的作用于LTRIM和RTRIM是相同的:

    
      
    1. select trim(leading '"' from name) from book where id=7;

        结果为:think in java"

        2.5、大小写转换:LOWER、UPPER和INITCAP

        LOWER把串或列种的任意字母转换为小写。

        UPPER与LOWER相反。

        INITCAP将串或列中每个单词的首字母转换成大写。

        它们经常一起使用。

        使用格式:

        LOWER(string)

        UPPER(string)

        INITCAP(string)

        我们可以看一下例子就清楚了:

    
      
    1. select name,upper(name),lower(name),initcap(name) from book;

        结果:

        08

        可以看到INITCAP不但将首字母大写了,还将后面的字母转换为小写。

        2.6、长度:LENGTH

        使用LENGTH可以得到一个串的长度。

        使用格式:

        LENGTH(string)

        例如:

    
      
    1. select name,length(name) from book;

        结果:

        09

        2.7、子串:SUBSTR

        使用SUBSTR函数可以提取出串的一部分。

        使用格式:

        SUBSTR(string,start[,count])

        这个函数告诉Oracle提取string的一个子串,从start位置开始,长度为count个字符。如果不指定count,将从start开始一直到这个串结束。

        如果有下面一张表:

    
      
    1. select * from phonebook;

        10

        如果我们需要不含区号的结果,可以这样:

    
      
    1. select rpad(firstname||lastname,10,'.') as name,substr(phone,5) as phone from phonebook;

        结果:

        11

        其中的start参数也可以是负值(仅当值类型为varchar2时,为char时不可用),这时就从串的末尾开始截取,比如上面的例子,也可以这样:

    
      
    1. select rpad(firstname||lastname,10,'.') as name,substr(phone,-9) as phone from phonebook;

        结果与前一个完全一致。

        count参数值一旦指定就必须为正数,否则结果将返回null。

        2.8、索引位置:INSTR

        INSTR可以告诉你要搜索的字符(串)在串种的位置。

        使用格式:

        INSTR(string,set[,start[,occurrence]])

        string为要寻找的列或常量;set为要指定的要寻找的值;start可选,默认为从串的第一个位置开始搜索;occurrence可选,为指定字符串出现的第occurrence次的位置。

        我们依然来看看刚刚的例子:

    
      
    1. SELECT name FROM BOOK;

        12

        执行如下语句:

    
      
    1. select name,instr(name,'a') from book;

        13

        再带上start参数:

    
      
    1. select name,instr(name,'a',7) from book;

        14

        继续加上occurrence参数:

    
      
    1. select name,instr(name,'a',1,2) from book;

        15

        当然,我们也可以查找一个串:

    
      
    1. select name,instr(lower(name),'java') from book;

        16

        我们也经常会将INSTR函数与||、SUBSTR等函数一起使用,比如还是这个例子:

    
      
    1. select * from phonebook;

        17

        我们要将各个列查询出来组合成一个串,其中,phone中的区号不一定就得是3位区号,有些地区就是4位,我们可以使用如下语句:

    
      
    1. select firstname||lastname||':'||substr(phone,instr(phone,'-')+1) as phoneinfo from phonebook;

        18

        2.9、转码:ASCII和CHR

        他们不常用。

        CHR吧数值转换为等价的ASCII字符串;ASCII相反,但效果只对传递给他的值的第一个字符起作用。

        一个例子:

    
      
    1. select 70,chr(70),'F',ascii('F'),ascii('FOCUS') from dual;

        输出:70FF7070

    3、在ORDER BY和WHERE子句中使用串函数

        串函数可以直接用于WHERE子句中:

    
      
    1. select name from book where length(name)>10;

        或者是ORDER BY子句中:

    
      
    1. select name from book order by length(name);

        我们也可以使用前面介绍的函数用于复杂的子句,比如稍微复杂一点的:

    
      
    1. select name from book where instr(name,'a',1,2)>0 and length(name)>10;

        输出:"think in java"

        3.1、发音:SOUNDEX

        SOUNDEX只用于WHERE子句的串函数。

        他能查找在发音上类似于其他词语的单词,无需担心这两个单词是如何拼写的。

        使用格式:SOUNDEX(string)

        比如:

    
      
    1. select * from book where soundex(name) = soundex('java');

        输出:《Java编程思想》

        SOUNDEX还可以结合Oracle Text工具在文章总搜索单词,这会在后面专门介绍Oracle Text的文章中介绍。

    4、小结

        本文主要介绍了Oracle中字符串相关函数的使用。

        有些函数可以在显示前调整内容:RPAD、LPAD、LTRIM、RTRIM、TRIM、LOWER、UPPER、INITCAP、SUBSTR等。

        还有些函数告诉我们串的相关信息:LENGTH、INSTR、SOUNDEX等。

        这些函数都可以单独或者组合使用。

        后续会更新两篇非常相关的文章,到时会将链接添加到下面:

    1.     Oracle中的正则表达式
    2.     Oracle Text工具
    展开全文
  • C++字符串类型说明(类型转换)

    千次阅读 2007-11-02 11:51:00
    引言 因为C语言风格的字符串容易出错且不易管理,黑客们甚至利用可能存在的缓冲区溢出bug把C语言风格的... 这篇文章将介绍所有在Win32 API, MFC, STL, WTL 和 Visual C++ 运行库中出现的字符串类型。我将描述每一个
    引言

      因为C语言风格的字符串容易出错且不易管理,黑客们甚至利用可能存在的缓冲区溢出bug把C语言风格的字符串作为攻击目标,所以出现了很多字符串封装类。不幸的是,在某些场合下我们不知道该使用哪个字符串类,也不知道怎样把一个C风格的字符串转换成一个字符串封装类。
      这篇文章将介绍所有在Win32 API, MFC, STL, WTL 和 Visual C++ 运行库中出现的字符串类型。我将描述每一个类的用法,告诉大家怎样创建每一个类的对象以及怎样把一个类转换成其他类。受控字符串和Visual C++ 7中的类两部分是Nish完成的。
      为了更好的从这篇文章中受益,你必须要明白不同的字符类型和编码,这些内容我在 第一部分中介绍过。
    Rule #1 of string classes

      使用cast来实现类型转换是不好的做法,除非有文档明确指出这种转换可以使用。
    促使我写这两篇文章的原因是字符串类型转换中经常遇到的一些问题。当我们使用cast把字符串从类型X转换到类型Z的时候,我们不知道为什么代码不能正常工作。各种各样的字符串类型,尤其是BSTR,几乎没有在任何一个地方的文档中被明确的指出可以用cast来实现类型转换。所以我想一些人可能会使用cast来实现类型转换并希望这种转换能够正常工作。
      除非源字符串是一个被明确指明支持转换操作符的字符串包装类,否则cast不对字符串做任何转换。对常量字符串使用cast不会起到任何作用,所以下面的代码:

    void SomeFunc ( LPCWSTR widestr );
    main()
    {
      SomeFunc ( (LPCWSTR) "C://foo.txt" );  // WRONG!
    }      
      肯定会失败。它可以被编译,因为cast操作会撤消编译器的类型检查。但是,编译可以通过并不能说明代码是正确的。
      在下面的例子中,我将会指明cast在什么时候使用是合法的。
    C-style strings and typedefs

      正如我在第一部分中提到的,windows APIs 是用TCHARs来定义的,在编译时,它可以根据你是否定义_MBCS或者_UNICODE被编译成MBCS或者Unicode字符。你可以参看第一部分中对TCHAR的完整描述,这里为了方便,我列出了字符的typedefs

    TypeMeaning
    WCHARUnicode character (wchar_t)
    TCHARMBCS or Unicode character, depending on preprocessor settings
    LPSTR string of char (char*)
    LPCSTRconstant string of char (const char*)
    LPWSTR string of WCHAR (WCHAR*)
    LPCWSTR constant string of WCHAR (const WCHAR*)
    LPTSTR string of TCHAR (TCHAR*)
    LPCTSTR constant string of TCHAR (const TCHAR*)

      一个增加的字符类型是OLETYPE。它表示自动化接口(如word提供的可以使你操作文档的接口)中使用的字符类型。这种类型一般被定义成wchar_t,然而如果你定义了OLE2ANSI预处理标记,OLECHAR将会被定义成char类型。我知道现在已经没有理由定义OLE2ANSI(从MFC3以后,微软已经不使用它了),所以从现在起我将把OLECHAR当作Unicode字符。
    这里给出你将会看到的一些OLECHAR相关的typedefs:

    TypeMeaning
    OLECHAR Unicode character (wchar_t)
    LPOLESTR string of OLECHAR (OLECHAR*)
    LPCOLESTR constant string of OLECHAR (const OLECHAR*)

      还有两个用于包围字符串和字符常量的宏定义,它们可以使同样的代码被用于MBCS和Unicode builds :

    Type Meaning
    _T(x)Prepends L to the literal in Unicode builds.
    OLESTR(x)Prepends L to the literal to make it an LPCOLESTR.

      在文档或例程中,你还会看到好多_T的变体。有四个等价的宏定义,它们是TEXT, _TEXT, __TEXT和__T,它们都起同样的做用。

    COM 中的字符串 —— BSTR 和 VARIANT

      很多自动化和COM接口使用BSTR来定义字符串。BSTRs中有几个"陷阱",所以这里我用单独的部分来说明它。
      BSTR 是 Pascal-style 字符串(字符串长度被明确指出)和C-style字符串(字符串的长度要通过寻找结束符来计算)的混合产物。一个BSTR是一个Unicode字符串,它的长度是预先考虑的,并且它还有一个0字符作为结束标记。下面是一个BSTR的示例:

     

    06 00 00 0042 006F 0062 0000 00
    --length--BobEOS

      注意字符串的长度是如何被加到字符串数据中的。长度是DWORD类型的,保存了字符串中包含的字节数,但不包括结束标记。在这个例子中,"Bob"包含3个Unicode字符(不包括结束符),总共6个字节。字符串的长度被预先存储好,以便当一个BSTR在进程或者计算机之间被传递时,COM库知道多少数据需要传送。(另一方面,一个BSTR能够存储任意数据块,而不仅仅是字符,它还可以包含嵌入在数据中的0字符。然而,由于这篇文章的目的,我将不考虑那些情况)。
      在 C++ 中,一个 BSTR 实际上就是一个指向字符串中第一个字符的指针。它的定义如下:

    BSTR bstr = NULL;
      bstr = SysAllocString ( L"Hi Bob!" ); 
      if ( NULL == bstr )
        // out of memory error 
      // Use bstr here...
     SysFreeString ( bstr );      
    自然的,各种各样的BSTR封装类为你实现内存管理。
      另外一个用在自动化接口中的变量类型是VARIANT。它被用来在无类型(typeless)语言,如Jscript和VBScript,来传递数据。一个VARIANT可能含有很多不同类型的数据,例如long和IDispatch*。当一个VARIANT包含一个字符串,字符串被存成一个BSTR。当我后面讲到VARIANT封装类时,我会对VARIANT多些介绍。

    字符串封装类

      到目前为止,我已经介绍了各种各样的字符串。下面,我将说明封装类。对于每个封装类,我将展示怎样创建一个对象及怎样把它转换成一个C语言风格的字符串指针。C语言风格的字符串指针对于API的调用,或者创建一个不同的字符串类对象经常是必需的。我不会介绍字符串类提供的其他操作,比如排序和比较。
      重复一遍,除非你确切的明白结果代码将会做什么,否则不要盲目地使用cast来实现类型转换。

    CRT提供的类

    _bstr_t
      _bstr_t是一个对BSTR的完整封装类,实际上它隐藏了底层的BSTR。它提供各种构造函数和操作符来访问底层的C语言风格的字符串。然而,_bstr_t却没有访问BSTR本身的操作符,所以一个_bstr_t类型的字符串不能被作为输出参数传给一个COM方法。如果你需要一个BSTR*参数,使用ATL类CComBSTR是比较容易的方式。
      一个_bstr_t字符串能够传给一个接收参数类型为BSTR的函数,只是因为下列3个条件同时满足。首先,_bstr_t有一个向wchar_t*转换的转换函数;其次,对编译器而言,因为BSTR的定义,wchar_t*和BSTR有同样的含义;第三,_bstr_t内部含有的wchar_t*指向一片按BSTR的形式存储数据的内存。所以,即使没有文档说明,_bstr_t可以转换成BSTR,这种转换仍然可以正常进行。
    // Constructing
    _bstr_t bs1 = "char string";       // construct from a LPCSTR
    _bstr_t bs2 = L"wide char string"; // construct from a LPCWSTR
    _bstr_t bs3 = bs1;                 // copy from another _bstr_t
    _variant_t v = "Bob";
    _bstr_t bs4 = v;                   // construct from a _variant_t that has a string
     
    // Extracting data
    LPCSTR psz1 = bs1;              // automatically converts to MBCS string
    LPCSTR psz2 = (LPCSTR) bs1;     // cast OK, same as previous line
    LPCWSTR pwsz1 = bs1;            // returns the internal Unicode string
    LPCWSTR pwsz2 = (LPCWSTR) bs1;  // cast OK, same as previous line
    BSTR    bstr = bs1.copy();      // copies bs1, returns it as a BSTR
     
      // ...
    SysFreeString ( bstr );      
      注意_bstr_t也提供char*和wchar_t*之间的转换操作符。这是一个值得怀疑的设计,因为即使它们是非常量字符串指针,你也一定不能使用这些指针去修改它们指向的缓冲区的内容,因为那将破坏内部的BSTR结构。

    _variant_t
      _variant_t是一个对VARIANT的完整封装,它提供很多构造函数和转换函数来操作一个VARIANT可能包含的大量的数据类型。这里,我将只介绍与字符串有关的操作。
    // Constructing
    _variant_t v1 = "char string";       // construct from a LPCSTR
    _variant_t v2 = L"wide char string"; // construct from a LPCWSTR
    _bstr_t bs1 = "Bob";
    _variant_t v3 = bs1;                 // copy from a _bstr_t object
     
    // Extracting data
    _bstr_t bs2 = v1;           // extract BSTR from the VARIANT
    _bstr_t bs3 = (_bstr_t) v1; // cast OK, same as previous line      
    注意
      如果类型转换不能被执行,_variant_t方法能够抛出异常,所以应该准备捕获_com_error异常。

    还需要注意的是
      没有从一个_variant_t变量到一个MBCS字符串的直接转换。你需要创建一个临时的_bstr_t变量,使用提供Unicode到MBCS转换的另一个字符串类或者使用一个ATL转换宏。
      不像_bstr_t,一个_variant_t变量可以被直接作为参数传递给一个COM方法。_variant_t
      继承自VARIANT类型,所以传递一个_variant_t来代替VARIANT变量是C++语言所允许的。

    STL 类
      STL只有一个字符串类,basic_string。一个basic_string管理一个以0做结束符的字符串数组。字符的类型是basic_string模般的参数。总的来说,一个basic_string类型的变量应该被当作不透明的对象。你可以得到一个指向内部缓冲区的只读指针,但是任何写操作必须使用basic_string的操作符和方法。
      basic_string有两个预定义的类型:包含char的string类型和包含wchar_t的wstring类型。这里没有内置的包含TCHAR的类型,但是你可以使用下面列出的代码来实现。
    // Specializations
    typedef basic_string
      tstring; // string of TCHARs
     
    // Constructing
    string str = "char string";         // construct from a LPCSTR
    wstring wstr = L"wide char string"; // construct from a LPCWSTR
    tstring tstr = _T("TCHAR string");  // construct from a LPCTSTR
     
    // Extracting data
    LPCSTR psz = str.c_str();    // read-only pointer to str''s buffer
    LPCWSTR pwsz = wstr.c_str(); // read-only pointer to wstr''s buffer
    LPCTSTR ptsz = tstr.c_str(); // read-only pointer to tstr''s buffer
    
      不像_bstr_t,一个basic_string变量不能在字符集之间直接转换。然而,你可以传递由c_str()返回的指针给另外一个类的构造函数(如果这个类的构造函数接受这种字符类型)。例如:
    // Example, construct _bstr_t from basic_string
    _bstr_t bs1 = str.c_str();  // construct a _bstr_t from a LPCSTR
    _bstr_t bs2 = wstr.c_str(); // construct a _bstr_t from a LPCWSTR      
    ATL 类

    CComBSTR
      CComBSTR 是 ATL 中的 BSTR 封装类,它在某些情况下比_bstr_t有用的多。最引人注意的是CComBSTR允许访问底层的BSTR,这意味着你可以传递一个CComBSTR对象给COM的方法。CComBSTR对象能够替你自动的管理BSTR的内存。例如,假设你想调用下面这个接口的方法:
    // Sample interface:
    struct IStuff : public IUnknown
    {
      // Boilerplate COM stuff omitted...
      STDMETHOD(SetText)(BSTR bsText);
      STDMETHOD(GetText)(BSTR* pbsText);
    };      
      CComBSTR有一个操作符--BSTR方法,所以它能直接被传给SetText()函数。还有另外一个操作--&,这个操作符返回一个BSTR*。所以,你可以对一个CComBSTR对象使用&操作符,然后把它传给需要BSTR*参数的函数。
    CComBSTR bs1;
    CComBSTR bs2 = "new text";
     
      pStuff->GetText ( &bs1 );       // ok, takes address of internal BSTR
      pStuff->SetText ( bs2 );        // ok, calls BSTR converter
      pStuff->SetText ( (BSTR) bs2 ); // cast ok, same as previous line      
      CComBSTR有和_bstr_t相似的构造函数,然而却没有内置的向MBCS字符串转换的函数。因此,你需要使用一个ATL转换宏。
    // Constructing
    CComBSTR bs1 = "char string";       // construct from a LPCSTR
    CComBSTR bs2 = L"wide char string"; // construct from a LPCWSTR
    CComBSTR bs3 = bs1;                 // copy from another CComBSTR
    CComBSTR bs4;
    
      bs4.LoadString ( IDS_SOME_STR );  // load string from string table
    // Extracting data
    BSTR bstr1 = bs1;        // returns internal BSTR, but don''t modify it!
    BSTR bstr2 = (BSTR) bs1; // cast ok, same as previous line
    BSTR bstr3 = bs1.Copy(); // copies bs1, returns it as a BSTR
    BSTR bstr4;
      bstr4 = bs1.Detach();  // bs1 no longer manages its BSTR
      // ...
      SysFreeString ( bstr3 );
      SysFreeString ( bstr4 );      
      注意在上个例子中使用了Detach()方法。调用这个方法后,CComBSTR对象不再管理它的BSTR字符串或者说它对应的内存。这就是bstr4需要调用SysFreeString()的原因。
      做一个补充说明:重载的&操作符意味着在一些STL容器中你不能直接使用CComBSTR变量,比如list。容器要求&操作符返回一个指向容器包含的类的指针,但是对CComBSTR变量使用&操作符返回的是BSTR*,而不是CComBSTR*。然而,有一个ATL类可以解决这个问题,这个类是CAdapt。例如,你可以这样声明一个CComBSTR的list:
    std::list< CAdapt<CComBSTR> > bstr_list;

      CAdapt提供容器所需要的操作符,但这些操作符对你的代码是透明的。你可以把一个bstr_list当作一个CComBSTR的list来使用。

    CComVariant
      CComVariant是VARIANT的封装类。然而,不像_variant_t,在CComVariant中VARIANT没有被隐藏。事实上你需要直接访问VARIANT的成员。CComVariant提供了很多构造函数来对VARIANT能够包含的多种类型进行处理。这里,我将只介绍和字符串相关的操作。

    // Constructing
    CComVariant v1 = "char string";       // construct from a LPCSTR
    CComVariant v2 = L"wide char string"; // construct from a LPCWSTR
    CComBSTR bs1 = "BSTR bob";
    CComVariant v3 = (BSTR) bs1;          // copy from a BSTR
     
    // Extracting data
    CComBSTR bs2 = v1.bstrVal;            // extract BSTR from the VARIANT      
      不像_variant_t,这里没有提供针对VARIANT包含的各种类型的转换操作符。正如上面介绍的,你必须直接访问VARIANT的成员并且确保这个VARIANT变量保存着你期望的类型。如果你需要把一个CComVariant类型的数据转换成一个BSTR类型的数据,你可以调用ChangeType()方法。
    CComVariant v4 = ... // Init v4 from somewhere
    CComBSTR bs3;
     
      if ( SUCCEEDED( v4.ChangeType ( VT_BSTR ) ))
        bs3 = v4.bstrVal;      
      像_variant_t一样,CComVariant也没有提供向MBCS字符串转换的转换操作。你需要创建一个_bstr_t类型的中间变量,使用提供从Unicode到MBCS转换的另一个字符串类,或者使用一个ATL的转换宏。

    ATL转换宏

      ATL:转换宏是各种字符编码之间进行转换的一种很方便的方式,在函数调用时,它们显得非常有用。ATL转换宏的名称是根据下面的模式来命名的[源类型]2[新类型]或者[源类型]2C[新类型]。据有第二种形式的名字的宏的转换结果是常量指针(对应名字中的"C")。各种类型的简称如下:
    A: MBCS string, char* (A for ANSI)
    W: Unicode string, wchar_t* (W for wide)
    T: TCHAR string, TCHAR*
    OLE: OLECHAR string, OLECHAR* (in practice, equivalent to W)
    BSTR: BSTR (used as the destination type only)

      所以,W2A()宏把一个Unicode字符串转换成一个MBCS字符串。T2CW()宏把一个TCHAR字符串转转成一个Unicode字符串常量。
      为了使用这些宏,需要先包含atlconv.h头文件。你甚至可以在非ATL工程中包含这个头文件来使用其中定义的宏,因为这个头文件独立于ATL中的其他部分,不需要一个_Module全局变量。当你在一个函数中使用转换宏时,需要把USES_CONVERSION宏放在函数的开头。它定义了转换宏所需的一些局部变量。
      当转换的目的类型是除了BSTR以外的其他类型时,被转换的字符串是存在栈中的。所以,如果你想让字符串的生命周期比当前的函数长,你需要把这个字符串拷贝到其他的字符串类中。当目的类型是BSTR时,内存不会自动被释放,你必须把返回值赋给一个BSTR变量或者一个BSTR封装类以避免内存泄漏。
      下面是一些各种转换宏的使用例子:

    // Functions taking various strings:
    void Foo ( LPCWSTR wstr );
    void Bar ( BSTR bstr );
    // Functions returning strings:
    void Baz ( BSTR* pbstr );
    #include <atlconv.h>
    main()
    {
    using std::string;
    USES_CONVERSION;    // declare locals used by the ATL macros
    // Example 1: Send an MBCS string to Foo()
    LPCSTR psz1 = "Bob";
    string str1 = "Bob";
     
      Foo ( A2CW(psz1) );
      Foo ( A2CW(str1.c_str()) );
     
    // Example 2: Send a MBCS and Unicode string to Bar()
    LPCSTR psz2 = "Bob";
    LPCWSTR wsz = L"Bob";
    BSTR bs1;
    CComBSTR bs2;
     
      bs1 = A2BSTR(psz2);         // create a BSTR
      bs2.Attach ( W2BSTR(wsz) ); // ditto, assign to a CComBSTR 
      Bar ( bs1 );
      Bar ( bs2 );
     
      SysFreeString ( bs1 );      // free bs1 memory
      // No need to free bs2 since CComBSTR will do it for us.
     
    // Example 3: Convert the BSTR returned by Baz()
    BSTR bs3 = NULL;
    string str2;
      Baz ( &bs3 );          // Baz() fills in bs3
      str2 = W2CA(bs3);      // convert to an MBCS string
      SysFreeString ( bs3 ); // free bs3 memory
    }      
      正如你所看见的,当你有一个和函数所需的参数类型不同的字符串时,使用这些转换宏是非常方便的。

    MFC类

    CString
      因为一个MFC CString类的对象包含TCHAR类型的字符,所以确切的字符类型取决于你所定义的预处理符号。大体来说,CString 很像STL string,这意味着你必须把它当成不透明的对象,只能使用CString提供的方法来修改CString对象。CString有一个string所不具备的优点:CString具有接收MBCS和Unicode两种字符串的构造函数,它还有一个LPCTSTR转换符,所以你可以把CString对象直接传给一个接收LPCTSTR的函数而不需要调用c_str()函数。
    // Constructing
    CString s1 = "char string";  // construct from a LPCSTR
    CString s2 = L"wide char string";  // construct from a LPCWSTR
    CString s3 ( '' '', 100 );  // pre-allocate a 100-byte buffer, fill with spaces
    CString s4 = "New window text";
     
      // You can pass a CString in place of an LPCTSTR:
      SetWindowText ( hwndSomeWindow, s4 );
     
      // Or, equivalently, explicitly cast the CString:
      SetWindowText ( hwndSomeWindow, (LPCTSTR) s4 );        
      你可以从你的字符串表中装载一个字符串,CString的一个构造函数和LoadString()函数可以完成它。Format()方法能够从字符串表中随意的读取一个具有一定格式的字符串。     
    // Constructing/loading from string table
    CString s5 ( (LPCTSTR) IDS_SOME_STR );  // load from string table
    CString s6, s7; 
      // Load from string table.
      s6.LoadString ( IDS_SOME_STR );
     
      // Load printf-style format string from the string table:
      s7.Format ( IDS_SOME_FORMAT, "bob", nSomeStuff, ... );  
      第一个构造函数看起来有点奇怪,但是这实际上是文档说明的装入一个字符串的方法。 注意,对一个CString变量,你可以使用的唯一合法转换符是LPCTSTR。转换成LPTSTR(非常量指针)是错误的。养成把一个CString变量转换成LPTSTR的习惯将会给你带来伤害,因为当你的程序后来崩溃时,你可能不知道为什么,因为你到处都使用同样的代码而那时它们都恰巧正常工作。正确的得到一个指向缓冲区的非常量指针的方法是调用GetBuffer()方法。下面是正确的用法的一个例子,这段代码是给一个列表控件中的项设定文字:
    CString str = _T("new text");
    LVITEM item = {0};
      item.mask = LVIF_TEXT;
      item.iItem = 1;
      item.pszText = (LPTSTR)(LPCTSTR) str; // WRONG!
      item.pszText = str.GetBuffer(0);      // correct
     
      ListView_SetItem ( &item );
    str.ReleaseBuffer();  // return control of the buffer to str      
      pszText成员是一个LPTSTR变量,一个非常量指针,因此你需要对str调用GetBuffer()。GetBuffer()的参数是你需要CString为缓冲区分配的最小长度。如果因为某些原因,你需要一个可修改的缓冲区来存放1K TCHARs,你需要调用GetBuffer(1024)。把0作为参数时,GetBuffer()返回的是指向字符串当前内容的指针。
      上面划线的语句可以被编译,在这种情况下,甚至可以正常起作用。但这并不意味着这行代码是正确的。通过使用非常量转换,你已经破坏了面向对象的封装,并对CString的内部实现作了某些假定。如果你有这样的转换习惯,你终将会陷入代码崩溃的境地。你会想代码为什么不能正常工作了,因为你到处都使用同样的代码而那些代码看起来是正确的。
      你知道人们总是抱怨现在的软件的bug是多么的多吗?软件中的bug是因为程序员写了不正确的代码。难道你真的想写一些你知道是错误的代码来为所有的软件都满是bug这种认识做贡献吗?花些时间来学习使用CString的正确方法让你的代码在任何时间都正常工作把。
      CString 有两个函数来从一个 CString 创建一个 BSTR。它们是 AllocSysString() 和SetSysString()。
    // Converting to BSTR
    CString s5 = "Bob!";
    BSTR bs1 = NULL, bs2 = NULL;
      bs1 = s5.AllocSysString();
      s5.SetSysString ( &bs2 );
      SysFreeString ( bs1 );
      SysFreeString ( bs2 );      
    COleVariant
      COleVariant和CComVariant.很相似。COleVariant继承自VARIANT,所以它可以传给接收VARIANT的函数。然而,不像CComVariant,COleVariant只有一个LPCTSTR构造函数。没有对LPCSTR 和LPCWSTR的构造函数。在大多数情况下这不是一个问题,因为不管怎样你的字符串很可能是LPCTSTRs,但这是一个需要意识到的问题。COleVariant还有一个接收CString参数的构造函数。
    // Constructing
    CString s1 = _T("tchar string");
    COleVariant v1 = _T("Bob"); // construct from an LPCTSTR
    COleVariant v2 = s1; // copy from a CString      
      像CComVariant一样,你必须直接访问VARIANT的成员。如果需要把VARIANT转换成一个字符串,你应该使用ChangeType()方法。然而,COleVariant::ChangeType()如果失败会抛出异常,而不是返回一个表示失败的HRESULT代码。
    // Extracting data
    COleVariant v3 = ...; // fill in v3 from somewhere
    BSTR bs = NULL;
      try
        {
        v3.ChangeType ( VT_BSTR );
        bs = v3.bstrVal;
        }
      catch ( COleException* e )
        {
        // error, couldn''t convert
        }
      SysFreeString ( bs );      

    WTL 类

    CString
      WTL的CString的行为和MFC的 CString完全一样,所以你可以参考上面关于MFC的 CString的介绍。

    CLR 和 VC 7 类

      System::String是用来处理字符串的.NET类。在内部,一个String对象包含一个不可改变的字符串序列。任何对String对象的操作实际上都是返回了一个新的String对象,因为原始的对象是不可改变的。String的一个特性是如果你有不止一个String对象包含相同的字符序列,它们实际上是指向相同的对象的。相对于C++的使用扩展是增加了一个新的字符串常量前缀S,S用来代表一个受控的字符串常量(a managed string literal)。
    // Constructing
    String* ms = S"This is a nice managed string";      
      你可以传递一个非受控的字符串来创建一个String对象,但是样会比使用受控字符串来创建String对象造成效率的微小损失。这是因为所有以S作为前缀的相同的字符串实例都代表同样的对象,但这对非受控对象是不适用的。下面的代码清楚地阐明了这一点:
    String* ms1 = S"this is nice";
    String* ms2 = S"this is nice";
    String* ms3 = L"this is nice";
      Console::WriteLine ( ms1 == ms2 ); // prints true
      Console::WriteLine ( ms1 == ms3);  // prints false      
    正确的比较可能没有使用S前缀的字符串的方法是使用String::CompareTo()
      Console::WriteLine ( ms1->CompareTo(ms2) );
      Console::WriteLine ( ms1->CompareTo(ms3) );      
      上面的两行代码都会打印0,0表示两个字符串相等。 String和MFC 7 CString之间的转换是很容易的。CString有一个向LPCTSTR的转换操作,而String有两个接收char* 和 wchar_t*的构造函数,因此你可以把一个CString变量直接传给一个String的构造函数。
    CString s1 ( "hello world" );
    String* s2 ( s1 );  // copy from a CString      
    反方向的转换也很类似
    String* s1 = S"Three cats";
    CString s2 ( s1 );      
      这也许会使你感到一点迷惑,但是它确实是起作用的。因为从VS.NET 开始,CString 有了一个接收String 对象的构造函数。
      CStringT ( System::String* pString );      
    对于一些快速操作,你可能想访问底层的字符串:
    String* s1 = S"Three cats";
      Console::WriteLine ( s1 );
    const __wchar_t __pin* pstr = PtrToStringChars(s1);
      for ( int i = 0; i < wcslen(pstr); i++ )
        (*const_cast<__wchar_t*>(pstr+i))++;
      Console::WriteLine ( s1 );      
      PtrToStringChars()返回一个指向底层字符串的const __wchar_t* ,我们需要固定它,否则垃圾收集器或许会在我们正在管理它的内容的时候移动了它。

    在 printf-style 格式函数中使用字符串类

      当你在printf()或者类似的函数中使用字符串封装类时你必须十分小心。这些函数包括sprintf()和它的变体,还有TRACE和ATLTRACE宏。因为这些函数没有对添加的参数的类型检查,你必须小心,只能传给它们C语言风格的字符串指针,而不是一个完整的字符串类。
      例如,要把一个_bstr_t 字符串传给ATLTRACE(),你必须使用显式转换(LPCSTR) 或者(LPCWSTR):
    _bstr_t bs = L"Bob!";
    ATLTRACE("The string is: %s in line %d/n", (LPCSTR) bs, nLine);

      如果你忘了使用转换符而把整个_bstr_t对象传给了函数,将会显示一些毫无意义的输出,因为_bstr_t保存的内部数据会全部被输出。

    所有类的总结

      两个字符串类之间进行转换的常用方式是:先把源字符串转换成一个C语言风格的字符串指针,然后把这个指针传递给目的类型的构造函数。下面这张表显示了怎样把一个字符串转换成一个C语言风格的字符串指针以及哪些类具有接收C语言风格的字符串指针的构造函数。

    Class  string type convert to char*? convert to const char*? convert to wchar_t*? convert to const wchar_t*? convert to BSTR? construct from char*? construct from wchar_t*?
    _bstr_tBSTRyes cast1yes cast yes cast 1 yes castyes2 yes yes
    _variant_tBSTRnononocast to
    _bstr_t3
    cast to
    _bstr_t3
    yes yes
    stringMBCS noyes c_str() method nonono yesno
    wstringUnicode no no no yes c_str() methodnono yes
    CComBSTRBSTR no no noyes cast to BSTRyes cast yes yes
    CComVariant BSTR no no noyes4 yes 4 yes yes
    CString TCHAR no6in MBCS
    builds, cast
    no 6in Unicode
    builds, cast
    no5 yes yes
    COleVariant BSTR no no no yes 4 yes 4 in MBCS
    builds
    in Unicode
    builds
  • 1、即使 _bstr_t 提供了向非常量指针的转换操作符,修改底层的缓冲区也会已引起GPF如果你溢出了缓冲区或者造成内存泄漏。
  • 2 、_bstr_t 在内部用一个 wchar_t* 来保存 BSTR,所以你可以使用 const wchar_t* 来访问BSTR。这是一个实现细节,你可以小心的使用它,将来这个细节也许会改变。
  • 3 、如果数据不能转换成BSTR会抛出一个异常。
  • 4 、使用 ChangeType(),然后访问 VARIANT 的 bstrVal 成员。在MFC中,如果数据转换不成功将会抛出异常。
  • 5 、这里没有转换 BSTR 函数,然而 AllocSysString() 返回一个新的BSTR。
  • 6 、使用 GetBuffer() 方法,你可以暂时地得到一个非常量的TCHAR指针。

  •  
    展开全文
  • 字符串类型处理实战

    千次阅读 2011-04-15 21:27:00
    在MFC中,为了服务于字符串操作,添加了类CString,该类的头 文件是afx.h.从char* 到CString的转换很简单,只需要用CString的构造函数即可。  CString到const char*和char*  新手在将CString向C的字符数组...
  • C++字符串类型说明(Win32 字符编码)

    千次阅读 2007-11-02 11:47:00
    引言 毫无疑问,我们都看到过像 TCHAR, std::string, BSTR 等各种各样的字符串类型,还有那些以 _tcs 开头的奇怪的宏。你也许正在盯着显示器发愁。本指引将总结引进各种字符类型的目的,展示一些简单的用法,并告诉...
  • 自动类型转换适用于兼容类型之间从小范围到大范围... 里面靠近字符串,所以a被转化为字符串了,结果为11 (1)String s = String.valueOf(i); String 类别中已经提供了将基本数据型态转换成 String 的 static 方法...
  • c++字符串类型(转载)

    千次阅读 2008-04-22 14:03:00
    区别wchar_t,char,WCHAR ANSI:即 char,可用字符串处理函数:strcat( ),strcpy( ), strlen( )等以str打头的函数。 UNICODE:wchar_t是Unicode字符的数据类型,它实际定义在里: typedef unsigned short wchar_t;...
  • 字符串 https://ww2.mathworks.cn/help/matlab/characters-and-strings.html 创建字符向量 通过将字符序列括在单引号中来创建一个字符向量。 chr = 'Hello, world' chr = 'Hello, world' 字符向量为 char 类型的...
  • Java中字符串indexof() 的使用方法

    万次阅读 多人点赞 2016-07-05 15:48:34
    Java中字符串中子串的查找共有四种方法(indexof()) indexOf 方法返回一个整数值,指出 String 对象内子字符串的开始位置。如果没有找到子字符串,则返回-1。 如果 startindex 是负数,则 startindex 被当作零。如果...
  • 属性:字符串类型的名字name,字符类型的性别gender,和整型的序号number; 方法: showMe,以“name-gender-number”格式输出Person对象的属性值。如果性别由字符M表示,则gender显示male;如果性别由字符F表示...
  • 【多选题】下列运算符的使用正确的有哪些( )【多选题】以下选项中,不符合 Python 语言变量命名规则的有( )【单选题】以下程序的输出结果是________ s = "python 编程 很 容易 学" print(len(s))【多选题】...
  • 前言: 在写一个按钮切换效果时,遇到了一个数据类型问题。我打算的是通过属性判断按钮是否被选中,设置其属性为true和false,但是奇怪的发现,当属性为空,切换到true,在切换到false,之后一直就为... 读出字符串...
  • 检测字符串编码类型

    千次阅读 2016-11-17 15:10:15
    当在php中使用mb_detect_encoding函数进行编码识别时,很多人都碰到过识别编码有误的问题,例如对与GB2312和UTF- 8,或者UTF-8和GBK(这里主要是对于cp936的判断),网上说是由于字符短是,mb_detect_encoding会出现...
  • 统计字符串中各类字符的个数

    千次阅读 2020-06-08 22:19:54
    统计字符串中各类字符的个数 ...字符串处理是C语言中很重要的一个知识点,但在C语言汇总并没有字符串类型,因此,只能采用字符数组或者字符指针的形式来使用字符串。要记住一点,不论我们使用的是字符串常量还是字...
  • 判断字符串编码类型

    千次阅读 2017-07-12 23:36:09
    public static String getEncoding(String str) { String encode = "GBK"; try { if (str.equals(new String(str.getBytes(encode), encode))) { return encode; } } catch (Exception except
  • C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。字符串常量适用于那些对它不做修改的字符串函数. 一、求字符串长度 strlen size_t strlen...
  • python整数、字符串、字节串

    万次阅读 2019-08-23 10:38:49
    python整数、字符串、字节串 文章目录python整数、字符串、字节串一、整数、字符串、字节串之间的相互转换1.进制转换2.字符to整数3.字节串to整数4.整数to字节串5.整数to字符串6.字符串to字节串7.字节串to字符串二、 ...
  • 字符、字符串、常用类型转换简介

    千次阅读 2008-04-02 18:03:00
    本文先介绍字符的编码方式、各种基本字符串类型,然后说明相关的帮助类,如CComBSTR、_bstr_t、CString和basic_string等,最后讨论在它们之间以及和其他的数据类型的转换方法。 2 ANSI、MBCS与UNI
  • 字符串算法题

    千次阅读 2018-09-27 14:39:57
    1.剑指offer:请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 这里我提供了两种方法:①常规方法;②利用 API 解决。 public ...
  • 字符串 常见类型转换[转]

    千次阅读 2011-06-07 17:17:00
    C++字符串完全指引之一 —— Win32 字符编码:CodeProject:The Complete Guide to C++ Strings, Part IC++字符串完全指引之二 —— 字符串封装类:CodeProject:The Complete Guide to C++ Strings, Part IICString...
  • 十六进制字符串与数值类型之间转换(C# 编程指南 以下示例演示如何执行下列任务: 获取字符串中每个字符的十六进制值。 获取与十六进制字符串中的每个值对应的字符。 将十六进制 string 转换为...
  • 字符串,字符和字节

    千次阅读 2013-11-23 17:39:48
    1. 字符串长度 strlen用于计算字符串的长度,但不包含结束符 NUL size_t strlen(char const *string);  strlen 返回一个类型为 size_t 的值,这个类型在头文件 stddef.h 中定义,是一个无符号整数类型。 2. 复制...
  • 当我们需要对字符串进行动态修改时,这时String的功能就会受到限制,而StringBuffer类可以完成字符串的动态添加、插入和替换等操作。 StringBuffer:线程程安全的可变和可写的字符序列。(注:线程安全在银行的网站,...
  • c++之字符串

    千次阅读 2018-02-08 17:39:04
    C++ 字符串C++ 提供了以下两种类型字符串表示形式:C 风格字符串C++ 引入的 string 类类型C 风格字符串C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持。字符串实际上是使用 null 字符 '\0' 终止的一...
  • MySQL支持大量的列类型,它可以被分为3类:数字类型、日期和时间类型以及字符串(字符)类型。本节首先给出可用类型的一个概述,并且总结每个列类型的存储需求,然后提供每个类中的类型性质的更详细的描述。概述有意...
  • Python 课课练 (五):字符串课后练习题

    千次阅读 多人点赞 2021-03-22 17:59:25
    (1) 下列关于字符串的分割说法正确的是()。 A. 分割是将字符串分割成任意序列 B. 指定了 split() 方法的最大分割次数,就必须分割这么多次 C. 在使用 split() 方法进行分割字符串时,如果不指定分隔符,就不能指定...
  • C++基础知识篇:C++ 字符串

    千次阅读 2020-12-17 22:36:24
    C++ 提供了以下两种类型字符串表示形式: C 风格字符串 C++ 引入的 string 类类型 C 风格字符串 C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持。字符串实际上是使用null字符 '\0' 终止的一维字符数组...
  • 字符串:str() 整数:int() 浮点数:float() 二、字符串 穿上单引号、双引号、三引号黄袍的内容就是字符串,无论引号里面内容是中文、英文、法文、数字、符号、甚至是火星文。 movie = '美国队长2' name = 'The ...
  • 如题,有下列字符串: user = "{'name' : 'jim', 'sex' : 'male', 'age': 18}" 可以用eval()或exec()函数实现: >>> user "{'name' : 'jim', 'sex' : 'male', 'age': 18}" >>> b=eval(user) ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 161,324
精华内容 64,529
关键字:

下列是字符串类型的是