FreeMarker如果遇到正则表达式的时候会出现的bug

当FreeMarker遇到正则表达式

需求描述

在编制 FreeMarker 模板文件时,我有一个需求,简单描述如下:

将一个表达式(expr)进行分解成多个token,每个token要么是一个标识符、要么不是,比如

当 expr = "name" 时,只包含一个token,即 ["name"];

当 expr = "name||name2" 时,可分解成3个token,即 ["name", "||", "name2"];

当 expr 就是一个 token 时,有一些特殊处理。

 

有问题的实现

于是,在 ftl 文件中,这样写道:

 

 

Freemarker代码   收藏代码
  1. <#macro parseExpr1 expr>  
  2.         parse ${expr}  
  3.         <#assign tokens = expr?matches("[\\w]+|[^\\w]+")/>  
  4.         <#list tokens as token>  
  5.                 <#if tokens?size == 1>  
  6.                         [${token}]  
  7.                 <#else>  
  8.                         [${token}]  
  9.                 </#if>  
  10.         </#list>  
  11. </#macro>  
  12.   
  13. <@parseExpr1 expr="name"/>  
  14. <@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) 

 

如果注释掉第二个测试,就不会有问题。

 

 

Freemarker代码   收藏代码
  1. <@parseExpr1 expr="name"/>  
  2. <#-- <@parseExpr1 expr="name||name2"/> -->  

 

        parse name

                        [name]

 

 

也就是说,在 expr 能分解成多个 token 时,这种写法就会有问题。

 

无问题的实现

上面 tokens?size 是在循环中计算的,改成在循环外计算试试:

 

 

Freemarker代码   收藏代码
  1. <#macro parseExpr2 expr>  
  2.         parse ${expr}  
  3.         <#assign tokens = expr?matches("[\\w]+|[^\\w]+"), count = tokens?size/>  
  4.         <#list tokens as token>  
  5.                 <#if count == 1>  
  6.                         [${token}]  
  7.                 <#else>  
  8.                         [${token}]  
  9.                 </#if>  
  10.         </#list>  
  11. </#macro>  
  12.   
  13. <@parseExpr2 expr="name"/>  
  14. <@parseExpr2 expr="name||name2"/>  

 

 

 

输出结果如下:

        parse name

                        [name]

        parse name||name2

                        [name]

                        [||]

                        [name2]

 

 

这样就没有问题了。从逻辑上讲,两个实现其实是等同的。这应该是 FreeMarker 在处理正则表达式的时候出现了问题。

 

测试用的 java 代码

 

Java代码   收藏代码
  1. import freemarker.template.*;  
  2. import java.util.*;  
  3. import java.io.*;  
  4.           
  5. public class Test {  
  6.                           
  7.         public static void main(String[] args) throws Exception {  
  8.                           
  9.                 /* ------------------------------------------------------------------- */  
  10.                 /* You should do this ONLY ONCE in the whole application life-cycle:   */  
  11.       
  12.                 /* Create and adjust the configuration */  
  13.                 Configuration cfg = new Configuration();  
  14.                 cfg.setDirectoryForTemplateLoading(new File("templates"));  
  15.                 cfg.setObjectWrapper(new DefaultObjectWrapper());   
  16.           
  17.                 /* ------------------------------------------------------------------- */  
  18.                 /* You usually do these for many times in the application life-cycle:  */  
  19.                   
  20.                 /* Get or create a template */  
  21.                 Template temp = cfg.getTemplate("test.ftl");  
  22.           
  23.                 /* Create a data-model */  
  24.                 Map root = new HashMap();  
  25.   
  26.                 /* Merge data-model with template */  
  27.                 Writer out = new OutputStreamWriter(System.out);  
  28.                 temp.process(root, out);  
  29.                 out.flush();  
  30.     }  
  31.           
  32. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岩-悠然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值