当FreeMarker遇到正则表达式
需求描述
在编制 FreeMarker 模板文件时,我有一个需求,简单描述如下:
将一个表达式(expr)进行分解成多个token,每个token要么是一个标识符、要么不是,比如
当 expr = "name" 时,只包含一个token,即 ["name"];
当 expr = "name||name2" 时,可分解成3个token,即 ["name", "||", "name2"];
当 expr 就是一个 token 时,有一些特殊处理。
有问题的实现
于是,在 ftl 文件中,这样写道:
<#macro parseExpr1 expr>
parse ${expr}
<#assign tokens = expr?matches("[\\w]+|[^\\w]+")/>
<#list tokens as token>
<#if tokens?size == 1>
[${token}]
<#else>
[${token}]
</#if>
</#list>
</#macro>
<@parseExpr1 expr="name"/>
<@parseExpr1 expr="name||name2"/>
上面的代码在执行时会有异常抛出:
Exception in thread "main" java.lang.IllegalStateException: No match available
at java.util.regex.Matcher.start(Matcher.java:325)
at freemarker.core.RegexBuiltins$RegexMatchModel$Match.<init>(RegexBuiltins.java:350)
at freemarker.core.RegexBuiltins$RegexMatchModel$2.next(RegexBuiltins.java:339)
at freemarker.core.IteratorBlock$Context.runLoop(IteratorBlock.java:164)
at freemarker.core.Environment.visit(Environment.java:428)
at freemarker.core.IteratorBlock.accept(IteratorBlock.java:102)
at freemarker.core.Environment.visit(Environment.java:221)
at freemarker.core.MixedContent.accept(MixedContent.java:92)
at freemarker.core.Environment.visit(Environment.java:221)
at freemarker.core.Macro$Context.runMacro(Macro.java:172)
at freemarker.core.Environment.visit(Environment.java:614)
at freemarker.core.UnifiedCall.accept(UnifiedCall.java:106)
at freemarker.core.Environment.visit(Environment.java:221)
at freemarker.core.MixedContent.accept(MixedContent.java:92)
at freemarker.core.Environment.visit(Environment.java:221)
at freemarker.core.Environment.process(Environment.java:199)
at freemarker.template.Template.process(Template.java:259)
at Test.main(Test.java:28)
如果注释掉第二个测试,就不会有问题。
<@parseExpr1 expr="name"/>
<#-- <@parseExpr1 expr="name||name2"/> -->
parse name
[name]
也就是说,在 expr 能分解成多个 token 时,这种写法就会有问题。
无问题的实现
上面 tokens?size 是在循环中计算的,改成在循环外计算试试:
<#macro parseExpr2 expr>
parse ${expr}
<#assign tokens = expr?matches("[\\w]+|[^\\w]+"), count = tokens?size/>
<#list tokens as token>
<#if count == 1>
[${token}]
<#else>
[${token}]
</#if>
</#list>
</#macro>
<@parseExpr2 expr="name"/>
<@parseExpr2 expr="name||name2"/>
输出结果如下:
parse name
[name]
parse name||name2
[name]
[||]
[name2]
这样就没有问题了。从逻辑上讲,两个实现其实是等同的。这应该是 FreeMarker 在处理正则表达式的时候出现了问题。
测试用的 java 代码
import freemarker.template.*;
import java.util.*;
import java.io.*;
public class Test {
public static void main(String[] args) throws Exception {
/* ------------------------------------------------------------------- */
/* You should do this ONLY ONCE in the whole application life-cycle: */
/* Create and adjust the configuration */
Configuration cfg = new Configuration();
cfg.setDirectoryForTemplateLoading(new File("templates"));
cfg.setObjectWrapper(new DefaultObjectWrapper());
/* ------------------------------------------------------------------- */
/* You usually do these for many times in the application life-cycle: */
/* Get or create a template */
Template temp = cfg.getTemplate("test.ftl");
/* Create a data-model */
Map root = new HashMap();
/* Merge data-model with template */
Writer out = new OutputStreamWriter(System.out);
temp.process(root, out);
out.flush();
}
}
分享到:
相关推荐
在实际开发中,除了直接使用正则表达式替换模板,还可以使用模板引擎库,如FreeMarker、Velocity或Thymeleaf等,它们提供了更高级的功能,如变量绑定、控制结构和函数调用,适合于生成动态HTML或其他格式的文档。...
5. **模板引擎**:一些模板引擎如FreeMarker或Velocity,它们的配置或模板语法中也支持正则表达式,用于动态内容的处理。 这个压缩包很可能包含JSP的基本教程、实例代码、正则表达式的使用指南,甚至可能有实战项目...
我们将深入探讨每个方面,同时引入正则表达式在验证用户输入中的应用。 首先,让我们看看"新浪微博邮箱登录界面"。这个界面通常会包含用户名(可以是手机号或邮箱)输入框、密码输入框、登录按钮,以及可能的记住...
正则表达式是实现这种字符串模板替换的一种有效方法。 在给定的实例中,`renderString` 方法演示了如何使用正则表达式和Java的 `Pattern` 和 `Matcher` 类来完成字符串模板的替换。以下是对这个方法的详细解释: 1...
在探讨如何用JavaScript编写一个只删除所有font标签的正则函数之前,我们首先需要了解font标签和正则表达式的基础知识。 font标签是HTML早期用来定义字体样式、大小和颜色的一个元素。例如,`文字内容</font>`。...
FreeMarker使用${...}表达式来插入变量,#{...}用于输出注释,以及、等控制结构进行条件判断和循环。然而,这些默认标签可能无法满足所有复杂的场景,因此自定义标签就显得尤为必要。 自定义FreeMarker标签通常涉及...
### Struts 结合 JS 的表单验证 在 Web 开发中,前端表单验证是非常重要的一个环节,它能够有效提高用户...同时,利用 JavaScript 的正则表达式功能,还可以方便地完成各种格式校验任务,从而提高应用程序的整体质量。
它可能负责读取模板文件,使用正则表达式替换特定内容,然后利用反射操作和文件写入功能,将处理后的数据写入新的文件中。 总结来说,这个项目涉及了Java开发中的基础操作和高级特性,包括文件的读写、路径处理、...
解析过程涉及正则表达式、词法分析和语法分析等技术。 2. **数据模型与模板结合**:Freemarker的数据模型可以是任何Java对象,它将对象映射到模板中的变量。开发者可以通过`ModelFactory`将业务数据绑定到模板,...
在`FreeMarker语法之表达式(一)`和`FreeMarker语法之表达式(二)`中,详细解释了各种类型的表达式,包括访问对象属性、数组和集合等。 - **遍历List**:在`Freemarker中如何遍历List.mht`中,会讲解如何使用`...
1. **基础概念**:Freemarker的工作原理,模板语言的基础元素,如变量、表达式、控制结构(if/else、foreach)以及注释等。 2. **数据模型**:理解如何将Java对象绑定到模板,包括基本类型、集合、Map等数据结构的...
Freemarker支持丰富的表达式,如`${user.name}`用来获取user对象的name属性,`<@util.formatDate date='yyyy-MM-dd'/>`调用自定义宏进行日期格式化。 8. **控制结构** Freemarker提供了条件语句(`<#if>`, `...
`freemarker-2.3.23.jar`是Freemarker库的一个版本,发布于2.3.23,这个版本可能包含了对早期版本的一些改进、新功能或bug修复。 Freemarker的核心概念是模板语言,它是一种声明式的编程方式,允许开发者编写不包含...
当模板首次被请求时,Freemarker会将其编译成Java字节码并缓存,后续请求可以直接使用编译后的结果,减少不必要的解析和编译时间。 5. **错误处理与调试**: Freemarker提供了详细的错误报告,帮助开发者定位和修复...
表达式是FreeMarker中用于获取数据值的方式。它们可以是简单的变量引用,也可以是函数调用或者更复杂的运算表达式。例如:`${user}`表示获取名为`user`的变量的值。 ### 三、FreeMarker的核心功能 #### 1. 模板...
4. **表达式**:FreeMarker支持丰富的表达式语法,包括算术表达式、比较表达式、逻辑表达式以及对对象方法的调用,这使得在模板中进行复杂的数据处理成为可能。 5. **缓存机制**:FreeMarker有内置的缓存系统,可以...
- 更新可能修复了一些已知的bug,提高了整体稳定性。 3. **Freemarker 2.3.21**: - 进一步的性能改进可能在此版本中体现,比如更快的模板执行速度或者更小的内存占用。 - 可能扩展了API,增加了新的功能,比如...
6. **错误处理**:当模板语法错误或数据模型问题出现时,Freemarker提供详细的错误报告,帮助开发者定位问题。 7. **API使用**:在Java代码中,开发者可以通过`Configuration`类配置Freemarker,并使用`Template`类...
1. **变量和表达式**:在FreeMarker模板中,`${}`内的内容是表达式,用于获取Java对象的属性或执行简单的运算。例如`${user.name}`将输出用户对象的name属性。 2. **指令**:FreeMarker提供了一系列的内置指令,如`...
1. 错误信息:Freemarker在遇到错误时会提供详细的错误信息。 2. 开发者模式:开启开发者模式可以获取更多调试信息。 3. 输出调试:使用`<#debug>`指令打印数据模型内容。 总结,这份Freemarker官方帮助文档详细...