【程序设计】7.1 [字与时] 字符串

 

7.1 字符串

到现在这止,我们在程序中处理过的数据,除了 output 时有个少量文字外,都是数值或数值构成的序列。其实,计算机还能方便地处理文字,在程序语言中,我们把这些文字称为字符串,或简称字串,字符串是不同于整数、浮点数的另一种数据类型。

在 SPL 中,直接在格子写上文字,如果不能被识别其它有意义的数据类型或者语句,就会缺省地认为是字符串常数。在表达式中,也可以用双引号把文字括起来表示字符串常数。


A

B

1

集算器

SPL

2

="集算器 "

="SPL"

3

3+5

="3+5"

4

=3*4

'=3*4

5

2020-1-1

'2020-1-1

6

for 10

'for 10

A1 就是字符串常数 "集算器",A2 是个正常的计算格,其计算结果也是 "集算器",和 A1 相同;同理,B1、B2 的格值都是 "SPL";A3 是数字开头,但并不能解释成数值,所以也是字符串,和 B3 一样都是 "3+5"。

A4 是个能计算出数值的计算格,就不是字符串了。希望写一个以 = 开头的字符串常数要在格子前面加写一个单引号’,这个多写的单引号不算字符串的一部分,A4 的格值为 "=3*4"。注意只要有一个单引号,不要在右边再写一个括起来,如果写了,右边的单引号也会被认为是这个字符串的一个字符。

类似地,A5 会被识别的日期常数,也就不是字符串,而希望产生一个这样的字符串,也需要用单引号开头;同样,A6 是一个合法语句,不会被识别成字符串,而希望获得这样的字符串常数,也需要用单引号开头。

字符串也是数据类型,也可以运算,它最常见的运算就是连结,即把两个字符串接起来形成一个更长的字符串。


A

B

1

集算器


2

=A1+"2020"

集算器 2020

3

=A1+2020

2020

4

=A1+string(2020)

集算器 2020

5

=A1/2020

集算器 2020

6

=A1/"2020"

集算器 2020

使用 + 号即可把两个字符串相连(A2);但要注意的是,字符串和数值相加却会忽略字符串部分(A3)这是 SPL 的特殊约定,其它大多数程序语言不是这么约定的,而是要么会报错,要么会把数值转换成字符串再连结。把数值用 string 函数转换成字符串就可以和其它字符串正常连结了(A4),如果用斜杠 / 来连结字符串和数值时,则会自动把数值转换成字符串(A5)。而 / 也可以直接拼接两个字符串(A6)。

现在,我们可以利用字符串改造分解质因数的代码,把分解结果显示成完整的表达式。


A

B

C

1

7215

=2

=string(A1)+"=1"

2

for A1>1

if A1%B1==0

>C1=C1+"*"+string(B1)

3



>A1=A1\B1

4



next

5


>B1+=1


这段程序执行完之后,C1 格会得到一个字符串:7215=1*3*5*13*37,把分解质因数的结果写出来了。仔细理解程序的执行过程,可以想像出它是如何一步步被拼出来的。

有连接就有拆分,SPL 还提供这样几个函数:


A

B

1

集算器 2020


2

=len(A1)

'7

3

=left(A1,2)

'集算

4

=right(A1,3)

'020

5

=mid(A1,3,2)

'器 2

6

=A2.(mid(A1,~,1))

["集 "," 算 "," 器 ","2","0","2","0"]

len 函数返回构成字符串的字符的个数,也称为字符串的长度,注意这个 len 函数和取序列长度的函数名字相同,但写法不一样,这里要把字符串当成参数,而不能写成 A1.len() 的样子。还要注意的是,SPL 采用了 unicode 编码方式,汉字和数字(或英文字母)都只算一个字符,有些早期程序语言中,汉字会算成两个字符。

A3、A4、A5 的 left,right 和 mid 函数将从字符串取出一部分构成一个新字符串返回,函数名称已经反映要取出的部位,再观察运行结果,很容易理解其参数的意义,这里就不细说了。几乎所有的能处理字符串的程序语言都有这几个函数,且命名和参数规则都一样。

A6 用循环函数把一个字符串拆成一个个字符构成的序列,可以再理解 mid 函数。单个字符也是个字符串,就是个长度为 1 的字符串。

分解质因数出来的结果,前面总是会写个 1*,这是因为我们在循环中每次在结果字符串上接续一个 * 和一个因数,如果不写前面的 1,就会出现 7215=*3*5*13*37 的结果,这就不对了。

但无论如何,这个 1* 有点多余,有什么办法呢?

用拆串的办法就可以解决它。


A

B

C

1

7215

=2

=string(A1)+"="

2

for A1>1

if A1%B1==0

>C1=C1+if(right(C1,1)=="=","","*")/B1

3



>A1=A1\B1

4



next

5


>B1+=1


在拼接因数时判断一下当前串是不是 = 结尾的,如果是说明现在是第一个因子,就不要再拼接 * 号了,否则就拼上。现在就可以得到我们希望的结果 7215=3*5*13*37 了。

也可以事后再做,把多余的 1* 部分去掉:


A

B

C

1

7215

=2

=string(A1)+"=1"

2

for A1>1

if A1%B1==0

>C1=C1+"*"+string(B1)

3



>A1=A1\B1

4



next

5


>B1+=1


6

=pos(C1,"=1*")

>C1=left(C1,A6+1)+mid(C1,A6+3)

我们又碰到一个函数 pos,它将在一个字符串中寻找另一个字符串,后者称为子串,找到子串后将返回位置,也就是原串的第几个字符开始会是这个子串,如果找不到就会返回 null,这和序列的 pos 函数很像,不过它也要把字符串当参数写而不能用对象式的写法。

我们确定地知道现在算出来的结果字符串中一定会有 "=1*" 这个子串(前面加了 = 之后就只会有 1 个了,否则可能有个中间的质因数以 1 结尾时,但 pos 只找第 1 个其实也不会错,但这里严谨一点),找到它的位置后,再用拆串和拼串的办法把其中的 1* 部分去除就可以了。

还可以更简单粗暴地用 replace 函数直接替换掉:=replace(C1,“=1*”,“=”)。同样地,要把 =1* 替换成 =,而不能把 1* 替换成空串。

SPL 提供了很多字符串处理函数,这里不一一列举了,需要时可以查帮助资料。

我们刚才使用了 == 来比较字符串,当然也可以用!=,那么 >、< 这些对字符串有意义吗?

也是有的。

计算机本质上只能处理数值,处理字符时也要把字符用数值表示,这就是编码方式。前面我们说过,SPL 采用的编码方式叫 unicode。

既然是数值,那就可以比大小,字符串比大小时就是用字符的编码来比较。比较规则和序列很像,就是两者的第 1 个字符先对比,如果不同,那大的就大了,如果相同再比第 2 个,…,直到不同或者其中一个不够长了。其实,这才是字典次序这个名词的真正来源。

那么,我们怎么知道两个字符谁大谁小呢?比如 "1" 和 "2" 那个大?"1" 和 "A" 呢?

简单来说,我们写句代码比一下就知道了。但是,全凭死记硬背就太累了,我们来看看这些编码有没什么规律可言,SPL 提供了 asc 函数来返回字符的编码。


A

B

1

=asc("0")

=9.(asc(string(~)))

2

=asc("A")

=asc("C")

3

=asc("a")

=asc("z")

4

=asc("集 ")

=asc("算 ")

我们不再一个个格子解释了,请读者自行执行这些代码看结果,这里我们直接把编码规律写出来:

1) “0”-"9" 的编码是连续的,从 48 到 57;

2) “A”-"Z" 的编码是连续的,从 65 到 90;

3) “a”-"z" 的编码是连续的,从 97 到 112;

4) 汉字的编码比较复杂,看不出明确的规律。

这套编码标准当初叫 ASCII 码,unicode 在是 ASCII 基础上扩展出来的,所以这个函数也叫 asc。

和 asc 函数相反的,SPL 还有个 char 函数,可以把编码转换成字符。

我们可以利用 char 函数以及刚才发现的规律来写一个函数:给两个整数 r 和 c,计算 Excel 中第 r 行第 c 列的格子叫什么名字。


A

B

C

D

1

>r=2,c=123

2

>rc=""

=1

=26


3

for c>C2

>c-=C2

>C2*=26

>B2+=1

4

>c-=1




5

for B2

>rc=char(65+c%26)+rc

>c\=26


6

return rc/r

计算格名主要麻烦在列,先计算出需要几个字母(B1),再计算出列对应的字母串。

反过来,用 asc 函数可以从格名 rc 反算出行号和列号:


A

B

C

D

1

>rc="PG45"


2

=len(rc).(upper(mid(rc,~,1)))


3

>r=c=0

=-1

=1


4

for A2

if A4>="A"

>c=c*26+asc(A4)-65


5



>B3+=C3

>C3*=26

6


else

>r=r*10+asc(A4)-48


7

return [r,c+B3+1]

upper 函数用于把字母变成大写。

Excel 格名的规则看起来简单,但要想出正确的计算逻辑也不容易,还是那个话,程序代码不会让帮我们解决问题,只会帮我们实现解法。

【程序设计】 前言及目录

【程序设计】6.3 [重复用] 可复用脚本

【程序设计】7.2 [字与时] 拆分合并