Genex 生成表达式(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​Generate Expression)

介绍

    生成表达式(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​Generate Expression,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​简称:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​Genex或GE)是一款用于按照指定语法规则随机或固定生成数据的功能库。主要适用于依赖规则数据的应用场景,例如:应用测试、模板数据生成等。Genex基于伪随机的生成器,确保在规则和随机种子相同的前提下,生成一致的随机结果。

    Genex主要分为两个部分,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​即 GenexCGenexR,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​其中 GenexC 是规则编译器,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​负责将用户输入的规则文本编译为字节码。​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​字节码分为两种:1) 基于引用传递的内存数据;2) 基于字符串传递的字符串编码数据。使用 1) 可以避免字节码的转换过程,提高效率;使用 2) 则可以针对字符串进行特殊的加密。 GenexR 是规则运行时,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​负责基于字节码生成最终的输出数据。 GenexR 是基础运行时,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​其以 UInt32 为单元类型,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​以 String 为最终输出类型。​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​

    Genex的编译与运行是分离的。​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​如果需要的话,开发者可提前基于 GenexC 和规则编译出字节码,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​然后在应用中仅引入 GenexR 部分用于运行字节码。​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​这样的方式可以提高生成规则的安全性、减小程序的打包体积。

开源项目链接

项目特性

  • 跨平台

    Genex目前已包含C/C++、JS/TS、Cangjie三种语言实现,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​支持HarmonyOS Next、Windows、Linux、Mac、Android、IOS等诸多操作系统。

  • 一致性

    Genex不同语言版本、不同系统版本都有着一致的字节码,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​GenexR运行时确保在种子及步数一致的前提下,在不同平台上输出一致的伪随机结果。这样的设计有利于应用测试场景中对问题进行复现。

  • 扩展性

    Genex支持注册方法,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​以满足开发者自行扩展随机生成数据的需求。(开发者应确保依据扩展提供的随机函数和随机值生成确定的随机结果,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​以满足上一条特性)

基础学习

数据生成范围

  • Genex 编译器(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​GenexC)默认的范围是 [0,0x10FFFF]
  • Genex 基础运行时(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​GenexR)支持Unicode编码,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​即支持生成 [0,0x10FFFF] 范围的字符数据

值得注意的是:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​

  1. Genex 输出的字符数据不采用任何编码格式,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​例如:UTF-8,具体的编码转换由开发者基于输出数据进行
  2. GenenCGenenR 同时限定生成范围,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​例如:配置 GenenC 范围为 [0,C]GenenR 范围为 [0,R],​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​则最终生成的数据范围一定在 [0, MIN(C,R)]

优先级

优先级从高到低,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​较高优先级的运算符会优先被计算

  1. () [] <>
  2. + * ? {}
  3. |

语法内容

以下例子都以GenexCGenexR的默认配置为标准

  1. 点号:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​.

    表示在限定范围内随机生成1个字符
    
例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​. 可生成 a; 0; \; ; Ж; ; ; ; …

  2. 星号:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​*

    表示控制前方随机生成一定数量的内容(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​默认生成数量范围为[0,10],​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​通过配置 GenenC 可修改此MAX范围)
    
例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​A* 可生成 \0; A; AA; AAA; …
    
例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​.* 可生成 \0; a; 00; \\\; 你你你你; …

  3. 加号:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​+

    表示控制前方随机生成一定数量的内容(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​默认生成数量范围为[1,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​10])
    (​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​值得注意的是:代码中配置 * 的最大生成数量MAX,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​对 + 也生效)

  4. 问号:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​?

    表示控制前方随机生成一定数量的内容(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​默认生成数量范围为[0,1])

  5. 重复执行区间:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​{n,m}

    重复执行区间会让前部分的生成过程被重复生成,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​本部分支持的写法如下:

    • {m} 表示生成范围为 [m,m]
    • {,m} 表示生成范围为 [0,m]
    • {n,} 表示生成范围为 [n,MAX]
    • {n,m} 表示生成范围为 [n,m]

    例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​1{1,10}就代表随机生成[1,10]个字符1

    (​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​值得注意的是:当{n,m}前方为自身时,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​则是对内容进行重复。例如:[ab]{1,1}{2,3}则代表会先生成1个ab然后重复[2,3]次生成的结果,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​最终结果可能是:aaaaabbbbb

  6. 数值范围生成:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​<n,m>

    数值生成范围部分不支持简写,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​
    
其中 n 为 小值,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​ m 为大值,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​允许的数值范围为 无符号32位整形

    例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​<10,32>就表示随机生成[10,32]区间内的数值

  7. 普通转义符:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​\t; \n; \v; \f; \r; \\;

    分别转义为:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​

    • 水平制表符 (​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​0x09)
    • 回车符 (​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​0x0A)
    • 垂直制表符 (​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​0x0B)
    • 换页符 (​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​0x0C)
    • 换行符 (​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​0x0D)
    • 反斜杠 (​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​0x5C)
  8. 范围转义符:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​\w; \W; \d; \D; \s; \S;

    分别转义为:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​

    • [A-Za-z0-9_]
    • [^A-Za-z0-9_]
    • [0-9]
    • [^0-9]
    • [\f\n\r\t\v]
    • [^\f\n\r\t\v]
  9. 进制转义符:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​\x********

    表示使用16进制描述一个字符,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​范围[\x0,\xFFFFFFFF]
    (​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​值得注意的是:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​\x后支持0-9A-Fa-f进行描述,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​当后方字符非范围内,或者范围内字符长度大于8时自动截断)
    
例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​\x61 可生成 a;
    
例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​\x61q 可生成 aq;
    
例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​\x000000611 可生成 a1;

  10. 范围描述区间:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​[...]

    整个[...]会被视为一个文本范围,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​表示只能生成此范围内的字符串
    
例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​[ab] 可生成 ab;

  11. 范围号:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​-

    此符号仅在[...]内有效,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​用于表示两个字符之间的所有字符(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​闭区间)
    
例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​[a-z] 可生成 a; b; c; d; … z;
    
例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​[0-9] 可生成 0; 1; 2; 3; … 9;

  12. 取反号:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​^

    此符号仅在[...]内的开头位置有效,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​用于表示反转整个范围描述区间
    
例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​[^\x0-\x127] 则含义意同 [\x128-\x10FFFF]

  13. 子表达式区间:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​(...)

    (...)囊括的所有内部语句将被视为一个整体

  14. 或号:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​|

    表示随机执行左右一侧的子表达式
    
例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​1|2 可生成 12;

  15. 调用描述区间:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​<...>

    有时候现有的语法无法满足生成的需求,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​为了便于扩展设计了<...>
    <...>内部以,分隔,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​第一个部分为调用函数名,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​后续皆为参数
    
例如:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​<time,-> 表示调用名为time的函数,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​并且传入一个参数-
    (​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​值得注意的是:所有参数都是字符串常量,不会被解析为规则文本。在扩展的调用方法中可访问到前向生成的结果数据,通过前向数据可以实现更为复杂的数据生成)

使用说明

编译构建(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​仓颉版本)

(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​注‘ RGF提供Build.​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​bat进行自动化编译,编译结果自动置入Build文件夹中。​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​使用自动化脚本前,请确保已经完整安装Cangjie编译环境,并且正确配置环境变量)

Genex 功能示例(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​仓颉版本)

  1. 引入Genex库

    示例代码如下:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​

    import genex.compiler.{ GenexC }
    import genex.runtime.{ GenexR }
    import genex.utile.{ u32string2String }
    // 或者全量引入也可
    import genex.*
  2. 编译并输出结果

    示例代码如下:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​

    // 编译生成表达式
    let gc:GenexC = GenexC("([a-z];){1}{3}");
    // 确认无错误
    if(gc.getError().size == 0){
        // 基于编译的字节码构建运行时
        let gr:GenexR = GenexR(gc.getStrCode());
        // 输出结果
        println(u32string2String(gr.generate()))
    }

    执行结果如下:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​

    i;i;i;
    分解如下:
    ([a-z];)  {1} 生成一次
    [a-z] 生成 i
    i 加上 ;
    i;  {3} 重复三次,生成最终结果
    i;i;i;

约束与限制

  • Genex(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​Cangjie 版本)基于 Cangjie 开发,理论支持所有Cangjie目标平台

  • Genex(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​JS/TS 版本)基于 TS 开发,理论支持所有JS运行环境

  • Genex(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​C++ 版本)基于 GNU C++ 开发,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​最低需使用 C++ 11 编译,理论支持所有C++目标平台

(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​注’ 以上各版本自身还区分32位版本和64位版本)

首版作者信息

(​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​添加请备注:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​“Genex”)

@QQ :​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​2874148643

@E-mail:​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​ 2874148643@qq.​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​com

参与贡献

欢迎大家提交PR、Issue,​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​欢迎大家参与任何形式的贡献。​‌‎​​‌‎​‌​‎‌‌​​‎​‌‌‌‎‌‌‌‌‌‎‌​‌‌‎‌​​‌‎​