Rust
PHP
JavaScript
一些编程语言的优点,使语法更为简洁,学习更简单。
BT可以用来快速开发Web网站,因为她那独有的纯洁性,她不依赖Apache
Nginx
这些Web服务器,你只需要编写几行简单的BT代码,就可以配置好域名、SSL以及项目目录的绑定。
BT既属于编译型语言,又属于解释型语言,这也是BT独有的魔性,看你要做什么用了,但绝不像PHP只服务于Web,她可以开发桌面软件,如果做为BT脚本,那么她可以直接被运行,还可以嵌入常见的主流程序语言中被调用。
- BT支持无限链式语法
- BT不是强类型语言,所以编写程序时,更加自由
- BT可以用来快速开发Web网站,只需要编写几行简单的BT代码,就可以配置好域名与项目目录的绑定。
- BT可以开发桌面软件,BT脚本文件可以直接被运行,可以嵌入常见的主流程序语言中被调用。
- BT语法超级自由,超级简洁,绝对称得上世界上最简洁的语法。
- BT是跨平台的,可以运行在
Windows
Linux
macOS
等多个操作系统上运行,而不需要对代码进行大量修改。
环境要求
适用于:环境搭建
BT语言是所有编程语言中最简洁的语言,无需搭建环境,只需要拥有一个简单的记事本足以,然而为了更快乐的写代码,官方推荐: 代码编辑器:Vscode
+ 扩展(bt-lang)
在Vscode中直接打开bt-lang扩展
其它编辑器:
HBuilderX
+ 扩展(bt-lang)
到HBuilderX插件市场进行安装
Sublime Text
+ 扩展(bt-lang)
到GitHub中下载,放入【软件安装目录\Data\Packages】即可
如何使用
BT语言编译器只能编译.bt文件,所以你的所有代码都应该写在以bt为后缀的文件中,BT语言编译器不仅是一个编译器,也是一个极为惊人的解释器。 当BT编译器打开时,如果当前目录存在main.bt文件时,会默认打开并执行里面的代码,不存在时,以终端命令行的方式运行。运行调试
官网针对各种编辑器开发了针对BT语言的扩展,统一名称为bt-lang
,这里以Vscode为示例,安装好bt-lang
扩展后,打开项目(项目根目录中必须存在BT编译器),编辑或创建main.bt文件,代码:
print 'hello world'
然后点击Vscode侧边活动栏上的BT按钮,展开侧栏,点击运行,终端将输出脚本执行的内容。
项目完成后,下面是关于各个平台的简单使用方式:
1. Windows中使用
直接双击 bt.exe 程序即可,默认打开当前目录的main.bt文件,执行里面的代码。2. Linux和macOS中使用
1)使用cd命令进入程序所在目录,然后赋予bt执行权限并运行,命令行: cd /home/project chmod +x bt ./bt 2)Linux中,如果为web项目,可通过nohup命令执行,该命令用于在后台执行命令或程序,并且不受终端关闭的影响 nohup ./bt &BT语言教程
BT语言编译器打开时,默认先执行当前目录的main.bt
文件,如果你需要做web端开发,那么该文件将作为项目配置文件,用于设定项目目录、SSL证书,以及web端的一些常用设置。
下载编译器后,进行解压,文件包中的main.bt
文件中有详细的web配置注释。
// -------------------------------------
// BT语言的项目配置文件
// -------------------------------------
// 项目路径 - 脚本存放路径,结尾为斜杠
PROJECT_PATH = 'script/'
// 入口文件 - 项目路径中首先执行的脚本文件
ENTRY_FILE = 'main.bt'
// web服务是否开启 - 只有开启,以下参数才会生效
WEB_SERVICE_OPEN = true
// 域名绑定 - Windows系统本地测试需改为127.0.0.1,部署至线上尽量使用0.0.0.0
WEB_DOMAIN_NAME = '0.0.0.0'
// 域名端口
WEB_PORT = '443'
// SSL证书是否开启 - 用于https访问
SSL_OPEN = true
// 证书文件路径
SSL_CERT_FILE = 'ssl/cart.pem'
// 密钥文件路径
SSL_KEY_FILE = 'ssl/key.pem'
// 静态文件服务是否开启
WEB_STATIC_OPEN = true
// 静态资源路径
WEB_STATIC_PATH = 'script/static/'
// 静态资源默认文件
// 如果请求的URL对应于一个目录而不是一个具体的文件,服务器将尝试返回该目录下的默认文件
// 这是一种常见的做法,用于在访问网站根目录或任何子目录时提供默认页面
// 支持在存在压缩文件的情况下,优先发送压缩文件,比如设置index.html时
// 会优先发送index.html.gz,index.html.zst,index.html.br这几个文件(如果存在的话)
WEB_STATIC_DEFAULT = 'index.html'
// 静态资源路由
// <**>: 代表通配符匹配的部分可以是空字符串, 比如路径是/files/<**>, 会匹配/files,/files/abc.txt,/files/dir/abc.txt
// <*+>: 代表通配符匹配的部分必须存在,不能匹配到空字符串, 比如路径是/files/<*+>, 不会匹配/files,
// 但是会匹配/files/abc.txt,/files/dir/abc.txt
// <*?>: 代表通配符匹配的部分可以是空字符串, 但是只能包含一个路径片段, 比如路径是 /files/<*?>, 不会
// 匹配/files/dir/abc.txt 但是会匹配 /files,/files/abc.txt
WEB_STATIC_ROUTER = 'static/<**>'
代码示例
经典的开场白: print 'hello world'语法说明
BT的语法更贴近于JavaScript
,有些地方与Rust相似,以下是BT的语法规范:
- 单行语句结束时,尽量不要写分号
;
,在BT语言中,空格和换行属于结束语句。 - 所有的语句都会拥有返回值,包括打印函数
print
,还有if
for
while
loop
- 声明变量时,无需使用let,直接声明即可,let主要用于声明当前作用域变量,而与全局变量分开。
输出
BT中的数据输出函数主要为:print
println
print
用于输出内容,可输出任何类型的数据
println
与print
不同的是该函数无论打印任何数据,都会重新换行
使用注释
在编程中,注释是一种在代码中添加说明或备注的方式,这些说明或备注不会被计算机执行。注释的主要目的是为了提高代码的可读性和可维护性,帮助开发者(或未来的自己)理解代码的意图、逻辑或实现方式。 在BT语言中分两种注释,一种是单行注释,一种是多行注释。 单行注释使用两个斜杠//
,多行注释使用两个斜杠和两个星号/**/
,示例:
/**
* 我是多行注释
* 你好,世界
*/
print 'hello world' // 我是单行注释
// 我是单行注释
name = 'Lisa'
声明变量
变量:可以在程序执行过程中被重新赋值,即其值可以发生变化,也可重复赋值不同的数据类型- 变量命名规范为[a-zA-Z0-9_$],可为字母、数字、下划线和$混合
- 变量命名不能以数字开头,不能以大写字母开头
- 变量名称对大小写敏感(aBc 和 abc 是不同的变量)
声明常量
常量:在定义后其值不可再被改变,用于表示程序中不会改变的数据,如配置参数、数学常数等。- 常量命名规范为[a-zA-Z0-9_$],可为字母、数字、下划线和$混合
- 常量命名只能以大写字母开头
- 常量名称对大小写敏感(ABC 和 ABc 是不同的常量)
数据类型
BT语言中的基础数据类型:-
Int
整数 -
Float
浮点 -
Bool
布尔 -
Str
字符 -
Array
数组 -
Object
对象
-
null
表示不是有效的值,可被打印出来。 -
empty
表示空,它不是一个值,不属于任何类型,不会被打印出来。
-
Fn
函数 -
Class
类 -
File
文件对象 -
Date
时间对象 -
Break
循环阻断 -
Continue
循环跳过 -
Regex
正则表达式
if
,没错,必须支持if...elseif...else
,如果你还不会用,请看下面的条件语句教学。
运算符
BT语言中的运算符非常丰富,主要包括算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符、条件运算符、逗号运算符等。 下面我将逐一介绍这些运算符及其用法:算术运算符
+
加法运算符
-
减法运算符
*
乘法运算符
/
除法运算符
%
取模运算符(求余数)
x = 12
y = 29 % 5
z = (x + y) * 5 / 2
关系运算符
>
大于
<
小于
==
等于
!=
不等于
>=
大于等于
<=
小于等于
price = 19.99
if price >= 10 {
print '大于等于10'
}
逻辑运算符
&&
逻辑与
||
逻辑或
!
逻辑非
price = 19.99
num = 20
if price >= 10 && num < 10 {
print 'ok'
}
位运算符
&
按位与,对两个数的二进制表示进行逐位比较,如果两个相应的位都为1,则该位的结果为1,否则为0
|
按位或,对两个数的二进制表示进行逐位比较,如果两个相应的位中至少有一个为1,则该位的结果为1,否则为0
^
按位异或,对两个数的二进制表示进行逐位比较,如果两个相应的位不同,则该位的结果为1,否则为0
~
按位取反,对一个数的二进制表示进行逐位取反,即0变为1,1变为0
<<
左移,将一个数的各二进制位全部左移若干位,由符号位(最左边的位)的空位则以0来填充
>>
右移,将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃
x = 20
y = x | 2
z = y >> 2
赋值运算符
=
简单赋值
+=
加后赋值
-=
减后赋值
*=
乘后赋值
/=
除后赋值
%=
取模后赋值
<<=
左移后赋值
>>=
右移后赋值
&=
按位与后赋值
^=
按位异或后赋值
|=
按位或后赋值
x = 20
x += 10
x %= 3
条件运算符
? :
条件运算符,格式为表达式1 ? 表达式2 : 表达式3。如果表达式1为真,则结果为表达式2的值,否则为表达式3的值。
x = 10
// 三元运算
y = x == 10 ? 1 : 2
// 等同于下面的代码
if x == 10 {
y = 1
} else {
y = 2
}
// 二元运算
x == 10 ? print 'yes'
// 等同于下面的代码
if x == 10 {
print 'yes'
}
说到二元运算,BT的魔性依然是性感的,示例:
x = 8
// 无论是三元还是二元都可以进行赋值,因为BT语言中,任何表达式都有返回值
// x == 9 不成立,所以这里会返回一个null,在别的编程语言中不要这么实验了,会报错
a = x == 9 ? 7
逗号运算符
,
逗号运算符,用于顺序执行一系列运算,整个逗号表达式的值为最后一个表达式的值。
a=1, b=2, c=3
其他运算符
()
括号运算符,用于改变运算顺序或进行函数调用。
[]
下标运算符,用于访问数组元素。
.
成员运算符。
print ['hello'][0].to_lowercase()
这些运算符是BT语言编程的基础,掌握它们对于编写高效、可读性强的代码至关重要。
条件语句
条件语句用于基于不同条件执行不同的逻辑。在 bt
中,我们可使用以下条件语句:
-
if
语句 - 当条件为true
时,执行该代码 -
if...else
语句 - 当if语句条件为true
时执行代码,当条件为false
时,执行else
中代码 -
if...elseif...else
语句- 使用该语句来选择多个代码块之一来执行
if 语句
只有当指定条件为true
时,该语句才会执行代码。
语法
if condition { 当条件为 `true` 时执行的代码 }注意:条件无需小括号,只有需要权重的时候,加入括号,这里是非必须的,为了保持整洁,简单条件语句无需加入括号
实例
当变量a大于10
的时候,打印hello
字符串:
if...else 语句
请使用f...else
语句在条件为 true
时执行代码,在条件为 false
时执行其他代码。
语法
if condition { 当条件为 `true` 时执行的代码 } else { 当条件为 `false` 时执行的代码 }实例
当变量大于10
的时候,打印hello
字符串,其它结果则打印world
字符串:
小插曲
其实在bt语言中,几乎所有的表达式都支持返回值,上面的打印代码可以简化为: a = 15 print if a > 10 { 'hello' } else { 'world' }if...elseif...else 语句
使用if...elseif...else
语句来选择多个代码块之一来执行。
语法
if condition1 { 当条件 1 为 true 时执行的代码 } elseif condition2 { 当条件 2 为 true 时执行的代码 } else { 当条件 1 和 条件 2 都不满足条件时执行的代码 }实例
当变量a大于10
的时候,打印hello
字符串,a大于15
的时候,打印world
字符串,其它结果则打印nice
字符串:
数字操作
基于Int和Float的操作支持以下函数:len
返回数字的字符串长度语法 Number.len()
num = 5.56789 println num.len() // 输出:7to_fixed
将数字格式化为指定小数位数的字符串,四舍五入到最接近的值。语法 Number.to_fixed(digits:Int)
digits:非必填,表示用于指定小数的位数
num = 5.56789 println num.to_fixed() // 输出:6 println num.to_fixed(2) // 输出:5.57to_string
将数字转换为字符串,可以指定基数(进制)来转换不同进制下的字符串。语法 Number.to_string(radix:Int)
radix:非必填,表示指定的进制基数
num = 15 // 转为字符串 println num.to_string() // 输出:15 // 转为二进制字符串 println num.to_string(2) // 输出:1111 // 转为八进制字符串 println num.to_string(8) // 输出:17 // 转为十六进制字符串 println num.to_string(16) // 输出:fto_exponential
将数字格式化为指数表示的字符串,即科学计数法。语法 Number.to_exponential()
num = 5.56789 println num.to_exponential() // 输出:5.56789e+0字符串操作
基于字符串的操作支持以下函数:len
返回字符串的长度语法 Str.len()
str = 'hello' println str.len() // 输出:5char
根据索引返回字符串中的字符语法 Str.char(index:Int)
index:必填,表示要返回字符的索引位置
str = 'hello' println str.char(1) // 输出:'e'char_code
根据索引返回字符串中字符的 Unicode 编码语法 Str.char_code(index:Int)
index:必填,表示要返回字符的索引位置
str = 'hello' println str.char_code(1) // 输出:101 ('e' 的 Unicode 编码)concat
连接两个或多个字符串,并返回新的字符串语法 Str.concat(...string:Str)
...string:必填,多参数
str1 = 'hello' str2 = 'world' println str1.concat(str2) // 输出:'helloworld' println str1.concat(' ', str2, '!') // 输出:'hello world!'ends_with
检查字符串是否以指定的子字符串结尾,返回布尔值语法 Str.ends_with(string:Str)
string:必填,用于查找的子字符串
str = 'hello, world!' println str.ends_with('!') // 输出:true println str.ends_with('world') // 输出:falsecontain
检查字符串是否包含指定的子字符串,返回布尔值语法 Str.contain(string:Str)
string:必填,用于查找的字符串
str = 'hello, world!' println str.contain('world') // 输出:true println str.contain('planet') // 输出:falseindex
返回在字符串中首次找到指定值的索引,如果不存在则返回 -1语法 Str.index(string:Str)
string:必填,用于查找的字符串
str = 'hello, world!' println str.index('o') // 输出:4 println str.index('planet') // 输出:-1last_index
返回在字符串中最后一次找到指定值的索引,如果不存在则返回 -1语法 Str.last_index(string:Str)
string:必填,用于查找的字符串
str = 'hello, world!' println str.last_index('o') // 输出:7 println str.last_index('planet') // 输出:-1repeat
返回一个新字符串,该字符串包含被连接在一起的指定数量的字符串副本语法 Str.repeat(count:Int)
count:必填,表示重复的次数
str = 'hello' println str.repeat(3) // 输出:'hellohellohello'replace
在字符串中查找匹配的子字符串,并替换为新的子字符串语法 Str.replace(string:Str|regex:Regex, new_string:Str)
string|regex:必填,字符串或正则表达式,表示要替换的内容
new_string:必填,字符串类型,表示替换后的内容
str = 'hello, world!' println str.replace('world', 'bt') // 输出:'hello, bt!' println str.replace(/l/, 'L') // 使用正则,输出:'heLlo, world!' println str.replace(/l/g, 'L') // 使用正则,输出:'heLLO, worLd!'search
使用正则表达式模式在字符串中查找匹配项,并返回第一个匹配项的索引语法 Str.search(regex:Regex)
regex:必填,表示要匹配查找内容的正则表达式
str = 'hello, world!' println str.search(/o/) // 输出:4 println str.search(/planet/) // 输出:-1match
使用正则表达式模式在字符串中查找匹配项,并返回包含结果的数组语法 Str.match(regex:Regex)
regex:必填,表示要匹配查找内容的正则表达式
str = 'hello, world!' println str.match(/o/g) // 输出:[{"0": "o"},{"1": "o"}] // 使用命名捕获组 str = '今天10号,明天11号' println str.match(/(?<num>\d+)/g) // 输出:[{"num": "10"},{"num": "11"}]slice
提取字符串的片段,并在新的字符串中返回被提取的部分语法 Str.slice(start:Int, end:Int)
start:必填,表示片段的起始位置
end:选填,表示片段的结束位置
str = 'hello, world!' println str.slice(0, 5) // 输出:'hello' println str.slice(7) // 输出:'world!'split
通过将字符串分割为子字符串数组语法 Str.split(string:Str)
string:必填,表示用于分割的字符串
str = 'hello, world!' println str.split(', ') // 输出:['hello', 'world!']starts_with
检查字符串是否以指定的子字符串开始,返回布尔值语法 Str.starts_with(string:Str)
string:必填,用于查找的字符串
str = 'hello, world!' println str.starts_with('hello') // 输出:true println str.starts_with('world') // 输出:falsesubstring
返回位于两个指定下标之间的字符串的子串语法 Str.substring(start:Int, end:Int)
start:必填,表示起始位置
end:选填,表示结束位置
str = 'hello, world!' println str.substring(0, 5) // 输出:'hello' println str.substring(7) // 输出:'world!'to_lowercase
将字符串转换为小写语法 Str.to_lowercase()
str = 'HELLO, WORLD!' println str.to_lowercase() // 输出:'hello, world!'to_uppercase
将字符串转换为大写语法 Str.to_uppercase()
str = 'hello, world!' println str.to_uppercase() // 输出:'HELLO, WORLD!'trim
去除字符串两端的空白字符(包括空格、制表符、换行符等)语法 Str.trim()
str = ' hello, world! ' println str.trim() // 输出:'hello, world!'to_string
返回字符串的字符串表示(对于字符串类型,此方法通常直接返回字符串本身)语法 Str.to_string()
str = 'hello' println str.to_string() // 输出:'hello'escape_html
将字符串中的特殊HTML字符转换为HTML实体(用于防止XSS攻击)语法 Str.escape_html()
str = '<div>Hello, world!</div>' println str.escape_html() // 输出:'<div>Hello, world!</div>'unescape_html
将字符串中的HTML实体转换回特殊HTML字符(用于显示HTML内容)语法 Str.unescape_html()
str = '<div>Hello, world!</div>' println str.unescape_html() // 输出:'<div>Hello, world!</div>'parse
将字符串转为Array数组或Object对象语法 Str.parse()
str = '["apple", "banana", "cherry"]' arr = str.parse() println arr[1] // 输出:banana println arr // 输出:['apple', 'banana', 'cherry'] str = '{"name": "John", "age": 30}' obj = str.parse() println obj.age // 输出:30 println obj // 输出:{'name': 'John', 'age': 30} // 你也可以直接在字符串上调用 parse 方法 println '["apple", "banana", "cherry"]'.parse()[1] // 输出:banana 以上便是字符串的原型函数,由于链式语法的原因,只要满足字符串类型可以无限调用原型函数,如下: println 'hello,world!'.to_uppercase().substring(6) // 输出 WORLD! println 'Lisa'.split('').join(',') // 输出 L,i,s,aArray数组操作
基于数组的操作支持以下函数:len
返回数组的长度语法 Array.len()
arr = ['apple', 'banana', 'cherry'] println arr.len() // 输出:3join
将数组的所有元素连接成一个字符串,元素之间用指定的分隔符隔开语法 Array.join(separator:Str)
separator:非必填,表示用来分隔数组元素的字符串,默认为逗号
arr = ['apple', 'banana', 'cherry'] println arr.join() // 输出:apple,banana,cherry println arr.join(' - ') // 输出:apple - banana - cherryeach
对数组的每个元素执行一次给定的函数语法 Array.each(callback(value:Any,key:Int))
callback:接收两个参数,元素值和索引
arr = ['apple', 'banana', 'cherry'] arr.each(fn(v,k){ println 'key: ' + k println 'value: ' + v })pop
移除数组中的最后一个元素,并返回该元素语法 Array.pop()
arr = ['apple', 'banana', 'cherry'] println arr.pop() // 输出:cherry println arr // 输出:['apple', 'banana']push
向数组的末尾添加一个或多个元素,并返回新数组的长度语法 Array.push(element1:Any, element2:Any, ...)
arr = ['apple', 'banana'] println arr.push('cherry') // 输出:3 println arr // 输出:['apple', 'banana', 'cherry']shift
移除数组中的第一个元素,并返回该元素语法 Array.shift()
arr = ['apple', 'banana', 'cherry'] println arr.shift() // 输出:apple println arr // 输出:['banana', 'cherry']unshift
向数组的开头添加一个或多个元素,并返回新数组的长度语法 Array.unshift(element1:Any, element2:Any, ...)
arr = ['banana', 'cherry'] println arr.unshift('apple') // 输出:3 println arr // 输出:['apple', 'banana', 'cherry']sort
根据指定的比较函数对数组元素进行排序语法 Array.sort(compareFunction)
compareFunction:非必填,用来定义排序顺序的函数
arr = [3, 1, 4, 1, 5] arr.sort() println arr // 输出:[1, 1, 3, 4, 5]reverse
反转数组中元素的顺序语法 Array.reverse()
arr = ['apple', 'banana', 'cherry'] arr.reverse() println arr // 输出:['cherry', 'banana', 'apple']slice
从数组中返回一个新数组,该数组从开始索引到结束索引(不包括结束索引)语法 Array.slice(start:Int, end:Int)
start:必填,起始索引
end:非必填,结束索引,默认到数组的末尾
arr = ['apple', 'banana', 'cherry'] println arr.slice(1, 2) // 输出:['banana']splice
通过移除或替换现有元素以及添加新元素来修改数组的内容,并返回被移除的元素语法 Array.splice(start:Int, deleteCount:Int, item:Any, item:Any,...)
start:必填,开始修改的位置
deleteCount:非必填,要删除的元素数量
...item:非必填,需添加的新元素
arr = ['apple', 'banana', 'cherry'] println arr.splice(1, 1, 'orange') // 输出:['banana'] println arr // 输出:['apple', 'orange', 'cherry']concat
将一个或多个数组或值连接到数组,并返回一个新的数组语法 Array.concat(array1:Any, array2:Any, ...)
arr1 = ['apple', 'banana'] arr2 = ['cherry', 'date'] println arr1.concat(arr2) // 输出:['apple', 'banana', 'cherry', 'date']contain
判断数组是否包含指定的值,如果包含返回true,否则返回false语法 Array.contain(value:Any)
arr = ['apple', 'banana', 'cherry'] println arr.contain('banana') // 输出:true println arr.contain('date') // 输出:falseindex
返回数组中第一个与指定值相等的元素的索引,如果没有找到,则返回-1语法 Array.index(value:Any)
arr = ['apple', 'banana', 'cherry'] println arr.index('banana') // 输出:1 println arr.index('date') // 输出:-1last_index
返回数组中最后一个与指定值相等的元素的索引,如果没有找到,则返回-1语法 Array.last_index(value:Any)
arr = ['apple', 'banana', 'apple'] println arr.last_index('apple') // 输出:2 println arr.last_index('date') // 输出:-1find
返回数组中第一个满足测试函数的元素值语法 Array.find(callback:Fn(value:Any, key:Int, current:Any))
callback:测试每个元素的函数,返回布尔值
arr = [1, 2, 3, 4] println arr.find(fn(v){ v > 2 }) // 输出:3find_index
返回数组中第一个满足测试函数的元素的索引语法 Array.find_index(callback:Fn(value:Any, key:Int, current:Any))
arr = [1, 2, 3, 4] println arr.find_index(fn(v){ v > 2 }) // 输出:2find_last
返回数组中最后一个满足测试函数的元素值语法 Array.find_last(callback:Fn(value:Any, key:Int, current:Any))
arr = [1, 2, 3, 4] println arr.find_last(fn(v){ v > 2 }) // 输出:4find_last_index
返回数组中最后一个满足测试函数的元素的索引语法 Array.find_last_index(callback:Fn(value:Any, key:Int, current:Any))
arr = [1, 2, 3, 4] println arr.find_last_index(fn(v){ v > 2 }) // 输出:3every
测试数组的所有元素是否都通过了指定的测试函数语法 Array.every(callback:Fn(value:Any, key:Int, current:Any))
arr = [1, 2, 3, 4] println arr.every(fn(v){ v > 0 }) // 输出:true println arr.every(fn(v){ v > 2 }) // 输出:falsesome
测试数组中的至少一个元素是否通过了指定的测试函数语法 Array.some(callback:Fn(value:Any, key:Int, current:Any))
arr = [1, 2, 3, 4] println arr.some(fn(v){ v > 2 }) // 输出:true println arr.some(fn(v){ v > 4 }) // 输出:falsefilter
创建一个新数组,其包含通过指定测试函数的所有元素语法 Array.filter(callback:Fn(value:Any, key:Int, current:Any))
arr = [1, 2, 3, 4] println arr.filter(fn(v){ v > 2 }) // 输出:[3, 4]map
创建一个新数组,其结果是对数组中每个元素应用一个函数的结果语法 Array.map(callback:Fn(value:Any, key:Int, current:Any))
arr = [1, 2, 3, 4] println arr.map(fn(v){ v * 2 }) // 输出:[2, 4, 6, 8]reduce
对数组中的每个元素执行一个归并操作,将其归并为单一输出值语法 Array.reduce(callback:Fn(acc:Any, value:Any, key:Int), initialValue:Any)
initialValue(非必填):初始值
arr = [1, 2, 3, 4] println arr.reduce(fn(acc, v){ acc + v }, 0) // 输出:10reduce_right
与reduce相同,但从右向左执行语法 Array.reduce_right(callback:Fn(acc:Any, value:Any, key:Int), initialValue:Any)
arr = [1, 2, 3, 4] println arr.reduce_right(fn(acc, v){ acc + v }, 0) // 输出:10fill
用一个固定值填充数组中从起始索引到终止索引的所有元素语法 Array.fill(value:Any, start:Int, end:Int)
start:非必填,填充开始的索引,默认为0
end:非必填,填充结束的索引(不包括该索引),默认为数组长度
arr = [1, 2, 3, 4] arr.fill(0, 1, 3) println arr // 输出:[1, 0, 0, 4]flat
创建一个新数组,其中包含所有子数组元素的元素语法 Array.flat(depth:Int)
depth(非必填):指定递归深度,默认为1
arr = [1, [2, 3], [4, [5, 6]]] println arr.flat() // 输出:[1, 2, 3, 4, [5, 6]] println arr.flat(2) // 输出:[1, 2, 3, 4, 5, 6]flat_map
首先使用映射函数映射每个元素,然后将结果压平语法 Array.flat_map(callback:Fn(value:Any, key:Int, current:Any))
arr = [1, 2, 3] println arr.flat_map(fn(v){ v * 2 }) // 输出:[1, 2, 2, 4, 3, 6]keys
返回一个新的数组,其包含数组的所有索引语法 Array.keys()
arr = ['apple', 'banana', 'cherry'] println arr.keys() // 输出:[0, 1, 2]values
返回一个新的数组,其包含数组的所有值语法 Array.values()
arr = ['apple', 'banana', 'cherry'] println arr.values() // 输出:['apple', 'banana', 'cherry']entries
返回一个新的数组,其中包含数组的所有索引和值的数组语法 Array.entries()
arr = ['apple', 'banana', 'cherry'] println arr.entries() // 输出:[[0, 'apple'], [1, 'banana'], [2, 'cherry']]fn函数
函数是编程语言中的一个重要概念,由事件驱动的或者当它被调用时执行的可重复使用的代码块 // 这是一个简单的函数声明 fn add(a, b){ a + b } print add(1, 2) // 如果你具有一定的编程基础,应该很理解`return`的使用,她用于返回数据,并中断后续的代码执行 fn add(a){ if a > 10 { return '大于10' } else { return '小于10' } } print add(20) // 也可以使用赋值的方式声明函数,其实这个没啥意义,你喜欢就好,因为在bt中,上面的函数声明是可以重复声明的 add = fn(a){ return a } print add(123) 在BT中,所有的语句都具有返回值,fn函数同样也是,默认会返回函数中最后一条语句的数据,当然你也可以在任何地方使用return
返回数据,此时它会中断return
后面的所有语句执行。
函数中的参数支持设置默认参数,如下:
// 给参数a和b添加默认参数 fn add(a=10, b=20){ a + b } print add() // 输出 30 print add(30) // 输出 50 print add(30, 40) // 输出 70Regex正则表达式
Regex:是正则表达式(regular expression)的简写。 正则表达式(Regular Expression)是一种强大的文本处理工具,用于匹配字符串中的特定模式。它由普通字符和特殊字符(称为元字符)组成,用于描述一种字符串匹配的模式。正则表达式可以检查一个字符串是否含有某种子串、将匹配的子串做替换或从某个字符串中取出符合某个条件的子串等。 正则表达式在许多编程语言和文本编辑器中都有广泛应用,例如VsCode、SublimeText等工具,以及PHP、Perl、Java、JavaScript、C#等编程语言。它主要用于文本搜索、替换、模式匹配等操作,能够帮助程序员高效地处理和分析文本数据。 例如:一个简单的正则表达式^\d+$
用于匹配一串数字,其中^
表示字符串的开始,\d+
表示一个或多个数字。
语法
正则表达式主要由两个斜杠组成,最后一个斜杠后面为修饰符,用于配置匹配模式,如下:re = /pattern/modifiers
pattern(模式) 表达式的模式 modifiers(修饰符) 用于指定全局匹配、区分大小写的匹配和多行匹配 // 声明一个正则类型,用于匹配四位数,全局匹配 re = /\d{4}/g修饰符
修饰符用于执行区分大小写和全局匹配:-
i
执行对大小写不敏感的匹配 -
g
执行全局匹配(查找所有匹配而非在找到第一个匹配后停止) -
m
执行多行匹配 -
s
允许 . 匹配 \n
字符类
字符类允许你定义匹配一组字符的规则,支持以下几种模式:-
[xyz]
匹配 x、y 或 z 中的任意一个字符(并集) -
[^xyz]
匹配除 x、y 和 z 之外的任何字符(取反) -
[0-9]
匹配 0 到 9 范围内的数字(区间匹配) -
[a-z]
匹配 a 到 z 范围内的任何小写字母(区间匹配) -
[A-Z]
匹配 A 到 Z 范围内的任何大写字母(区间匹配) -
[A-z]
匹配 A 到 z 范围内的任何大写和小写字母(区间匹配) -
[[:alpha:]]
匹配任意字母字符(ASCII 字符类,等价于 [A-Za-z]) -
[[:^alpha:]]
匹配任何非字母字符(取反的 ASCII 字符类,等价于 [^A-Za-z]) -
[x[^xyz]]
嵌套/分组字符类,匹配 x 和除 y 和 z 之外的任意字符 -
[a-y&&xyz]
交集操作,匹配 x 或 y(即 a-y 与 xyz 的交集) -
[0-9&&[^4]]
使用交集和取反进行的减法操作,匹配 0-9 中除 4 之外的字符 -
[0-9--4]
直接减法操作,匹配 0-9 中除 4 之外的字符 -
[a-g~~b-h]
对称差操作,匹配 a 和 h(即 a-g 与 b-h 的对称差) -
[\[\]]
在字符类中转义,匹配 [ 或 ] -
[a&&b]
空字符类,匹配不到任何字符
元字符
元字符(Metacharacter)是拥有特殊含义的字符:-
.
匹配任意字符,除了换行符(如果设置了 s 标志,. 也可以匹配换行符) -
\d
匹配任意数字字符(等价于 Unicode 类 \p{Nd}) -
\D
匹配任意非数字字符 -
\s
匹配任意空白字符(包括空格、制表符等) -
\S
匹配任意非空白字符 -
\w
匹配任意单词字符(包括字母、数字和下划线) -
\W
匹配任意非单词字符 -
\*
匹配字面上的 *,适用于所有 ASCII 字符,除了 [0-9A-Za-z<>] -
\a
响铃符(\x07) -
\f
换页符(\x0C) -
\t
水平制表符(tab 键) -
\n
换行符 -
\r
回车符 -
\v
垂直制表符(\x0B) -
\A
匹配输入的开头 -
\z
匹配输入的结尾 -
\b
单词边界断言 -
\B
非单词边界断言(即反向的单词边界) -
\b{start}, \<
单词开始边界断言 -
\b{end}, \>
单词结束边界断言 -
\b{start-half}
单词开始边界的半边断言 -
\b{end-half}
单词结束边界的半边断言 -
\123
八进制字符代码,最多三位数(当启用时) -
\x7F
十六进制字符代码(精确为两位) -
\x{10FFFF}
任何对应于 Unicode 代码点的十六进制字符代码 -
\u007F
十六进制字符代码(精确为四位) -
\u{7F}
任何对应于 Unicode 代码点的十六进制字符代码 -
\U0000007F
十六进制字符代码(精确为八位) -
\U{7F}
任何对应于 Unicode 代码点的十六进制字符代码 -
\p{Letter}
Unicode 字符类(例如,匹配任意字母字符) -
\P{Letter}
反向的 Unicode 字符类(例如,匹配任何非字母字符) -
\pX
匹配由一个字母标识的 Unicode 字符类,例如 \pL 匹配所有字母 -
\PX
匹配由一个字母标识的取反 Unicode 字符类,例如 \PL 匹配非字母字符
重复匹配
在BT的正则表达式中,可以使用以下语法来指定重复模式:-
x*
匹配零次或多次 x(贪婪匹配) -
x+
匹配一次或多次 x(贪婪匹配) -
x?
匹配零次或一次 x(贪婪匹配) -
x*?
匹配零次或多次 x(非贪婪/懒惰匹配) -
x+?
匹配一次或多次 x(非贪婪/懒惰匹配) -
x??
匹配零次或一次 x(非贪婪/懒惰匹配) -
x{n,m}
匹配至少 n 次 x,且至多 m 次 x(贪婪匹配) -
x{n,}
匹配至少 n 次 x(贪婪匹配) -
x{n}
精确匹配 n 次 x -
x{n,m}?
匹配至少 n 次 x,且至多 m 次 x(非贪婪/懒惰匹配) -
x{n,}?
匹配至少 n 次 x(非贪婪/懒惰匹配) -
x{n}?
精确匹配 n 次 x(非贪婪/懒惰匹配)
提示:在这里,贪婪匹配 意味着正则表达式会尽可能多地匹配,而 非贪婪/懒惰匹配 则会尽可能少地匹配
空匹配
以下是BT正则表达式中与空匹配相关的符号及其含义:-
^
匹配输入的开头(或在多行模式下匹配行的开头) -
$
匹配输入的结尾(或在多行模式下匹配行的结尾) -
\A
仅匹配输入的开头(即使启用了多行模式也只匹配整个文本的开头) -
\z
仅匹配输入的结尾(即使启用了多行模式也只匹配整个文本的结尾) -
\b
匹配 Unicode 单词边界(当一侧是单词字符 \w,另一侧是非单词字符 \W、\A 或 \z 时) -
\B
匹配非 Unicode 单词边界 -
\b{start}, \<
匹配 Unicode 单词开头边界(左侧为 \W 或 \A,右侧为 \w) -
\b{end}, \>
匹配 Unicode 单词结尾边界(左侧为 \w,右侧为 \W 或 \z) -
\b{start-half}
匹配半个 Unicode 单词开头边界(左侧为 \W 或 \A) -
\b{end-half}
匹配半个 Unicode 单词结尾边界(右侧为 \W 或 \z)
提示:这些符号常用于匹配位置或边界,而不是实际字符
分组与标志
在BT正则表达式中,可以使用以下语法来进行分组:-
(exp)
编号捕获组,捕获的内容会根据左括号的顺序进行编号(从 1 开始)。 -
(?P
或exp) (?
命名捕获组,同时也会被编号。组名必须是字母数字(a-z, A-Z, 0-9)。exp) -
(?:exp)
非捕获组,这种组只进行匹配但不会捕获结果。 -
(?flags)
在当前分组中设置标志(影响该分组内的匹配方式)。 -
(?flags:exp)
为特定的表达式 exp 设置标志,且该表达式为非捕获组。
ASCII 字符类
以下是基于 UTS#18 提供定义的 ASCII 字符类及其含义:-
[[:alnum:]]
字母数字字符(即 [0-9A-Za-z])。 -
[[:alpha:]]
字母字符(即 [A-Za-z])。 -
[[:ascii:]]
ASCII 字符(即 [\x00-\x7F],包括从 0 到 127 的所有 ASCII 字符)。 -
[[:blank:]]
空白字符(即 [\t ],包括水平制表符和空格)。 -
[[:cntrl:]]
控制字符(即 [\x00-\x1F\x7F],包括不可打印的控制字符)。 -
[[:digit:]]
数字字符(即 [0-9])。 -
[[:graph:]]
可见的图形字符(即 [!-~],包括除空格外的所有可打印字符)。 -
[[:lower:]]
小写字母(即 [a-z])。 -
[[:print:]]
可打印字符(即 [ -~],包括空格和所有可见的图形字符)。 -
[[:punct:]]
标点符号(即 [!-/:-@\[-{-~]`,包括标点和符号)。 -
[[:space:]]
空白字符(即 [\t\n\v\f\r ],包括制表符、换行符、垂直制表符、换页符、回车符和空格)。 -
[[:upper:]]
大写字母(即 [A-Z])。 -
[[:word:]]
单词字符(即 [0-9A-Za-z_],包括字母、数字和下划线)。
Unicode支持
Unicode 对内存使用和搜索速度的影响
该正则表达式库默认启用了对 Unicode 的全面支持,在大多数情况下,支持Unicode所需的额外内存开销是可以忽略的,并且通常不会影响搜索速度,但在某些情况下可能会有影响。关于内存使用:
Unicode 的影响主要体现在 Unicode 字符类的使用上。Unicode 字符类往往非常庞大。例如,默认的 \w 匹配大约 14 万个不同的代码点。这需要额外的内存,并可能使正则表达式的编译变慢。虽然偶尔使用 \w 影响不大,但如果你写了 \w{100},那么默认情况下将生成一个相当大的正则表达式。 例如,(?-u:\w) 的 ASCII 版本明显比 Unicode 版本小得多,所以如果你的需求可以通过 ASCII 满足,最好使用 ASCII 字符类。ASCII 版本的 \w 可以通过多种方式表示,以下都是等价的:-
[0-9A-Za-z_]
-
(?-u:\w)
-
[[:word:]]
-
[\w&&\p{ascii}]
关于搜索速度:
即使使用大型 Unicode 字符类,搜索速度通常也能很好地处理 Unicode。不过,一些更快的内部正则表达式引擎无法处理支持 Unicode 的单词边界断言。因此,如果你不需要 Unicode 感知的单词边界断言,建议使用(?-u:\b)
代替 \b
,前者使用 ASCII 版本的单词字符定义。
总之,虽然启用 Unicode 支持通常不会显著影响内存和性能,但在某些情况下使用 ASCII 类可以减少开销并提升性能。
BT语言的正则完全实现了 Unicode 技术标准 #18(UTS#18)中规定的“基本 Unicode 支持”(第一级)。
字符类 \w、\d 和 \s 默认都是支持 Unicode 的。使用 (?-u:\w)
(?-u:\d)
和 (?-u:\s)
可获得仅支持 ASCII 的定义。
类似的 \b 和 \B 使用 Unicode 定义的“单词”字符。若要获得仅支持 ASCII 的单词边界,可使用(?-u:\b)
和(?-u:\B)
。这同样适用于特殊的单词边界断言(即 \b{start}
、\b{end}
、\b{start-half}
、\b{end-half}
)。
在多行模式下,^ 和 $ 不支持 Unicode,也就是说,它们只识别 \n(假设未启用 CRLF 模式),而不会识别 Unicode 定义的其他行终止符形式。
大小写不敏感的搜索支持 Unicode 并使用简单的大小写折叠。
Unicode 的一般类别、脚本和许多布尔属性默认可通过 \p{property name}
语法使用。
在所有情况下,匹配的结果都使用字节偏移量报告,准确地说,是 UTF-8 编码单元的偏移量。这允许在常数时间内对文本进行索引和切片操作。
在BT中,默认情况下,正则匹配是 Unicode 感知的,这意味着它可能匹配的比你想象的要多。例如:\d
print "𝟚𝟘𝟙𝟘-𝟘𝟛-𝟙𝟜".match(/^\d{4}-\d{2}-\d{2}$/) // 输出 [𝟚𝟘𝟙𝟘-𝟘𝟛-𝟙𝟜]
要仅匹配 ASCII 十进制数字,以下所有内容都是等效的:
-
[0-9]
-
(?-u:\d)
-
[[:digit:]]
-
[\d&&\p{ascii}]
循环遍历
在 BT 脚本语言中,循环是遍历数据结构和控制流程的重要工具,BT 提供了三种循环类型:for、while 和 loop,每种循环都有其特定的使用场景,它们都支持continue
和 break
控制语句,同时也可以使用标签
来对嵌套循环进行更精细的控制。
For循环
在 BT 中,for 循环专门用于遍历数组或对象,主要通过for...in...形式。通过 for 循环,可以轻松地对数组或对象中的每一项进行操作。数组的遍历
arr = ['Lisa' 'Suci' 'Emerie'] for v in arr { println v } // 在上面的代码中,for 循环遍历了数组 arr,输出每一个元素的值: // Lisa // Suci // Emerie 同时获取键和值,这里的k和v是一个变量,你可以随意自定义,这里使用了key和value的首字母,for与in关键字之间如果存在一个变量,则为数组或对象的value,如果存在两个变量,则第一个变量为key(索引),第二个变量为value(值) for k,v in arr { println k + ' - ' + v } // 输出: // 0 - Lisa // 1 - Suci // 2 - Emerie对象的遍历
除了数组,for 循环也可以用来遍历对象: obj = { name1: 'Lisa' name2: 'Suci' name3: 'Emerie' } for v in obj { println v } // 输出对象中每一个属性的值: // Lisa // Suci // Emerie // 如果需要同时获取键和值: for k,v in obj { println k + ' - ' + v } // 输出键和值的组合: // name1 - Lisa // name2 - Suci // name3 - Emerie跳过循环项:continue
continue 可以用于跳过某一轮循环: for k,v in arr { if k == 1 { continue } println k + ' - ' + v } // 当 k == 1 时,循环跳过该轮输出,结果为: // 0 - Lisa // 2 - Emerie中断循环:break
break 用于提前终止循环: for k,v in arr { if k == 1 { break } println k + ' - ' + v } // 在 k == 1 时终止循环,输出: // 0 - Lisa标签:精确控制嵌套循环
通过使用标签,你可以更灵活地控制嵌套循环的终止和跳过。例如,使用break a
和continue b
来控制外层和内层循环:
arr = ['Lisa' 'Suci' 'Emerie']
list = ['Rita' 'maria' 'Jenna']
for:a k1,v1 in arr {
for:b k2,v2 in list {
if k1 == 1 {
break a
}
if k2 == 1 {
continue b
}
println v2
}
println v1
}
// 输出结果为:
// Rita
// Jenna
// Lisa
While 循环
while 循环会在指定条件为 true 时重复执行代码块。在 BT 中,while 循环同样支持 continue 和 break,并且可以使用标签来控制循环。 arr = ['Lisa' 'Suci' 'Emerie'] while arr.len() { println arr.shift() } // 上面的代码每次移除数组的第一个元素并打印,直到数组为空为止,输出: // Lisa // Suci // Emerie使用 continue 和 break
和 for 循环类似,while 循环可以使用 continue 跳过某一轮迭代,或使用 break 提前退出循环。 arr = ['Lisa', 'Suci', 'Emerie'] while arr.len() { if arr[0] == 'Suci' { arr.shift() continue } println arr.shift() } // 在这里,当数组的第一个元素为 'Suci' 时,跳过该轮输出。输出结果为: // Lisa // Emerie使用标签控制嵌套循环
while 循环也可以结合标签来控制多层循环: arr = ['Lisa', 'Suci', 'Emerie'] list = ['Rita', 'maria', 'Jenna'] while:a arr.len() { while:b list.len() { if arr[0] == 'Suci' { break a } if list[0] == 'maria' { list.shift() continue b } println list.shift() } println arr.shift() } // 输出: // Rita // Jenna // LisaLoop 循环
loop 是一个无限循环,除非显式地使用 break 来中断循环,否则它会无限执行下去。loop 循环也支持 continue 和标签。 arr = ['Lisa', 'Suci', 'Emerie'] loop { if arr.len() == 1 { break } println arr.shift() } // 在数组元素长度为 1 时,循环中断,输出: // Lisa // Suci使用 continue 和 break
你可以结合 continue 和 break 来控制循环的执行逻辑: arr = ['Lisa', 'Suci', 'Emerie'] loop { if arr.len() == 0 { break } if arr[0] == 'Suci' { arr.shift() continue } println arr.shift() } // 输出: // Lisa // Emerie使用标签控制嵌套的 loop
和其他循环一样,loop 循环也支持标签,用来控制多层循环的终止和跳过: arr = ['Lisa', 'Suci', 'Emerie'] list = ['Rita', 'maria', 'Jenna'] loop:a { loop:b { if arr[0] == 'Suci' { break a } if list[0] == 'maria' { list.shift() continue b } println list.shift() } println arr.shift() } // 输出: // Rita // Jenna // Lisa总结
BT 脚本中的三种循环 (for、while 和 loop) 各有其独特的用法,但它们都支持 continue 和 break 进行流程控制,并且可以通过标签来管理嵌套循环的执行。熟练掌握这些循环结构,可以让你的 BT 脚本更加高效、灵活。class类
每个类的定义都以关键字class
开头,后面跟着类名,里面包含有类的属性与方法的定义。
BT中的类没有指定的构造函数,因为类中的任何方法都可以成为构造函数
类的属性和方法默认情况下为私有,设为公共需添加pub
关键字
// 这是一个简单的类声明
class Article{
title = '月下相思'
content = '月色皎洁映纱窗,轻风拂面夜微凉,独坐幽篁思故人,琴声幽幽绕梁上,相思无尽何处诉,唯愿清风寄情长。'
time = '2020.12.12'
new(){
this.time = date('%Y-%m-%d')
return this
}
set_date(){
this.time = date('%Y-%m-%d %h-%i-%s')
}
pub get_title(){
this.title
}
pub get_content(){
this.content
}
pub set_title(title){
this.title = title
}
pub set_content(content='曾记花间共笑语,如今空余泪满眸'){
this.content = content
}
}
article = Article.new()
print article.get_title()
print article.set_title('花开花落')
print article.set_content('花开一季映日红,花落无声水自流')
date日期
在BT语言中,date
是一个内置的标准库,用于处理日期和时间。通过该库,你可以轻松地进行时间对象的创建、时间戳的获取、时间格式化的操作以及时间字符串的解析等。
以下是一个详细的教程,帮助你理解和使用date
库。
// 声明一个基于当前时间的时间对象
t = date()
print get_type(t) // 获取类型,输出:date
// 返回秒级时间戳
print t.secs() // 输出:1728387116
// 返回毫秒级时间戳
print t.millis() // 输出:1728387116794
// 返回微秒级时间戳
print t.micros() // 输出:1728387116794496
// 返回纳秒级时间戳
print t.nanos() // 输出:1728387116794496130
// 返回格式化的时间字符串
print t.format('%Y-%m-%d')
// 通过时间字符串更新时间对象,在BT中,能解析任何形式具有数字的字符串时间
// 常见形式的字符串解析
t.from_str('2024-09-15 06:30:50')
t.from_str('2024-09-15 06:30')
t.from_str('2024-09-15 06')
t.from_str('2024-09-15')
t.from_str('2024-09')
t.from_str('2024')
// 常见形式的字符串解析
t.from_str('2024-09-15 06:30:50')
t.from_str('15-2024-09 06:30:50')
t.from_str('15-09-2024 06:30:50')
t.from_str('50s 15-09-2024 06:30')
t.from_str('2024年09月15日 06时30分50秒')
// 不常见形式的字符串解析
t.from_str('这是年:2024 这是月:09 这是日:15')
// 通过时间戳更新当前时间对象
t.from_timestamp(1728386360)
print t.format('%Y-%m-%d') // 输出:2024-09-10
print t.from_timestamp(1726373550).format('%Y-%m-%d') // 输出:2024-09-15
from_str
函数解析字符串时间时,只解析数字串,然后根据年来定位,先确定年的位置,然后遵循下面规则进行解析,不存在的时间以0处理。
// 字母代表:Y年, m月, d日, h时, i分, s秒
(Y, m, d, h, i, s)
(d, Y, m, h, i, s)
(d, m, Y, h, i, s)
(s, d, m, Y, h, i)
(s, i, d, m, Y, h)
(s, i, h, d, m, Y)
file文件操作
在BT语言中file
是一个内置的标准库,用于处理文件和文件夹。通过该库,你可以轻松地进行文件的读写、重命名、复制以及删除等操作。以下是一个详细的教程,帮助你理解和使用file
库。
// 声明一个文件操作对象,相对定位基于当前程序运行目录
f = file('script/main.bt')
// 获取当前的文件路径
f.get_path()
// 读取文件内容
content = file('script/main.bt').read()
// 输出文件内容
print content
// 写入内容,会清空该文件的内容然后重新写入新内容
file('script/main.bt').write('hello')
// 头部追加内容,不会清空文件之前的内容
file('script/main.bt').prepend('hello')
// 尾部追加内容,不会清空文件之前的内容
file('script/main.bt').append('hello')
// 获取文件的字节数
file('script/main.bt').size()
// 重命名文件
file('script/main.bt').rename('script/hello.bt')
// 重命名文件夹
file('script/lib').rename('script/db')
// 复制文件
file('script/main.bt').copy('lib/main.bt')
// 复制文件夹
file('script').copy('lib')
// 删除文件
file('script/main.bt').delete()
// 删除文件夹
file('script').delete()
// 创建文件夹
file('script/lib').create_dir()
// 创建文件
file('script/main.bt').create_file()
// 创建文件并写入内容
file('script/main.bt').create_file('hello')
// 获得该文件夹下的文件列表,返回一个数组
list = file('script/lib').list()
for item in list{
// item是一个File类型对象
// 输出路径
println item.path()
}
// 是否为文件夹
file('script/lib').is_dir()
// 是否为文件
file('script/lib').is_file()
// 该路径是否为相对路径
file('script/lib').is_relative()
// 该路径是否为绝对路径
file('script/lib').is_absolute()
// 是否为一个符号链接
file('script/lib').is_symlink()
// 该文件或目录是否存在
file('script/lib').is_exists()
Web端函数变量
main.bt中如果WEB_SERVICE_OPEN = true启用后,会开启Web服务,此模式下,会额外支持一些专门针对Web开发的一些函数和变量,分别如下:header
设置web表头Content-Type
默认为text/html; charset=utf-8
,所以Web中无需设置
语法 header(header_info:Object)
header_info:必填,用于设置web的表头信息
// 页面重定向:使用 header()函数实现页面跳转,例如: header({Location: 'https://www.example.com'}) // 设置内容类型:例如,设置响应的内容类型为JSON: header({'Content-Type': 'application/json'}); // 防止页面缓存:可以通过设置响应头信息来禁止客户端缓存页面: header({ 'Cache-Control': 'no-cache, must-revalidate' 'Expires': 'Sat, 26 Jul 1997 05:00:00 GMT' }); // 文件下载:可以使用 header()函数来实现文件下载功能: header({ 'Content-Type': 'application/octet-stream' 'Content-Disposition': 'attachment; filename="example.zip"' 'Content-Length': file('example.zip').size() });status_code
设置web的状态码语法 status_code(code:Int)
code:必填,用于设置web的状态码
// 错误页状态 status_code(404)redirect
重定向语法 redirect(url:Str)
code:必填,用于设置web的状态码
// 跳转页面 redirect('/admin')url
获取网页的链接,不包含域名 // 访问 https://www.example.com/news/view?id=89 println url // 输出:/news/viewget
获取网页的get参数,Object类型 // 访问 https://www.example.com/news/view?id=89 println get // 输出:{id: 89} println get.id // 输出:89post
获取网页form表单传递的post参数,Object类型 // 前端页面 // <form action="https://www.example.com/news/view?id=89" method="POST"> // 用户:<input type="text" name="username" value="张三"/> // 密码:<input type="password" name="password" value="123456"/> // <button type="submit">提交</button > // </form> println post // 输出:{username: "张三", password: "123456"} println post.username // 输出:张三 println post.password // 输出:123456method
获取form表单类型,值:POST
或GET
// 前端页面
// <form action="https://www.example.com/news/view?id=89" method="POST">
// 用户:<input type="text" name="username" value="张三"/>
// 密码:<input type="password" name="password" value="123456"/>
// <button type="submit">提交</button >
// </form>
println method // 输出:POST
server
服务器信息,可以包含服务器的主机名或服务器软件的名称及其版本。例如,Apache服务器可能会返回类似 Apache/2.4.41 (Unix),表示使用的Web服务器和版本信息。这个信息通常出现在HTTP响应的 Server 头中。 服务器信息,包含以下字段:version:
这是HTTP协议的版本。例如,HTTP/1.1 或 HTTP/2。它指示客户端与服务器之间使用的协议版本,以确定如何格式化请求和响应。scheme:
这个字段表示使用的协议方案,通常是 http 或 https。它决定了传输层的安全性以及如何与服务器通信。headers:
HTTP请求或响应中的头信息。它是一个键值对集合,用于传递关于请求或响应的元数据,比如 Content-Type(表示内容类型)、User-Agent(标识发起请求的客户端)、Authorization(用于身份验证)、Host(请求目标的主机名)等。local_addr:
本地地址,指的是服务器监听的IP地址和端口号。它通常代表服务器端的IP地址,例如 127.0.0.1:80,用来识别服务器的网络接口。remote_addr:
远程地址,指的是客户端的IP地址和端口号,即发起请求的设备的地址。例如 192.168.1.100:54321。这可以用于识别和追踪请求的来源。 println server // 输出 { "method": "GET", "version": "HTTP/2.0", "scheme": "https", "headers": { "cache-control": "max-age=0", "sec-ch-ua": "\"Microsoft Edge\";v=\"129\", \"Not=A?Brand\";v=\"8\", \"Chromium\";v=\"129\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"Windows\"", "upgrade-insecure-requests": "1", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0", "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "sec-fetch-site": "none", "sec-fetch-mode": "navigate", "sec-fetch-user": "?1", "sec-fetch-dest": "document", "accept-encoding": "gzip, deflate, br, zstd", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "cookie": "BMAP_SECKEY=bqOcSjuJjrWIZwN9gp98gG89VznaBlacMsKuQaWK5weC_HJaOxrGgcl9sMQ1SMlPY9NxKNMi4K7GCt7sveMFIkU0HdNXii2fb7EkG_NTFf-PbszqNZ1uNsC-9DFbPuFHrmCCJr5KYTRt6dASpLc7bjkSo9SAtAGonRJMkZ_n49z-PJgpjJRPg1K7NX2H0iL_", "priority": "u=0, i" }, "local_addr": "socket://0.0.0.0:443", "remote_addr": "socket://127.0.0.1:57752" }常用函数
以下是BT语言中常用的函数:include
引用文件代码,类似PHP的include函数,常用于引入库或引入类。 提示:include中的代码作用域取决于引入的位置语法 include(file_path:Str)
file_path:必填,需引用的文件路径
demo.bt中的代码: name = 'Susan' main.bt中的代码: name = 'Lisa' // 引入demo.bt的代码 include(script/demo.bt) print name // 输出:Susan,变量name在demo.bt中发生了改变bool
将数据类型转为Bool类型语法 bool(data:Any)
data:必填,需转换的数据
println bool(null) // 输出:false println bool(0) // 输出:false println bool(1) // 输出:true println bool(19.99) // 输出:true println bool('hello') // 输出:true println bool([]) // 输出:false println bool(['yes']) // 输出:true println bool({}) // 输出:false println bool({name:'Lisa'}) // 输出:trueget_type
获取数据的类型语法 get_type(data:Any)
data:必填,需获取类型的数据
println get_type(null) // 输出:Null println get_type(0) // 输出:Int println get_type(19.99) // 输出:Float println get_type('hello') // 输出:Str println get_type(['yes']) // 输出:Array println get_type({name:'Lisa'}) // 输出:Object