`
coding1688
  • 浏览: 236817 次
  • 来自: 上海
社区版块
存档分类
最新评论

当FreeMarker遇到正则表达式,Bug就出现了

 
阅读更多

当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();
    }
        
}
 

 

 

3
0
分享到:
评论

相关推荐

    怎么利用Java正则表达式换模板

    在实际开发中,除了直接使用正则表达式替换模板,还可以使用模板引擎库,如FreeMarker、Velocity或Thymeleaf等,它们提供了更高级的功能,如变量绑定、控制结构和函数调用,适合于生成动态HTML或其他格式的文档。...

    jsp学习详细资料(含有正则表达式)

    5. **模板引擎**:一些模板引擎如FreeMarker或Velocity,它们的配置或模板语法中也支持正则表达式,用于动态内容的处理。 这个压缩包很可能包含JSP的基本教程、实例代码、正则表达式的使用指南,甚至可能有实战项目...

    javaweb新浪微博邮箱登录界面,图书周排行榜界面,正则表达式验证用户注册页面前端代码资源包

    我们将深入探讨每个方面,同时引入正则表达式在验证用户输入中的应用。 首先,让我们看看"新浪微博邮箱登录界面"。这个界面通常会包含用户名(可以是手机号或邮箱)输入框、密码输入框、登录按钮,以及可能的记住...

    Java用正则表达式实现${name}形式的字符串模板实例

    正则表达式是实现这种字符串模板替换的一种有效方法。 在给定的实例中,`renderString` 方法演示了如何使用正则表达式和Java的 `Pattern` 和 `Matcher` 类来完成字符串模板的替换。以下是对这个方法的详细解释: 1...

    [js]一个只删除所有font标签的正则函数

    在探讨如何用JavaScript编写一个只删除所有font标签的正则函数之前,我们首先需要了解font标签和正则表达式的基础知识。 font标签是HTML早期用来定义字体样式、大小和颜色的一个元素。例如,`文字内容&lt;/font&gt;`。...

    freemarker 自定义freeMarker标签

    FreeMarker使用${...}表达式来插入变量,#{...}用于输出注释,以及、等控制结构进行条件判断和循环。然而,这些默认标签可能无法满足所有复杂的场景,因此自定义标签就显得尤为必要。 自定义FreeMarker标签通常涉及...

    struts结合js的表单验证

    ### Struts 结合 JS 的表单验证 在 Web 开发中,前端表单验证是非常重要的一个环节,它能够有效提高用户...同时,利用 JavaScript 的正则表达式功能,还可以方便地完成各种格式校验任务,从而提高应用程序的整体质量。

    文件写入,项目相对路径,java反射,模板数据写入

    它可能负责读取模板文件,使用正则表达式替换特定内容,然后利用反射操作和文件写入功能,将处理后的数据写入新的文件中。 总结来说,这个项目涉及了Java开发中的基础操作和高级特性,包括文件的读写、路径处理、...

    freemarker源码.rar

    解析过程涉及正则表达式、词法分析和语法分析等技术。 2. **数据模型与模板结合**:Freemarker的数据模型可以是任何Java对象,它将对象映射到模板中的变量。开发者可以通过`ModelFactory`将业务数据绑定到模板,...

    FreeMarker 2.3.18

    在`FreeMarker语法之表达式(一)`和`FreeMarker语法之表达式(二)`中,详细解释了各种类型的表达式,包括访问对象属性、数组和集合等。 - **遍历List**:在`Freemarker中如何遍历List.mht`中,会讲解如何使用`...

    非常好的Freemarker中文教程

    1. **基础概念**:Freemarker的工作原理,模板语言的基础元素,如变量、表达式、控制结构(if/else、foreach)以及注释等。 2. **数据模型**:理解如何将Java对象绑定到模板,包括基本类型、集合、Map等数据结构的...

    freemarker Demo 适用于freemarker初学

    Freemarker支持丰富的表达式,如`${user.name}`用来获取user对象的name属性,`&lt;@util.formatDate date='yyyy-MM-dd'/&gt;`调用自定义宏进行日期格式化。 8. **控制结构** Freemarker提供了条件语句(`&lt;#if&gt;`, `...

    freemarker-2.3.23jar

    `freemarker-2.3.23.jar`是Freemarker库的一个版本,发布于2.3.23,这个版本可能包含了对早期版本的一些改进、新功能或bug修复。 Freemarker的核心概念是模板语言,它是一种声明式的编程方式,允许开发者编写不包含...

    freemarker-2.3.28.jar

    当模板首次被请求时,Freemarker会将其编译成Java字节码并缓存,后续请求可以直接使用编译后的结果,减少不必要的解析和编译时间。 5. **错误处理与调试**: Freemarker提供了详细的错误报告,帮助开发者定位和修复...

    FreeMarker中文文档.pdf下载

    表达式是FreeMarker中用于获取数据值的方式。它们可以是简单的变量引用,也可以是函数调用或者更复杂的运算表达式。例如:`${user}`表示获取名为`user`的变量的值。 ### 三、FreeMarker的核心功能 #### 1. 模板...

    apache-freemarker-2.3.26

    4. **表达式**:FreeMarker支持丰富的表达式语法,包括算术表达式、比较表达式、逻辑表达式以及对对象方法的调用,这使得在模板中进行复杂的数据处理成为可能。 5. **缓存机制**:FreeMarker有内置的缓存系统,可以...

    freemarker各种版本的jar包

    - 更新可能修复了一些已知的bug,提高了整体稳定性。 3. **Freemarker 2.3.21**: - 进一步的性能改进可能在此版本中体现,比如更快的模板执行速度或者更小的内存占用。 - 可能扩展了API,增加了新的功能,比如...

    freemarker-2.3.22

    6. **错误处理**:当模板语法错误或数据模型问题出现时,Freemarker提供详细的错误报告,帮助开发者定位问题。 7. **API使用**:在Java代码中,开发者可以通过`Configuration`类配置Freemarker,并使用`Template`类...

    FreeMarker2.3.23官方中文文档

    1. **变量和表达式**:在FreeMarker模板中,`${}`内的内容是表达式,用于获取Java对象的属性或执行简单的运算。例如`${user.name}`将输出用户对象的name属性。 2. **指令**:FreeMarker提供了一系列的内置指令,如`...

    Freemarker官方帮助文档

    1. 错误信息:Freemarker在遇到错误时会提供详细的错误信息。 2. 开发者模式:开启开发者模式可以获取更多调试信息。 3. 输出调试:使用`&lt;#debug&gt;`指令打印数据模型内容。 总结,这份Freemarker官方帮助文档详细...

Global site tag (gtag.js) - Google Analytics