【问题标题】:Resolving variables inside a Coldfusion string解析 Coldfusion 字符串中的变量
【发布时间】:2009-12-09 02:27:30
【问题描述】:

我的客户有一个电子邮件正文的数据库表,这些电子邮件正文会在特定时间发送给客户。电子邮件的文本包含 ColdFusion 表达式,例如 Dear #firstName# 等。这些电子邮件是 HTML - 它们还包含各种 HTML 标记。我想做的是将数据库中的文本读入一个字符串,然后让 ColdFusion Evaluate() 该字符串解析变量。当我这样做时, Evaluate() 会引发异常,因为它不喜欢其中的 HTML 标记(我还尝试通过 HTMLEditFormat() 过滤字符串作为笑声的中间步骤,但它不喜欢其中的实体) .

我的前任通过将电子邮件文本写入文件然后 cfinclude 解决了这个问题。有用。不过,这似乎真的很hacky。有没有更优雅的方法来处理这个问题,比如我没有看到的 Evaluate?

【问题讨论】:

  • 我想指出,将其写入 FS 或使用 Evaluate() 允许执行任何和所有代码。如果不小心处理,这可能会导致安全问题。我会选择@kevink 的每个变量替换。
  • 同意本。评估工作正常,直到您每秒收到如此多的请求以致 CF 给出错误。到目前为止,我发现替换是最好的方法。

标签: coldfusion


【解决方案1】:

其他语言经常做的似乎工作得很好的就是在你的模板中有某种标记,可以很容易地被正则表达式替换。所以你可能有一个像这样的模板:

Dear {{name}}, Thanks for trying {{product_name}}.  Etc...

然后你可以简单地:

<cfset str = ReplaceNoCase(str, "{{name}}", name, "ALL") />

当你想变得更漂亮时,你可以写一个方法来包装它:

<cffunction name="fillInTemplate" access="public" returntype="string" output="false">
    <cfargument name="map" type="struct" required="true" />
    <cfargument name="template" type="string" required="true" />

    <cfset var str = arguments.template />
    <cfset var k = "" />

    <cfloop list="#StructKeyList(arguments.map)#" index="k">
        <cfset str = ReplaceNoCase(str, "{{#k#}}", arguments.map[k], "ALL") />
    </cfloop>

    <cfreturn str />
</cffunction>

然后像这样使用它:

<cfset map = { name : "John", product : "SpecialWidget" } />
<cfset filledInTemplate = fillInTemplate(map, someTemplate) />

【讨论】:

  • 这得到了完整示例代码的认可,尽管我不得不使用 REReplaceNoCase 而不是 Replace,因为 Replace 区分大小写并且 CF 将所有结构成员键都转换为大写。
  • 有道理。我更新为使用 ReplaceNoCase 而不是 REReplaceNoCase 因为您不需要正则表达式,但我想您可以根据需要使用它们。
  • 有趣。我正在使用 CF7,我查找了 ReplaceNoCase,但它没有在我的 CF7 WACK 书中列出,并且它在 Adob​​e 上没有在线帮助条目,除非您查看 CF8 及更高版本。我以为它是在 CF8 中添加的,但我确实看到它在 CF6 的示例代码中使用。所以,不知道该怎么做。
  • 查看 ColdFusion MX 7 的帮助页面:adobe.com/livedocs/coldfusion/7/htmldocs/wwhelp/wwhimpl/common/…。它确实存在,我不得不说,文档不是 CF 的强项之一。
【解决方案2】:

不确定是否需要替换,如果您没有太多要合并的字段,您可以通过简单的替换来强制它

这样的东西怎么样(未测试)

<cfset var BaseTemplate = "... lots of html with embedded tokens">

<cfloop (on whatever)>

   <cfset LoopTemplate = replace(BaseTemplate, "#firstName#", myvarforFirstName, "All">
   <cfset LoopTemplate = replace(LoopTemplate, "#lastName#",  myvarforLastName, "All">
   <cfset LoopTemplate = replace(LoopTemplate, "#address#",   myvarforAddress, "All">

</cfloop>

只需将 html 块视为一个简单的字符串。

【讨论】:

  • 是的。我通常以这种方式使用动态变量填充电子邮件模板,只是关键字包含在其他 %characters% 中。
  • 我也做过类似的事情,但避免使用哈希标记来描述变量,因为它在读取文件时会造成严重破坏。我通常喜欢用 [[brackets]] 括起我的变量。
  • 听起来他正在处理遗留代码,其中 #fieldname# 语法已经嵌入在他的“模板”中。如果您是从头开始设计它,我同意“#”字符将是一个糟糕的选择。
  • 是的,以前的程序员故意使用#。他将客户姓名从数据库中读入一个变量,然后cfinclude 电子邮件模板和CF 将为他解析这些变量。创建电子邮件模板的人需要知道 CF 变量的名称。我欣赏代码的简单性和紧凑性,但它创建了一个绑定非常紧密且不灵活的系统。自己搜索和替换变量/关键字需要更多代码,但我喜欢这个想法,因为它使它更具自我记录性。
  • 顺便说一句,虽然我同意自己进行替换可能是更好的设计,但从我的客户有限的预算 PoV 中获得的最佳快速修复仍然是诱使 Evaluate() 顺利地为我替换变量的方法忽略 HTML。我猜从回复中没有办法做到这一点?
【解决方案3】:

CF 7+:你可以使用正则表达式,REReplace()?

CF 9:使用Virtual File System

【讨论】:

  • Henry - 谢谢,我忘了说我在 CF7 上。我看不到如何使用 REReplace 进行变量替换。有什么我在文档中看不到的东西吗?
  • 你几乎可以用正则表达式做任何事情! :) 好吧,把#varName#里面的变量名捞出来,然后调用evalulate(varName),把“#varName#”换成评估结果?
  • or... 循环遍历字符串中的每个字符,就像输入流一样,当你遇到#号时,停止输出到输出流,直到你碰到另一个#号,评估记录的字符串,并将其添加到您的输出流中。 :)
  • 我认为 ReReplace 是一个很好的解决方案。如果只替换三个变量并使用 ReplaceNoCase(),您可能会更加务实。
  • @Henry:+1,这也是我会做的。不成文的 SO 规则,再次证明:讲概念不是很有成果,讲概念并添加代码示例 = 赞成票。 ;)
【解决方案4】:

如果变量在一个结构中,比如表单帖子,那么您可以使用“StructFind”。它完全按照您的要求进行。我在处理带有动态输入的表单时遇到了这个问题。

例如

StructFind(FORM, 'WhatYouNeed')

【讨论】:

    猜你喜欢
    • 2019-09-12
    • 2011-05-15
    • 1970-01-01
    • 2010-10-13
    • 1970-01-01
    • 1970-01-01
    • 2012-09-30
    • 2011-08-21
    • 1970-01-01
    相关资源
    最近更新 更多