#string #template #render-template #format-string #parser

bin+lib string-template-plus

具有更多选项的字符串模板渲染

22 个不稳定版本 (3 个破坏性更新)

0.4.3 2024年2月11日
0.4.2 2024年1月6日
0.3.7 2023年11月1日
0.3.6 2023年10月17日
0.1.6 2023年9月23日

#43 in 模板引擎

Download history 2/week @ 2024-05-18 4/week @ 2024-05-25 5/week @ 2024-06-01 1/week @ 2024-06-08 155/week @ 2024-06-29 168/week @ 2024-07-27 8/week @ 2024-08-03

176 每月下载量
用于 nadi_core

GPL-3.0-only

75KB
1.5K SLoC

string-template-plus

简介

这是一个简单的模板工具,它使用变量名和 HashMapString。可以从 [str] 解析 Template,然后您可以使用 HashMap 中的变量和通过 Exec 运行的任何 shell 命令来渲染它。

功能

  • 从易于编写的 str 解析模板
  • 支持可选变量,如果某些变量不存在,则使用 ? 分隔可选项,使用它找到的第一个。如果 ? 在末尾,则留空而不是报错。
  • 支持可选选项中的文字字符串,如果您想在末尾放置空字符串而不是空白,则可以使用包含在 "string" 中的文字字符串 " 作为可选项。
  • 支持使用 chrono 的日期时间格式,您可以在变量占位符 {} 内使用以 % 开头的任何格式,以使用 chrono 支持的日期时间格式。
  • 支持任何任意命令等。您可以将任何命令放在 $() 内部运行,并在模板中使用结果。您可以在其中使用其他格式元素。
  • 支持使用相同模板条件迭代(使用 -N 增量)字符串
  • 有限的格式化支持,如 UPCASE、downcase、float significant digits 等。有关更多信息,请参阅 transformers

用法

简单变量

#
let templ = Template::parse_template("hello {name}").unwrap();
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("name".into(), "world".into());
let rendered = templ
.render(&RenderOptions {
variables: vars,
..Default::default()
            })
            .unwrap();
assert_eq!(rendered, "hello world");

安全替换,如果不存在则留空,或者使用字面字符串

#
let templ = Template::parse_template("hello {name?} {lastname?\"User\"}").unwrap();
let vars: HashMap<String, String> = HashMap::new();
let rendered = templ
.render(&RenderOptions {
variables: vars,
..Default::default()
            })
            .unwrap();
assert_eq!(rendered, "hello  User");

替代,找到的第一个变量将被替换

#
let templ = Template::parse_template("hello {nickname?name}").unwrap();
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("name".into(), "world".into());
let rendered = templ
.render(&RenderOptions {
variables: vars,
..Default::default()
            })
            .unwrap();
        assert_eq!(rendered, "hello world");

计算可以写成类似于 lisp 的语言,它支持简单函数。使用 lisp 还可以使您编写更复杂的逻辑。lisp 的实现来自 https://github.com/brundonsmith/rust_lisp,有关功能请参阅那里的 README。

要访问 lisp 中的值,您可以使用以下函数

  • st+var : 将值作为字符串,
  • st+num 将值作为数字,以及
  • st+has 如果值存在则返回 true,否则返回 false。

您需要引用符号以传递给函数(例如 (st+num 'total))。

否则,您也可以像正常一样在花括号中写入变量。

#
let templ = Template::parse_template("hello {nickname?name}. You've done =(/ (st+num 'task_done) (st+num 'task_total)) work.").unwrap();
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("name".into(), "world".into());
vars.insert("task_done".into(), "1".into());
vars.insert("task_total".into(), "4".into());
let rendered = templ
.render(&RenderOptions {
variables: vars,
..Default::default()
            })
            .unwrap();
        assert_eq!(rendered, "hello world. You've done 0.25 work.");

自定义命令

#
let templ = Template::parse_template("L=$(printf \"%.2f\" {length})").unwrap();
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("length".into(), "12.342323".into());
let rendered = templ
.render(&RenderOptions {
wd: PathBuf::from("."),
variables: vars,
shell_commands: true,
            })
            .unwrap();
        assert_eq!(rendered, "L=12.34");

您可以选择关闭自定义命令以确保安全

#
let templ = Template::parse_template("L=$(printf \"%.2f\" {length})").unwrap();
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("length".into(), "12.342323".into());
let rendered = templ
.render(&RenderOptions {
wd: PathBuf::from("."),
variables: vars,
shell_commands: false,
            })
            .unwrap();
        assert_eq!(rendered, "L=$(printf %.2f 12.342323)");

日期和时间

#
let templ = Template::parse_template("hello {name} at {%Y-%m-%d}").unwrap();
let timefmt = Local::now().format("%Y-%m-%d");
let output = format!("hello world at {}", timefmt);
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("name".into(), "world".into());
let rendered = templ
.render(&RenderOptions {
wd: PathBuf::from("."),
variables: vars,
shell_commands: false,
            })
            .unwrap();
        assert_eq!(rendered, output);

转换器

尽管没有格式字符串,但有一些转换函数可以进行格式化。我计划根据需要添加更多格式函数。

要将转换器应用于变量,请在变量模板后提供它 VAR_TRANSFORM_SEP_CHAR(目前为 “:”)。

有几个可用的转换器

转换器 函数 参数 函数 示例
f 转换器::float_format [.]N 仅显示 N 位小数 {"1.12":f(.1)} ⇒ 1.1
case 转换器::string_case up 将字符串转换为大写 {"na":case(up)} ⇒ NA
case 转换器::string_case down 将字符串转换为小写 {"nA":case(down)} ⇒ na
case 转换器::string_case proper 将首字母转换为大写 {"nA":case(proper)} ⇒ Na
case 转换器::string_case title 将字符串转换为标题大小写 {"na":case(title)} ⇒ Na
calc 转换器::calc [+-*/^]N 算术计算 {"1":calc(+1*2^2)} ⇒ 16
calc 转换器::calc [+-*/^]N 算术计算 {"1":calc(+1,-1)} ⇒ 2,0
count 转换器::count str 计算字符串中 str 的出现次数 {"nata":count(a)} ⇒ 2
repl 转换器::replace str1,str2 将 str1 替换为 str2 {"nata":rep(a,o)} ⇒ noto
q 转换器::quote [str1] 使用 str1 引用,或 "" {"nata":q()} ⇒ "noto"
take 转换器::take str,N 通过 str 分隔 N 组 {"nata":take(a,2)} ⇒ "t"
trim 转换器::trim str 使用 str 去除字符串 {"nata":trim(a)} ⇒ "nat"

您可以将转换器依次链接以进行组合操作。例如,count( ):calc(+1) 将提供句子中单词的总数。

示例代码位于transformers中的各个函数中。

#
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("length".into(), "120.1234".into());
vars.insert("name".into(), "joHN".into());
vars.insert("job".into(), "assistant manager of company".into());
let options = RenderOptions {
variables: vars,
..Default::default()
        };
let cases = [
("L={length}", "L=120.1234"),
("L={length:calc(+100)}", "L=220.1234"),
("L={length:f(.2)} ({length:f(3)})", "L=120.12 (120.123)"),
("hi {name:case(up)}", "hi JOHN"),
(
 "hi {name:case(proper)}, {job:case(title)}",
 "hi John, Assistant Manager of Company",
),
 ("hi {name:case(down)}", "hi john"),
];

for (t, r) in cases {
 let templ = Template::parse_template(t).unwrap();
 let rendered = templ.render(&options).unwrap();
 assert_eq!(rendered, r);
 }

局限性

  • 在这个模板系统中,您不能使用位置参数,只能使用命名参数。代码{}将被替换为空字符串。尽管您可以使用"0""1"等作为模板和渲染选项变量的变量名,但最好保持名称标识符友好。
  • 虽然应该可以工作,但我没有测试过各种名称。
  • 目前没有格式说明符,现在您可以使用带有printf bash命令的命令选项来按照您想要的方式格式化内容,或者使用具有有限格式化功能的transformers。例如,模板this is $(printf "%05.2f" {weight}) kg.应该以正确的浮点格式渲染。

许可证:GPL-3.0-only

依赖关系

~4–15MB
~132K SLoC