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

当FreeMarker遇到正则表达式

需求描述

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

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

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

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

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

有问题的实现

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

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

parse name

[name]

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

无问题的实现

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

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

输出结果如下:

parse name

[name]

parse name||name2

[name]

[||]

[name2]

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

测试用的 java 代码

Java代码 收藏代码
  1. importfreemarker.template.*;
  2. importjava.util.*;
  3. importjava.io.*;
  4. publicclassTest{
  5. publicstaticvoidmain(String[]args)throwsException{
  6. /*-------------------------------------------------------------------*/
  7. /*YoushoulddothisONLYONCEinthewholeapplicationlife-cycle:*/
  8. /*Createandadjusttheconfiguration*/
  9. Configurationcfg=newConfiguration();
  10. cfg.setDirectoryForTemplateLoading(newFile("templates"));
  11. cfg.setObjectWrapper(newDefaultObjectWrapper());
  12. /*-------------------------------------------------------------------*/
  13. /*Youusuallydotheseformanytimesintheapplicationlife-cycle:*/
  14. /*Getorcreateatemplate*/
  15. Templatetemp=cfg.getTemplate("test.ftl");
  16. /*Createadata-model*/
  17. Maproot=newHashMap();
  18. /*Mergedata-modelwithtemplate*/
  19. Writerout=newOutputStreamWriter(System.out);
  20. temp.process(root,out);
  21. out.flush();
  22. }
  23. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值