killme2008 / aviatorscript

A high performance scripting language hosted on the JVM.
http://fnil.net/aviator/
4.47k stars 833 forks source link

利用“字符串插值”特性替代模板引擎时出现问题,请教 #620

Closed missfmaster closed 6 months ago

missfmaster commented 6 months ago

请问: 想利用字符串插值,实现类似模板引擎的功能,即: 在库中配置模板串: 小明说:"#{name},你好"。 提供name后,可以得到: 小明说:“张三,你好”。

现在存在的问题是: 将模板串从库中取出来后,进行编译: engine.compile(expression); 得到以下报错: Exception in thread "main" com.googlecode.aviator.exception.ExpressionSyntaxErrorException: Syntax error: unexpect token '小明说', maybe forget to insert ';' to complete last expression at 4, lineNumber: 1, token : [type='variable',lexeme='小明说',index=0], while parsing expression: 小明说:^^^`

原因是,库中配置的串,前后没有引号,所以,引擎无法识别其是字符串。 但是如果通过代码在前后添加单引号或者双引号,又会涉及到模板串内引号的转义问题。

请问,这种情况有好的处理办法吗?

方案一:在库中配置时,手动添加引号的方式;(排除) 方案二:手动写代码去前后添加引号,然后将模板串内的引号转义; 方案三:Aviator中有相应的处理方案吗?

killme2008 commented 6 months ago

不是很明白问题是什么? 能给一段模版示例?

missfmaster commented 6 months ago

不是很明白问题是什么? 能给一段模版示例?

// 比如,下边的表达式是从库中配置的
 String expression = "带有插值的字符串:#{name}";
 // 使用引擎进行编译
engine.compile(expression);

会出现:

Exception in thread "main" com.googlecode.aviator.exception.ExpressionSyntaxErrorException: Syntax error: unexpect token '这是一个带有插值的字符串', maybe forget to insert ';' to complete last expression  at 13, lineNumber: 1, token : [type='variable',lexeme='这是一个带有插值的字符串',index=0],
while parsing expression: `
这是一个带有插值的字符串:^^^
`

需要修改成:

String expression = "\"带有插值的字符串:#{name}\"";
Expression exp = engine.compile(expression);

才能通过编译。

可是,如果让用户手动在前后添加引号,不是太好; 程序自动添加引号,又会涉及到表达式内部存在引号需要转义的问题:

String expression = "带有插值的\"字符串\":#{name}";

需要转成:

String expression = "\"带有插值的\\\"字符串\\\":#{name}\"";

才能通过编译,处理起来挺复杂,尤其是插值内也是表达式的情况:

String expression = "带有插值的\"字符串\":#{name + \"_X\"}";

需要处理成:

String expression = "\"带有插值的\\\"字符串\\\":#{name + \\\"_X\\\"}\"";

:(

killme2008 commented 6 months ago

这在统一的 compile 入口去加下引号不就行了?

missfmaster commented 6 months ago

这在统一的 compile 入口去加下引号不就行了?

可以的,但是表达式内如果存在引号,需要对其进行转义,处理起来挺复杂。

从源码中找到了一种方案:

StringSegments ss = engine.compileStringSegments(expression2);
System.out.println("结果:" + ss.toString(map, expression2));

经过测试耗时甚至比

Expression exp = engine.compile(expression);
 System.out.println("结果:" + exp.execute(map));

更短,:)

感谢回答。:):):)

killme2008 commented 6 months ago

是的,可以用这种办法。