您的位置 首页 php

Delphi基础教程图文版之字符串详解

8c1dbf93c37b465ca22dd7f982b03efe

Delphi中的字符一直处于懵懵懂懂的状态,不同于我接触到的其它编程语言在Delphi中居然有好几种字符串,今天好好研究一番!!

Delphi中字符串的操作很简单,但幕后情况却相当复杂。Pascal传统的字符串操作方法与Windows不同,Windows吸取了C语言的字符串操作方法。

32位Delphi中增加了长字符串类型,该类型功能强大,是Delphi缺省的字符串类型。

传统的字符串类型是一个字符序列,序列的头部是一个长度字节,指示当前字符串的长度。由于只用一个字节来表示字符串的长度,所以字符串不能超过255个字符。

这一长度限制为字符串操作带来不便,因为每个字符串必须定长(确省最大值为255),当然你也可以声明更短的字符串以节约存储空间。 为克服传统Pascal字符串的局限性,32位Delphi增加了对长字符串的支持。这样共有三种字符串类型:

ShortString

短字符串类型也就是前面所述的传统Pascal字符串类型。短字符串中的每个字符都属于 AnsiChar类型(标准字符类型)

 var  S: ShortString;   { 255个字符长度,256个字节}  S1: String[255];  { S1和S的字符类型一样}  Len: Integer;begin  S := 'Hello';  Len := Ord(S[0]); { Len现在包含S的长度为5,Ord函数可以把一个字符类型转换为整数类型}  Len := SizeOf(S); { Len现在包含的是ShortString类型的大小,为256字节} end;  

以上例子通过S[0]可以获得S的字符串长度,当然也可以用Length函数来确定一个短字符串的长度。

可以通过数组的下标来访问ShortString中的一个特定位置的字符,具体使用参看下面例子和注释说明:

 var  S: string[8];  i: Integer;begin  S := 'a_pretty_darn_long_string';  { 因为S只有8个字符大小,因此s的实际存储的内容为"a_pretty"}  i := 10;  S[i] := 's';  { 因为S只有8个字符大小,试图改写第10个元素,将会使内存混乱}end;  

AnsiString

这种类型也有人称为长字符串类型(LongString)同时也是Delphi默认的字符串类型,它是一种动态分配的字符串,其大小只受可用内存的限制。声明一个长字符串,只需要用关键字String不加大小参数即可。据说使用了更新前拷贝(copy–on-write)技术。恕我才疏学浅没研究过这个东西。这类字符串长度没有限制(可以存储多达20亿个字符),其字符类型也是AnsiChar类型。

由于是动态分配的,一次可以随意修改字符串,而不用担心对其他的影响,也不用担心越界的问题。String类型没有0元素,试图存取String类型的0元素会产生一个编译错误。

之前在万一老师的博客中看到了以下的代码不太理解,现在可以完全解释为什么我们试图将一个string类型的变量直接赋值给字符数组时报错了

 //字符串 < > 字符数组,注意这里说的字符串仅仅是长字符串var  arr: array[0..5] of Char;  str: string;begin  {可以把字符串常量直接赋给字符数组; 但超界不行}  arr := 'Delphi';  ShowMessage(arr); {Delphi}  {可以把字符数组直接赋给字符串变量}  str := arr;  ShowMessage(str); {Delphi}  {其实字符串内部也是包含了一个字符数组, 所以能索引访问, 不过它的索引起始于 1}  ShowMessage(str[1]); {D}  ShowMessage(arr[0]); {D}  {但不能把一个字符串变量赋给字符数组}  //arr := str;     {错误; 这需要用其他手段实现, 譬如复制或移动内存}end;  

WideString

长字符串类型与AnsiString 类型相似,只是它基于WideChar字符类型,WideChar字符为双字节Unicode字符。

 var  S: string;  { 在Delphi 7中默认string等同于AnsiString}  WS: WideString;begin  S := '世界你好';  WS := S;  ShowMessage(S[1]);  { 此时无任何显示,因为S[1]取出的是‘世’的一半}  ShowMessage(WS[1]); { 显示‘世’}end;  

不过WideString和AnsiString的不同主要在三个方面:

  • WideString由WideChar字符组成,而不是由AnsiChar字符组成的,它们跟Unicode字符串兼容。
  • WideString用SysAllocStrLen()API函数进行分配,它们跟OLE的BSTR字符串相兼容。
  • WideString没有引用计数,所以将一个WideString字符串赋值给另一个WideString字符串时,就需要从内存中的一个位置复制到另一个位置。这使得WideString在速度和内存的利用上不如AnsiString有 效。

Ansi和Unicode

字符编码:为了区分一个字符到底使用了几个字节,就不能将字符的编号直接存储到计算机中,字符编号在存储之前必须要经过转换,在读取时还要再逆向转换一次,这套转换方案就叫做字符编码。 它规定了如何将字符的编号存储到计算机中

字符集:为每个字符分配了唯一的编号。可以将字符集理解成一个很大的表格,它列出了所有字符和二进制的对应关系,计算机显示文字或者存储文字,就是一个查表的过程。 它定义了字符和二进制的对应关系

ASCII(American Standard Code for Information Interchange,美国信息交换标准码),它使用7 bits来表示一个字符,总共表示128个字符,后来IBM公司在此基础上进行了扩展,用8bit来表示一个字符,总共可以表示256个字符

ANSI(American National Standard Institite)美国国家标准学会(美国的一个非营利组织),首先ANSI编码是一种对ASCII码的拓展,它不是指的一种特定的编码,而是不同地区扩展编码方式的统称,各个国家和地区所独立制定的兼容ASCII但互相不兼容的字符编码,微软统称为ANSI编码

Unicode 是一套字符集,而不是一套字符编码。它固定使用16 bits(两个字节)来表示一个字符,共可以表示65536个字符。标准的Unicode称为UTF-16。后来为了双字节的Unicode能够在现存的处理单字节的系统上正确传输,出现了UTF-8

个人理解:ANSI是每个国家根据自己的语言在ASCII基础扩展的一些编码。为了实现大一统出现了Unicode,而Unicode为了兼容以前的字符出现了双字节(UTF-16)和单字节(UTF-8)之分

PChar和字符数组

在第二季的视频中我曾经对端口号做过一次转换 sin_addr.S_addr := inet_addr(PAnsiChar(AnsiString(EditAddr.Text))); 这段代码,一个将字符串转成PAnsiChar的一个场景,这是个什么玩意儿?其实这样做纯粹是为了兼容winAPI中的数据类型

在C和C++中没有真正的字符串数据类型,都是通过以Null结尾(0)的字符数组来实现的,字符数组没有长度字节,因此只能通过结尾的Null标志来作为字符串的字符结束标志。又因为Windows是用C编写的,很多Windows函数要用到以字符数组作为参数,但Pascal字符串类型不是字符数组,因为为了让Pascal字符串也能与Windows兼容,就需要一个字符串数组,PChar类型正是符合这种需求,在任何需要字符数组的地方都可用PChar。相应的也有PAnsiChar和PWideChar,分别对应于AnsiChar字符和WideChar字符。

其实最初我也被字符串折腾的不行不行的,所以整理这篇文章

文章来源:智云一二三科技

文章标题:Delphi基础教程图文版之字符串详解

文章地址:https://www.zhihuclub.com/43332.shtml

关于作者: 智云科技

热门文章

网站地图