# string.builder 库模块帮助文档

<details>  <summary>使用说明</summary>  <p>
string.builder 对象基于 raw.realloc 分配的内存动态指针，
在需要动态修改内存、改变内存大小时可以提供更好的性能。

string.builder 提供 pointer 方法可以临时提取内部指针，
在 API 函数参数中 string.builder 对象也可以自动转换为指针。
通过指针操作通常可以提供更好的性能，aardio 中有很多函数可以直接支持指针参数。
例如文件对象的 readBuffer,writeBuffer 函数除了可以指定 buffer 参数，也可以指定指针参数。
使用指针可以避免不必要的内存复制，提供更好的性能。
但指针功能属于高级功能，需要非常谨慎。

与字符串、buffer 的对比：
1. 字符串是只读的，buffer 与 string.builder 都是可读写的。
2. buffer 是定长的，内部指针不会改变，
但 string.builder 可以改变长度，存储的内部动态指针可能会变更（指向新的内存地址）。
3. 字符串、buffer、string.builder 都会自动回收内存。

string.builder 对象支持用单索引读写字节码，
1 为起始索引，负整数表示自尾部倒计数的索引（-1 表示最后一个字节），索引超出范围时忽略操作或返回 null 。

> 注意 只有 string.build 对象的下标操作符内可以使用负数索引访问指定位置的字节码，
> string,buffer类型的下标操作符内都不支持这种负索引

string.builder 也支持使用多项索引读写指定范围的数据，读取时返回字符串，可写入的类型有字符串、buffer、结构体。
例如 `stringBuilder[2,4] = "写入数据" //第一个索引不要加负号`

注意在 aardio 中多项索引的第一个索引如果包含操作符（例如负号）要写为空格分格的双层中括号，
例如 `stringBuilder[ [-4,-2] ] = "写入数据" //可用以负数表示自右侧倒计数位置`
这是因为多项索引实际是纯数组的一个语法糖，但如果第一个索引出现操作符 aardio 会将其视为单项索引。

string.builder 在使用下标读写单字节码时效率不及字符串、字节串等基础类型。
但使用多项索引读写片段使用原生内存指针操作，效率与操作字节串差不多。

string.builder 传入原生 API 参数或 raw.toPointer 时可自动转换为指针。
但触发 string.builder 对象修改长度的操作有可能会改变对象内部存储的指针地址，
因此不可存储其指针值，在 string.builder 修改内容或大小后不可再使用之前获得的指针。
</p></details>

## string 成员列表 <a id="string" href="#string">&#x23;</a>

### string.builder() <a id="string.builder" href="#string.builder">&#x23;</a>
创建字符串生成器，不允许跨线程传递此对象。  
可选在参数中指定预分配内存大小。  
生成器对象可使用 `+` 或 `++` 操作符连接字符串、buffer、结构体,或使用`[]`操作符取字节码,  
此对象可用于拼接字符串，并自动调整内存大小,  

在大字符串频繁拼接时可明显提升速度，  
小字符串少量拼接不需要使用此对象  

[返回对象:StringBuilderObject](#StringBuilderObject)

## string.builder 成员列表 <a id="string.builder" href="#string.builder">&#x23;</a>

字符串生成器。  
创建的对象内部使用动态指针，并负责自动释放动态指针。  
此对象适合用于读写需要原地修改内存、频繁调整内存大小的字节序列。  
与 buffer 不同的是 string.builder 是长度可变的。  
与字符串不同的是 string.builder 是可写可原地修改的。  

string.builder 对象可用相关成员函数或 tostring 转换为字符串，  
也可以在原生 API 或 raw.toPointer 函数中自动转换为普通指针。  

要切记任何可能导致自动调整内存大小的操作都有可能改变内部的动态指针地址，  
因此不可记录获得的指针值，总是通过 string.builder 对象自动获取最新指针值。

### string.builder.is() <a id="string.builder.is" href="#string.builder.is">&#x23;</a>
参数 @1 是否 string.builder 对象。

## ::Msvcrt 成员列表 <a id="::Msvcrt" href="#::Msvcrt">&#x23;</a>

### ::Msvcrt.* <a id="::Msvcrt.any" href="#::Msvcrt.any">&#x23;</a>
可不用声明直接在此输入函数名并调用 AP I函数  

一、传入参数规则：  
1、null参数不可省略  
2、32位整数类型，小于32位的整数、以及枚举类型都可以直接在API参数中写数值。  
3、对于任何数值类型的指针（输出参数）一律使用结构体表示，例如double * v 表示为{ double v }  
4、数组使用结构体表示  
5、所有结构体传给API的都是指针地址，都是输出参数并增加返回值  

二、返回值规则：  
1、返回值默认为int类型,可用 >>> 0 强制转为无符号数,  
2、可以使用[API尾标]改变返回值为其他类型  

三、所有可用的【API尾标】:  
::User32.ApiNameW() 切换到Unicode版本，字符串UTF8-UTF16双向转换  
::User32.ApiNameA() 切换到ANSI版本,字符串不作任何转换  
::User32.ApiNameL() 返回值为64位LONG类型  
::User32.ApiNameP() 返回值为指针类型  
::User32.ApiNameD() 返回值为double浮点数  
::User32.ApiNameF() 返回值为float浮点数  
::User32.ApiNameB() 返回值为C++中的8位bool类型  
注意【尾标】前必须是小写字母

### ::Msvcrt.api("字符串参数","void()" ) <a id="::Msvcrt.api("字符串参数","void" href="#::Msvcrt.api("字符串参数","void">&#x23;</a>
声明Kernel32 API函数

### ::Msvcrt.gethandle() <a id="::Msvcrt.gethandle" href="#::Msvcrt.gethandle">&#x23;</a>
返回句柄

## StringBuilderObject 成员列表 <a id="StringBuilderObject" href="#StringBuilderObject">&#x23;</a>

### StringBuilderObject.append(追加数据,追加长度) <a id="StringBuilderObject.append" href="#StringBuilderObject.append">&#x23;</a>
追加数据可以是字符串、buffer、结构体、其他指针。  
如果参数不是指针追加长度可省略。  
此函数可能改变内部动态指针值。

### StringBuilderObject.appendf("C格式化串",...) <a id="StringBuilderObject.appendf" href="#StringBuilderObject.appendf">&#x23;</a>
在尾部写入使用 C 函数 snprintf 格式化所有参数得到的字符串。  
参数 @1 支持的格式化语法与 snprintf 相同。  

此函数可能改变内部动态指针值

### StringBuilderObject.assign() <a id="StringBuilderObject.assign" href="#StringBuilderObject.assign">&#x23;</a>
重置初始值  
参数可以是字符串，buffer，或结构体  
此函数可能改变内部动态指针值

### StringBuilderObject.buffer() <a id="StringBuilderObject.buffer" href="#StringBuilderObject.buffer">&#x23;</a>
转换为 buffer 对象（字节串）。

### StringBuilderObject.capacity() <a id="StringBuilderObject.capacity" href="#StringBuilderObject.capacity">&#x23;</a>
返回预分配内存大小。  
释放指针后此函数返回0

### StringBuilderObject.eachIndexOf(查找内容) <a id="StringBuilderObject.eachIndexOf" href="#StringBuilderObject.eachIndexOf">&#x23;</a>

```aardio
for(i in StringBuilderObject.eachIndexOf(/*查找内容*/)){
	/*迭代变量 i 为当前找到子串的开始索引*/	
}
```

### StringBuilderObject.empty() <a id="StringBuilderObject.empty" href="#StringBuilderObject.empty">&#x23;</a>
存储内容是否为空。

### StringBuilderObject.expand() <a id="StringBuilderObject.expand" href="#StringBuilderObject.expand">&#x23;</a>
增加存储数据大小。  
参数 @1 指定要增加的长度（单位为字节），如果为负数则减少长度。

### StringBuilderObject.find <a id="StringBuilderObject.find" href="#StringBuilderObject.find">&#x23;</a>
查找字符串，用法与 string.find 相同

### StringBuilderObject.find("查找模式串",开始位置) <a id="StringBuilderObject.find" href="#StringBuilderObject.find">&#x23;</a>
使用模式串在字符串中查找子串的位置，  
开始位置为可选参数,默认为1，必须以字节计数，  
函数返回匹配结果的起始,结束位置,以及所有捕获分组  
如果有多个捕获分组,将附加为多个返回值

### StringBuilderObject.free() <a id="StringBuilderObject.free" href="#StringBuilderObject.free">&#x23;</a>
释放内存。  
此函数设置内部动态指针值为null  
释放动态指针以后,仍然可以调用reserve函数重新分配内存

### StringBuilderObject.fromUtf16(转换字符数,目标编码) <a id="StringBuilderObject.fromUtf16" href="#StringBuilderObject.fromUtf16">&#x23;</a>
自UTF16编码转换为多字节编码字符串，默认为 UTF-8。  
参数 @1 以字符计数，即 2 个字节为一个单位,字符数只能为数值，省略时默认值为 -1。  
字符数为 -1 表示查找 ```'\u0000'``` 终止符获取可打印文本长度。

### StringBuilderObject.hex(前缀,忽略字符串) <a id="StringBuilderObject.hex" href="#StringBuilderObject.hex">&#x23;</a>
返回十六进制编码后的字符串，所有参数可省略。  
调用参数将被传递给 string.hex 函数，用法请参考 string.hex 说明。

### StringBuilderObject.indexAny("字符串参数") <a id="StringBuilderObject.indexAny" href="#StringBuilderObject.indexAny">&#x23;</a>
参数用一个字符串指定要查找的单字节字符。  
返回任意字符最初出现的位置,找不到返回值为空

### StringBuilderObject.indexOf(查找内容,查找开始位置) <a id="StringBuilderObject.indexOf" href="#StringBuilderObject.indexOf">&#x23;</a>
普通字符串查找。  
不使用模式匹配语法。

### StringBuilderObject.leftString() <a id="StringBuilderObject.leftString" href="#StringBuilderObject.leftString">&#x23;</a>
从左侧截取参数指定长度的字符串。  
返回字符串对象,参数可用负数表示右侧截取位置  
不会改变内部动态指针值

### StringBuilderObject.match <a id="StringBuilderObject.match" href="#StringBuilderObject.match">&#x23;</a>
匹配字符串，用法与 string.match 相同

### StringBuilderObject.match("查找模式串",开始位置) <a id="StringBuilderObject.match" href="#StringBuilderObject.match">&#x23;</a>
使用模式串在字符串中查找子串。  
参数 @2 可选指定起始位置,负数表示尾部倒计数。  
返回匹配字符串,如果使用了匹配分组则返回多个对应的匹配串。  
返回值的顺序对应模式串中左圆括号的开始顺序

### StringBuilderObject.pack <a id="StringBuilderObject.pack" href="#StringBuilderObject.pack">&#x23;</a>
调用 raw.pack 打包二进制数据并写入当前对象。  
可连续写入，或批量写入二维数组。  
必须提前导入 raw.pack 库。

### StringBuilderObject.pack() <a id="StringBuilderObject.pack" href="#StringBuilderObject.pack">&#x23;</a>
[返回对象:StringBuilderObject](#StringBuilderObject)

### StringBuilderObject.pack(format,...) <a id="StringBuilderObject.pack" href="#StringBuilderObject.pack">&#x23;</a>
参数 @format 指定二进制格式化字符串（格式请参考 raw.pack 库）。  
其他不定个数的参数指定待打包的值，也可以传入包含多个参数的单个数组参数。  
成功返回字节串（ buffer 类型 ），  
失败返回 null,错误信息。  

为了与 Python 的用法保持一致，  
每个打包解包的参数都必须是单个非数组值（数值、字符串、buffer 等）。  
但改用 getStruct 或 getCode 可以得到支持数组的 aardio 结构体声明。  
将结构体作为参数就以用 raw.convert 解包或调用 raw.buffer 或 raw.tostring 打包。

### StringBuilderObject.pack(format,argsArray) <a id="StringBuilderObject.pack" href="#StringBuilderObject.pack">&#x23;</a>
参数 @format 指定二进制格式化字符串（格式请参考 raw.pack 库）。  
参数 @argsArray 指定一个二维数组则批量执行打包操作，每个数组项指定一组打包参数。  
此函数遍历数组并连续调用 pack 方法在当前对象尾部追加打包后的二进制数据。

### StringBuilderObject.pointer(偏移量) <a id="StringBuilderObject.pointer" href="#StringBuilderObject.pointer">&#x23;</a>
获取临时指针（返回值为 pointer 类型）。  
如果对象已被释放则此函数返回 null 值。  
可选在参数中指定偏移量，偏移量自 0 开始（默认值为 0）。  
如果指定负数则表示自尾部倒记数的偏移量，参数为 -1 返回的指针地址指向倒数第 2 个字节。  

要非常谨慎地使用使函数避免内存错误。  
调用 string.builder 任何可改变内存大小的方法都可能导致内存重新分配，  
内存重新分配以后，string.builder 内部存储的动态指针地址就可能发生变化。  
因此 pointer 函数得到的指针地址只能供一次性临时使用，用后应当立即弃用。  

直接将 string.builder 对象传给原生 API 也会自动转换为指针值，但不能更改偏移量。  
直接访问内存指针在一些时候可以大幅优化程序性能，但处理内存指针应当非常谨慎。

### StringBuilderObject.read(readSizeOrStruct,...) <a id="StringBuilderObject.read" href="#StringBuilderObject.read">&#x23;</a>
从头读取一个或多个内存数据，可指定一个或多个读取参数。  
参数如果是指定读取长度的数值则读取指定长度数据到 buffer 对象，并增加一个返回值。  
参数如果是负数则跳过指定长度（取绝对值）然后继续读取下一个参数。  
参数如果是结构体则读取数据到结构体，并增加一个返回值返回该结构体。  
参数为其他类型时跳过。  
无法满足参数要求的读取长度时停止读取并返回已读取的数据。  

此函数返回一个或多个已读取的值。  
每次调用此函数总是从头开始读取。

### StringBuilderObject.readAt(startIndex,readSizeOrStruct,...) <a id="StringBuilderObject.readAt" href="#StringBuilderObject.readAt">&#x23;</a>
从参数 @startIndex 指定的位置开始读取一个或多个内存数据，可增加一个或多个读取参数。  
@startIndex 可用负数表示自尾部倒计数的位置，-1 表示最后一个辽节。   

参数 @2 开始如果遇到指定读取长度的数值则读取指定长度数据到 buffer 对象，并增加一个返回值。  
如果遇到指定负数值的参数则跳过指定长度（取绝对值）然后继续读取下一个参数。  
如果遇到结构体参数则读取数据到结构体，并增加一个返回值返回该结构体。  
参数为其他类型时跳过。  
无法满足参数要求的读取长度时停止读取并返回已读取的数据。  

此函数返回一个或多个已读取的值。  
每次调用此函数总是从头开始读取。

### StringBuilderObject.replace <a id="StringBuilderObject.replace" href="#StringBuilderObject.replace">&#x23;</a>
使用模式匹配查找并替换字符串。  
此 string.replace 的基本用法相同，  
但此函数修改自身并返回自身（可能会触发内存调整并且变更内部存储的动态指针）。  
第二个返回值为替换次数。

### StringBuilderObject.replace("字符串","@查找字符串","替换字符串",替换次数) <a id="StringBuilderObject.replace" href="#StringBuilderObject.replace">&#x23;</a>
禁用模式匹配替换,  
在查找串中用模式匹配语法，替换字符串反斜杠也仅仅表示字面值不再表示匹配分组,  
以`@@`开始则是`<@@...@>`的缩写形式,忽略大小写查找  
替换次数省略则全局替换

### StringBuilderObject.replace("字符串","模式串",替换函数,替换次数) <a id="StringBuilderObject.replace" href="#StringBuilderObject.replace">&#x23;</a>
使用模式匹配在字符串中查找替换。  
替换回调函数返回需要替换的新字符串,不返回值则保留原字符串。  
有几个匹配分组就有几个回调参数。  
与 string.replace 不同的是，这里回调函数的 owner 参数为 null 值。  

替换次数省略则全局替换  
返回值为替换后的新字符串

### StringBuilderObject.replace("字符串","模式串",替换字符串,替换次数) <a id="StringBuilderObject.replace" href="#StringBuilderObject.replace">&#x23;</a>
使用模式匹配在字符串中查找替换。  
替换字符串,可使用 `\1` 至`\9`引用匹配分组,`\0`表示匹配到的完整字符  

替换次数省略则全局替换  
返回值为替换后的新字符串

### StringBuilderObject.replace("字符串","模式串",替换表,替换次数) <a id="StringBuilderObject.replace" href="#StringBuilderObject.replace">&#x23;</a>
使用模式匹配在字符串中查找替换。  
替换表对象中键为匹配到的字符串,替换值可以是字符串、数值、函数、false  
其中数值转换为字符串返回，false 表示取消替换,  
函数用于接收匹配结果并返回新字符串,有几个匹配分组就有几个回调参数

### StringBuilderObject.reserve() <a id="StringBuilderObject.reserve" href="#StringBuilderObject.reserve">&#x23;</a>
调整预分配内存大小,返回自身。  
小于存储内容大小时则设为存储内容大小。  
参数为 0 时则默认设为 1024。  
此函数可能改变内部动态指针值  

释放动态指针以后,仍然可以调用此函数重新分配内存。  

在分配内存失败时此函数会抛出异常。  
除了极端情况，这通常表示不合理地一次性分配了过多内存，应修正代码而非增加 try 语句。

[返回对象:StringBuilderObject](#StringBuilderObject)

### StringBuilderObject.resize() <a id="StringBuilderObject.resize" href="#StringBuilderObject.resize">&#x23;</a>
调整存储数据大小。  
增加大小时可能改变内部动态指针值。  
减小大小或者设为 0 时仅改变存储的有效数据长度，不会重新分配内存也不会实际修改内存数据。  

在分配内存失败时此函数会抛出异常。  

除了极端情况，这通常表示不合理地一次性分配了过多内存，应修正代码而非增加 try 语句。

### StringBuilderObject.rightString() <a id="StringBuilderObject.rightString" href="#StringBuilderObject.rightString">&#x23;</a>
从右侧截取参数指定长度的字符串。  
返回字符串对象,参数可用负数表示左侧截取位置   
不会改变内部动态指针值

### StringBuilderObject.size() <a id="StringBuilderObject.size" href="#StringBuilderObject.size">&#x23;</a>
返回存储内容大小。  
释放指针后此函数返回 0。

### StringBuilderObject.sliceArray(startIndex,endIndex) <a id="StringBuilderObject.sliceArray" href="#StringBuilderObject.sliceArray">&#x23;</a>
读取指定索引范围的字节串到数组对象。  
省略 startIndex 默认为 1，省略 endIndex 默认为最后一个字节。  
可用负数表示自右侧倒计数的索引。  

startIndex 小于 1 时会设为 1，endIndex 大于长度时会设为长度。  
如果 endIndex 小于 startIndex 则返回 null 。

### StringBuilderObject.sliceBuffer(startIndex,endIndex) <a id="StringBuilderObject.sliceBuffer" href="#StringBuilderObject.sliceBuffer">&#x23;</a>
读取指定索引范围的字节串到 buffer 对象。  
省略 startIndex 默认为 1，省略 endIndex 默认为最后一个字节。  
可用负数表示自右侧倒计数的索引。  

startIndex 小于 1 时会设为 1，endIndex 大于长度时会设为长度。  
如果 endIndex 小于 startIndex 则返回 null 。

### StringBuilderObject.sliceString(startIndex,endIndex) <a id="StringBuilderObject.sliceString" href="#StringBuilderObject.sliceString">&#x23;</a>
读取指定索引范围的字符串。  
省略 startIndex 默认为 1，省略 endIndex 默认为最后一个字节。  
可用负数表示自右侧倒计数的索引。  

startIndex 小于 1 时会设为 1，endIndex 大于长度时会设为长度。  
如果 endIndex 小于 startIndex 则返回 null 。

### StringBuilderObject.splice(start,deleteCount,arg1,...) <a id="StringBuilderObject.splice" href="#StringBuilderObject.splice">&#x23;</a>
自参数 @start 指定索引删除 @deleteCount 长度（默认为 0）的字节，  
然后在删除位置写入后续的任意个参数，可写入字符串、buffer、结构体。  
如果删除了数据则返回包含删除数据的字符串对象。

### StringBuilderObject.str <a id="StringBuilderObject.str" href="#StringBuilderObject.str">&#x23;</a>
转换为纯文本字符串  
如果需要转换为二进制字符串,直接使用 tostring 函数转换 string.builder 对象即可。

### StringBuilderObject.str(是否unicode,偏移) <a id="StringBuilderObject.str" href="#StringBuilderObject.str">&#x23;</a>
去掉尾部多余终结符转换为纯文本字符串,参数可省略,偏移默认为 0。  
参数 @1 为 true 反回字符串标记会设置 UTF-16 标记,否则设为 UTF-8 标记

### StringBuilderObject.string() <a id="StringBuilderObject.string" href="#StringBuilderObject.string">&#x23;</a>
返回二进制字符串，等价于将当前对象作为参数调用 tostring 函数。  
如果要获取纯文本字符串可改用 str 函数，纯文本以空字符（NUL）为终止符。

### StringBuilderObject.toUtf16(转换字节数,源编码) <a id="StringBuilderObject.toUtf16" href="#StringBuilderObject.toUtf16">&#x23;</a>
转换并返回 UTF16 编码字符串。  
字节数可省略,默认为 -1。  
字节数为 -1 时表示查找 ``'\0'`` 终止符自动获取长度

### StringBuilderObject.tokenize(分割符) <a id="StringBuilderObject.tokenize" href="#StringBuilderObject.tokenize">&#x23;</a>

```aardio
for(token in StringBuilderObject.tokenize("/*任意个单字节分割符*/")){
	/*文本模式拆分，迭代变量 token 为当前拆分的文本单元。  
此迭代器使用迭代开始时获取的动态指针，  
应避免在拆分过程中扩大 string.builder 对象的内存导致该迭代器使用的指针失效。  
此迭代器会修改源指针里每个拆分文本单元的尾部分隔符为空字符，  
但返回的 token 已复制为新的字符串对象。*/
}
```

### StringBuilderObject.trim() <a id="StringBuilderObject.trim" href="#StringBuilderObject.trim">&#x23;</a>
清除两侧空白字符  
可选用一个字符串指定要清除的单字节字符。

### StringBuilderObject.trimleft() <a id="StringBuilderObject.trimleft" href="#StringBuilderObject.trimleft">&#x23;</a>
清除左侧空白字符。  
可选用一个字符串指定要清除的单字节字符。

### StringBuilderObject.trimright() <a id="StringBuilderObject.trimright" href="#StringBuilderObject.trimright">&#x23;</a>
清除右侧空白字符。  
可选用一个字符串指定要清除的单字节字符。

### StringBuilderObject.write() <a id="StringBuilderObject.write" href="#StringBuilderObject.write">&#x23;</a>
在尾部写入一个或多个字符串、buffer、结构体参数。  
其他类型参数转换为字符串写入，遇到 null 值停止写入。

### StringBuilderObject.writeAt(startIndex,arg1...) <a id="StringBuilderObject.writeAt" href="#StringBuilderObject.writeAt">&#x23;</a>
在参数 @startIndex 指定位置开始写入一个或多个字符串、buffer、结构体参数。  
其他类型参数转换为字符串写入，遇到 null 值停止写入。  

@startIndex 为 1 表示从开头写入，  
省略 @startIndex 在尾部追加式写入（等价于调用 write 函数）。  
@startIndex 为负数则表示自尾部倒计数的位置，-1 表示最后一个字节。  

与此函数相比，splice 方法可指定要删除的旧数据长度再插入新数据，后面的数据自动向后移动。  
在 writeAt 则是在指定位置开始覆写而非插入，会覆盖已存在的内容，不会移动旧数据的位置。  
相同的是 write,writeAt,splice 方法都可以在内存不够时自动增大内存以容纳更长的内容。

### 全局常量

### ::Msvcrt <a id="::Msvcrt" href="#::Msvcrt">&#x23;</a>
VC 基础运行库，这是所有操作系统都自带的系统 DLL。  
string.builder, ustring, console 等标准库都自动加载了此 DLL。  
默认使用 cdecl 调用约定。  

[返回对象:dllModuleObject](https://www.aardio.com/zh-cn/doc/library-reference/raw/_.html#dllModuleObject)
