aardio 文档

字符串与编码

基础知识

字符串

计算机以八个二进制位表示一个字节 - 这称为一个单字节字符。

一组连续的字节就构成一个字符串,在 aardio 中字符串是基于二进制的,可以包含任何数据(例如图像、文本、或者'\0'等不可打印字符)。

字符串本质上是字节构成的数组,但这个数组是只读的,每次对字符串做替换、连接等操作都会生成新的字符串,每个字符串指向的内存不应该被直接修改。

下面的代码定义了一个最基本的字符串:

var str ="C:\Documents and Settings\admin\Desktop\string.aardio" 

要注意在 aardio 中双引号包含的是原始字符串,不处理转义符,不需要将 "\" 写为 "\\"。只有用单引号包含的字符串才会处理转义符,在 aardio 里 '\\' 等价于 "\"

可以用 #str 获取字符串 str 占用的内存字节长度。

也可以使用下标获取字符串中每个字节的字节码数值, 例如 str[1] 取出第一个字节的数值是 67, 内存中的 67 在文本中显示出来的就是字符"C" - 这是 ASCII 编码规定的。

文本编码

字符串的一个字节只有 8 个二进制位,那它能表示的字符就很有限,所以就有了很多不同的编码规则用多个字节来表示更多的字符。例如 GBK,UTF-8 等多字节字符集,这些字符集通常会用小于 0x80 的单字节表示 ASCII 字符(英文字母数字这些), GBK 用双字节表示汉字(首字符大于0x80),而 UTF8 用两个以上的字节表示宽字符(多字节的所有字节大于 0x7F )。 要注意 UTF8 是变长编码的,理论上一个字符可以是1,2,3,4 .....个字节。

GBK 编码的第二个字节还是会与 ASCII 冲突,如果不从头重新计算就容易混淆某个字节到底是归属哪个字符,这导致容易出现串码问题。 而 UTF8 的多字节字符中的所有字节码总是会大于0x7F,首字符的前两个二进制位总是 1 ,而附加字节的前两个 二进制位总是10,这就让我们处理文本非常方便,也不会出现GBK 那样的串码问题。例如 HTML,JSON 这些格式化文本的分隔标记通常都是字节码小于 0x7F 的 ASCII 字符,在 UTF-8 编码的文本中就不会与其他多字节字符发生混淆,非常方便。

不同的编码还存在不同的系统环境不兼容的问题,例如 GBK 的软件在繁体系统上就会乱码。而 Unicode 通用编码可以避免这一问题,Unicode 编码有多种方案,主要被采用的则是UTF-8,UTF-16。

aardio 源代码与字符串的默认编码是 UTF-8 编码。而 Windows 系统 API 函数的 Unicode 函数使用的是 UTF-16 编码, aardio 在调用这些 UTF-16 编码的系统 API 时支持自动切换编码,这让我们可以大幅简化了调用代码,请参考 UTF-16 API

实际上 UTF-8 已经成了最流行的编码方案,很多编程语言默认使用 UTF-8 编码,或更改为使用 UTF-8 编码。而且我们处理的文本或者格式化文本通常也是 UTF-8 编码,最常见的例如 JSON 就使用 UTF-8 编码。

aardio 字符串虽然默认使用 UTF-8 编码,但是也支持 UTF-16 编码的字符串,实际上可以在 aardio 字符串里存放任何二进制数据。

字符串的 UTF 编码标记

aardio 的每个字符串都拥有一个 UTF 标记,用于标记该字符串使用的文本编码。

可以使用 string.getUtf() , string.setUtf() 函数获取或修改UTF标记。但尽量不要去使用这些函数,应当让 aardio 自动维护字符串的 UTF 标记,用户在编写程序中一般不应去获取或修改 UTF 标记。

UTF 标记是按位设置的,规则如下:

空字符串忽略 UTF 标记。
非空字符串只能在创建 UTF-16 字符串时自动将 UTF 标记设为 UTF-16,不允许在运行时直接调用 string.setUtf() 设置字符串的 UTF 标记为 UTF-16。

UTF 编记的作用是优化自动编码转换的效率。例如我们在调用 Unicode(UTF-16) 版本的原生 API 函数时 aardio 会自动将 UTF-8 编码的文本转换为 UTF-16 编码,通过 UTF 标记 aardio 就可以避免重复转换与错误转换。

ardio 只要在能确认一个字符串的编码格式时才会对字符串设置 UTF 标记。例如直接写在 aardio
源码中的字符串字面值会自动设置适合的 UTF 标记。在调用 string.fromto(), string.fromUtf16(), string.toUtf16() 这些编码转换的函数成功以后,返回字符串也会自动更新 UTF 标记。甚至是使用 string.len 这些拥有检测编码功能的函数也会自动设置字符串的 UTF 标记。

UTF 标记是 aardio 对字符串的一种特殊优化机制,因为有这种特殊的机制,aardio 才能自由地兼容不同的编码,避免了大部分的编码转换操作。

但我们应当让 aardio 自动去处理 UTF 标记。在编程时应当明确地使用编码转换、处理、识别函数,而不是试图去控制 UTF 标记,这很复杂也完全没有必要。

aardio 字符串分类介绍

一、原始字符串( raw string literals ) #

在 aardio 中使用双引号( " )或反引号( ` )包含原始字符串。

原始字符串不处理转义符,在原始字符串中单个反斜杆 "\" 表示的就是字面值,不需要用双反斜杆表示单个反斜杆。

双引号中的原始字符串可以用两个双引号表示双引号自身。反引号中的原始字符串可以用两个反引号表示反引号自身。

原始字符串可以包含换行。无论原始字符串的换行是'\r''\n' 还是 '\r\n',换行总是会被规范化为 '\n'

例如:

var strPath ="C:\Documents and Settings\admin\Desktop\string.aardio" 
var strLine ="第一行
第二行"

原始字符串使用 UTF-8 编码,字符串的 UTF 标记也自动设为 UTF-8 编码。

二、转义字符串( escaped string literals ) #

转义字符串放在单引号中,支持 \ 转义符,转义规则与 C 语言类似。

在单引号中的字符串可以换行书写,但是 aardio 会忽略所有的回车换行,只能用 '\r' 表示回车符,'\n' 表示换行符。

单引号中可用的转义符列表如下:

转义符 说明
\\ 表示普通\字符
\ddd 用一到三个数字组成十进制数值表示一个字符 ,
如果只想表示'\0',并且后面有其他不相关的数字,
可以在\0后面加一个换行,例如 str ='\0
86'
\xFF \x 后面的两位十六进制表示一个字符
\uFFFF \u 后面的4位十六进制表示一个 Unicode 字符,
可使用一对代理字符表示 Unicode 编码大于 0x10000 的4字节字符,例如:'\uD86E\uDC1C'
注意普通字符串里默认会解析为UTF-8编码的多字节字符,
而在 UTF-16 字符串(ustring)中解析为 UTF-16 编码的字符。
\UFFFFFFFF \U大写时,
可在其后跟随8. 6. 4 个十六进制字符表表示一个 Unicode 字符,为避免歧义,应当总是使用 8 个 16 进制字符(不足在前面补 0)。

支持Unicode编码大于 0x10000 的字符。

注意普通字符串里默认会解析为UTF-8编码的多字节字符,例如'\U0002b81c'
而在 UTF-16 字符串(ustring)中解析为 UTF-16 编码的字符,例如'\U0002b81c'u
\a 响铃符,常用于发出警告声,例如 console.log('\a')
\b 退格
\f 换页
\e ESC 码。等价于 \x1b
\r 回车
\n 换行
\r\n 回车换行
\t 制表符(横向跳格)
\v 匹配一个垂直制表符。等价于 \x0b
\" 双引号
\' 单引号
\[ 方括号[
\] 方括号]

示例:

import console;

// 字符串中也可以直接用十六进制表示字符,例:
console.log('Hel\x6c\x6f world\x21'); //换行被忽略

//字符串也可以直用三位十进制数表示字符,例:
console.logPause('Hel\108\111 world\33') 

如果单引号内的普通字符串未使用除 '\u' 或 '\U' 以外的转义符,则会自动设置 UTF 标记为 UTF-8 编码。

示例:

var utf8str = 'UTF-8 字符串'

如果单引号包含的字符串后面有一个小写的 u 则创建 UTF-16 编码的字符串( 在 aardio 中简称 ustring )。 #

示例:

//下面是一个 UTF-16 LE 编码字符串,代码页:1200
var ustr = 'UTF-16 字符串,简称 ustring,'u  

UTF-16 字符串(ustring)用下标取字节或用下接下标取字符时,返回的是用双字节表示的 16 位宽字节或宽字节码(索引按字符计数),例如

import console; 

var ustr ='中文abc'u;
for(i=1;#ustr/2;1){
    console.log( ustr[i] ) //宽字节码
    console.log( ustr[[i]] ) //宽字节字符
}

console.pause(true);

如果单引号中仅包含一个字符、并且后面附加 # 号后缀、则表示该字符的字节码数值。

示例:

import console;

//单引号仅包含一个字符,并在后面加# 号表示取字节的字节码数值
console.logPause( 'A'# ) //显示65

三、包含字符串

在包含文件路径的原始字符串前面加上 $ 操作符,就可以在编译时嵌入该文件的二进制数据并返回一个字符串对象。

例如:

var str = $"/test/test.jpg"

在 aardio 程序编译发布以后,该文件就会直接被编译到 aardio 代码中,不再需要原来的文件也可以运行。

四、注释字符串 #

在 aardio 的赋值语句中,可以注释作为一个字符串组成赋值语句。
因为 aardio 中行注释可以自定义注释标记里的星号数目 - 只要首尾匹配就可以。这样就可以方便地表示复杂的字符串,而不用担心所包含的字符串里可能出现字符串的结束标记。

注释字符串的作用与原始字符串类似不处理转义符,并且 aardio 也会将注释字符串的 UTF 标记设为 UTF8 编码。

块注释保证将换行解释为'\r\n',并且忽略首尾紧邻星号的第一个空行(如果有的话),而单行注释保证字符串没有回车符('\r')或换行符('\n')。

请参考:回车换行符

示例:

var str = //表示原始单行字符串,到行尾结束;

var str2 = /* 

表示原始多行字符串,首尾的*字符可以有一或多个,但*字符的数目必须首尾匹配
*/

Markdown 格式