跳到主要内容

基本用法

FVV 全称 Fresh View for Viewer,是一个较为简单易上手的语言,名字显而易见,是个 废物 清新 的文本格式,那么有多清新呢,请看示例

Val1 = "FVV\"" <字符串转义与注释转义\>>
Val2 = true <布尔值>
Val3 = 2006 <整数>
Val4 = 2006.06 <浮点数>

Val5 = ["FVV", "FW"] <字符串组>
Val6 = [2, 0, 0, 6,] <整数组(这个“,”是故意多打的)>
Val7 = [Val5, Val6] <字符串组(值组赋值默认跟随第一个值的类型)>
Val8 = <FVV值组嵌套> [
{
Val9 = "FVV"
Val10 = <FVV值组> [
<FVV值组子值> {
Val11 = "FW"
}
{
Val12 = "FW"
}
]
}
]

Group = {
Sub = {
a = Val3 <跨组赋值>
} <子组>
c = Sub.a <跨组赋值>
} <组>

Group.Sub.b = a <同组赋值,支持用“.”连接组名>
Group.Sub.b = Group.Sub.a <同组赋值,用“.”表示了完整名称>

Desc = "这是描述"
Value = "这是值" <Desc>
<Value的描述是通过赋值Desc实现的,这样Value的描述将会是“这是描述”>

显而易见,支持字符串布尔值整数浮点数以及它们的的定义,还有 FVV 本身的,还支持值组以及赋值

提示

FVV 本身在实现方面有部分缺陷,对转义的判断仅为当当前符号是特定符号时(例如 ">), 判断其上一个字符是否为 \,并没有很完善的转义判断,故仅支持转义 ">(即 "\""<\>>), 不支持 \n 等转义,直接使用 \ 时不需要 \\,直接 \ 即可(因此字符串或注释的末尾不可以是 \

值的命名也是没有什么忌口的,但需要注意的是, 如果一个值被命名为纯数字(仅 整数,因为 浮点数 会被分割为双层组), 那么这个值将无法用于赋值,因为没法判断到底给的是值还是值的名称

同样的,还需要注意正常命名不要带 . 啊喂,会被认为是多层组的定义的

值的定义使用 ;换行 进行, 所有的值都可以置于根路径的 {} 里面(放不放都没区别,只不过加一个 {} 看起来类 JSON 一点), 块注释使用 <>,没有行注释

提示

换行 可以省略掉以下字符:

  • ;: 当定义值时有 换行 则无需在行尾添加 ;
  • ,: 当定义组时有 换行 则无需在两个值之间添加 ,

注释是 FVV 一个比较特色的功能,它可以放到任何地方,请看示例:

<注释>{<注释>a<注释>=<注释>1<注释>;<注释>}<注释>

可以非常直接地看出来,注释完全是想怎么写就怎么写,但是它的作用不止于此

介于 =;(或 换行)之间的最后一个注释,将会被认定为是该值的 描述,在解析时将会被留存为该值的附属值

注意

因为 换行 可以替代 ;描述 又是和定义一样通过 换行/; 来解析的, 所以 描述 不可以写到定义的下一行

备注

为了让 FWW 有更好的开发体验,FVV 值组 及其子值的 描述 是放在前面的

提示

描述 是支持赋值的,也就是说任意字符串都有可能赋值到 描述 上,只要 描述 与该字符串的值名称相同

所以在实践中,建议在编写 描述 时,在开头加一个 - ,从而实现类似于 <- 这是注释> 的效果, 如果字体支持,<- 会变成一个好看的箭头,这样既不会与赋值机制有冲突,还可以提升观感

代码层使用方法

提示

仅支持 UTF-8 文本(或 UTF-8 with BOM),由于各种语言实现的差异,不确保所有语言均可正常解析所有文本

解析时会把所有 \r\n 替换为 \n,把所有 \r 替换为 \n (即强制将文本转换为 LF 文本)

引入依赖

在项目中添加文件后,直接 #include 即可:

#include "fvv.hh"

基本功能

首先当然是解析

提示

由于 Go 的语言特性,其函数名称不得不大写

由于 DartGo 不支持函数重载,为了保证长期维护的可能性,额外添加了 String 后缀

FVV::FVVV fvv;
fvv.parse(txt);

然后是格式化成字符串,当传入以下内容时,会有不同的格式化效果:

  • Common: 默认
  • Min: 格式化后的文本将去掉任何符号间的空格缩进换行(替换成 ;)、描述
  • BigList: 格式化后的文本中的任何组都会被展开为一行一值
  • NoDesc: 格式化后的文本不再有任何描述
备注

各个语言的格式化选项位置如下:

  • C++: FVV::FormatOpt
  • Dart: FVVFormatOpt
  • Go: 以 FmtOpt 开头的值,调用时需要通过 PrintOpt 传入
  • Kotlin: FVVV.Companion.FormatOpt

不同的语言在命名上略有不同,但实际行为一致

important

FVV 值组描述 在 FWW 中是页面标题,在 MinNoDesc 中不会被去除

其内部的 FVV 值描述 则是其组件类型,同样也不会被去除

提示

一切去除描述的行为均仅为在输出的字符串中去除,不会影响到代码中的描述

string fvv_str = fvv.print();

然后是对值的基本判断

备注

由于 Go 的语法可用性太低了,便又封装了 SubIsEmptySubIsNotEmpty 来判断子项是否为空, 但使用前最好还是先判断一下值本身是否为 nil

由于写 Kotlin 时语法基本上照抄 Dart,所以 isEmptyisNotEmpty 是通过 getter 获取的

bool is_empty = fvv.isEmpty() && !fvv.isNotEmpty(); // 判断是否为空
bool is_type = fvv.isType<T>(); // 判断类型

然后是读取值

提示

由于 Go 的语法实现这些有点麻烦,所以请自行使用 .(T) 来获取值吧

由于 Dart 机制,常规获取 List 类型得到的是拷贝,有 Ref 后缀的函数获取到的才是引用

备注

由于 JVM 机制,在 Kotlin 获取 List 类型的方法有点抽象...,在 Kotlin 获取到的是拷贝

auto value = fvv.as<T>(); // 指定类型获取
string str = fvv.asString(); // 获取字符串
vector<string> strs = fvv.asStrings(); // 获取字符串组
// 其他依此类推,不再示范
备注

由于 Dart 的基本类型名称会冲突,所以没在它上面实现 getter 获取...

赋值只需要在有重写运算符功能的语言上直接赋值即可,没有则需要手动调用内部的值进行赋值