跳到主要内容

基本用法

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

<基本类型>
BoolVal = true <布尔值>
IntVal1 = 1 <十进制整数>
IntVal2 = 1000'0000 <有引号的十进制整数>
IntVal3 = 0x5 <十六进制整数>
IntVal4 = 02 <八进制整数>
IntVal5 = 0b0 <二进制整数>
FloatVal = -1.0 <浮点数>
StrVal = "字符串" <字符串>

<列表>
StrList = ["1", "2", "3"] <字符串列表>
<不再多写...>

<组>
Group = {
SubVal = "子值" <子值>
SubGroup = {
SubVal = "子值" <子组子值>
}
} <普通组>
GroupList = [
{
SubVal = "组一子值"
} <组一>
{
SubVal = "组二子值"
} <组二>
] <组列表>

<赋值>
Value1 = StrVal <常规赋值>
Value2 = "字符串" <Value1>
<这里把注释给赋值了,注释的赋值只会生效于目标是字符串类型的情况,不会隐式转换>
List1 = [Value1, Value2] <常规列表赋值>
List2 = [List1] <列表赋值列表,会自动展开>
Group1.SubVal1 = Value1 <通过点连接组名赋值到子值>
Group2.SubVal = Group1.SubVal1 <用同样的方式赋值到另一个子值>
Group1 = {
SubGroup = {
SubVal2 = SubVal1 <展开赋值>
}
}
<赋值遵守就近原则,并且赋值的字符串将按原样存储>
<仅有常规赋值会保留原样,列表或注释中的赋值不会保留>

<拼接与类型提升>
StrVal1 = "字符串" + "字符串" <常规拼接>
StrVal2 = StrVal1 + true + 1 + 1.0 <所有非字符串基本类型进行拼接都会提升为字符串>
<解析时不会记录拼接的原样,所有拼接中的赋值都会丢失>
StrList1 = ["字符串" + "字符串"] <拼接在列表中也可用>
StrList2 = [StrVal1, StrList1, true, 1, 1.0] <在列表中也会提升类型为优先级最高的字符串>
FloatList1 = [true, 1, 1.0] <字符串之下是浮点数>
IntList1 = [true, 1] <浮点数之下是整数>
BoolList1 = [true] <整数之下只有布尔值了>
<组不支持拼接,列表也不支持拼接(因为已经支持在列表中展开其他列表了)>
<并且列表仅允许单一类型,组与基本类型不可以混合存储>

<分隔符>
Val1 = 1 <用换行省略了分号>
Val2 = 2 <显式的分号声明>;
ValList1 = [
1
2
3
] <用换行省略了逗号>
ValList2 = [
1,
2,
3,
] <显式的逗号声明(末尾是否有逗号不影响解析)>

<其他字符>
Key1: "Value" <冒号与等号等价>
Key2:"Value" <全角冒号同样可用>
IntVal = 1000’0000 <有全角引号的整数>
Say1 = "\"Hello\" “Hello”" <常规字符串>
Say2 = “"Hello" “Hello\”” <用全角引号包裹的字符串>
<可以看到转译也会因此改变>
Say3 = `
"Hello" “Hello”
` <用反引号包裹的原始字符串,解析时会去掉开头与结尾的空白,并且去掉最小缩进>
Grp = {Lst1 =[Key1, Key2];} <全角括号>
Lst2 = ["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 获取...

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