用GSUB替换SmartCodes
我从事Ruby> 3.0,我需要替换文本内容(用SmartCode在线HTML文本)。 本文可能很长,例如这样:“你好,{{viewer_name}}!你好吗?”
我有一种替换smartcodes的方法:
def populate_smartcodes(content)
content.gsub(/\{{(.*?)\}}/).each do |value|
smartcode = value[/#{Regexp.escape('{{')}(.*?)#{Regexp.escape('}}')}/m, 1]
str_smartcode = "{{#{smartcode}}}"
case smartcode
when 'viewer_name'
content = content.gsub(str_smartcode, viewer.name)
when 'company_city'
content = content.gsub(str_smartcode, company.city )
end
content
end
company_city
和viever_name
是我需要向查看器提供一个user :: viever的实例。
而且我有很多智能编码可以替换...我认为这不是做到这一点的好方法,而是在起作用。
您能帮我改善性能还是做到这一点?
编辑:
我向用户显示了PDF内容,他们只有可用的“键”或“ SmartCode”列表,这样,每个人都可以(通过内容)更改其PDF。我们只保留数据库中具有PDF内容的文本。也许我们可以使用另一种策略? 现在,我想要一种将字符串元素替换为另一个值的方法。
I work on ruby > 3.0 and i need to replace a text content (in-line html text with smartcode).
this text can be long and for example it's like this : "Hello, {{viewer_name}} ! How are you ?"
I have a method to replace theses smartcodes :
def populate_smartcodes(content)
content.gsub(/\{{(.*?)\}}/).each do |value|
smartcode = value[/#{Regexp.escape('{{')}(.*?)#{Regexp.escape('}}')}/m, 1]
str_smartcode = "{{#{smartcode}}}"
case smartcode
when 'viewer_name'
content = content.gsub(str_smartcode, viewer.name)
when 'company_city'
content = content.gsub(str_smartcode, company.city )
end
content
end
company_city
and viewer_name
are variables i need to provide with viewer an instance of User::Viewer.
And i have a lot of smartcodes to replace ... I think this is not a good way to do it but it's working.
Can you help me to improve the performance or the way to do it ?
Edit :
I have pdf content shown to the user, they just have a list of 'keys' or 'smartcode' available, this way everyone can change their pdf as the want to (through the content). We keep only a text with the pdf content in the database. Maybe we can use another strategy ?
For now i wanted a way to replace string element by another value.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在这里,您正在在现有的GSUB块中运行一个新的GSUB,这不是必需的,因为GSUB块将无论如何都会用块的返回值代替每个匹配。只需使用2行代码即可实现相同的结果:
...但这仍在分析整个字符串两次。如果您事先知道所有SmartCodes,则可以做类似的事情:
这将返回输入字符串的副本,其中所有实例
{{vuether_name}}
和{company_city} }
更换。您也可以使用gsub!
而不是gsub
如果要修改原始字符串,因此可以像populate_smartcodes(onigral_string)而不是
Original_string = populate_smartcodes(oilter_string)
。Here you're running a new gsub inside an existing gsub block, which isn't necessary, since the gsub block will substitute each match with the return value of the block anyway. The same result could be achieved simply with 2 lines of code:
...but that is still analyzing the whole string twice. If you know all of the smartcodes beforehand, you could do something like this instead:
This will return a copy of the input string with all instances of
{{viewer_name}}
and{{company_city}}
replaced. You could also usegsub!
instead ofgsub
if you want to modify the original string in place, so you can call it likepopulate_smartcodes(original_string)
instead oforiginal_string = populate_smartcodes(original_string)
.可以以更简单(更清洁?)方式从模板中提取智能编码。我们可以肯定地知道,它们总是包含4个括号-2个。因此,我们可以将
gsub
匹配的内容,然后将2 ..- 3
chars作为实际绑定名称:下一步,我们想将这些匹配的SmartCodes解析为有意义的事物。 我们想动态地做到这一点,以避免对许多人的智能编码进行硬编码,正确?
在您的示例中,您将
viewer_name
解析为viever.name
和company_city
tocompany.city
- 看起来像某种模式<接收器>。property>
。如果是这种情况,我们可以使用这种“通用性”来动态解析事物,而无需为每个“ smartcode”进行硬码分辨率:嗯,它可以起作用。可能:)但是它闻起来像地狱:
我将分裂限制在2中,以确保我们始终坚持使用
receviver.property
模式。因此,user_first_name
之类的东西将被解析为user.first_name
。但是,总体而言,这个假设可能完全是错误的!实际上,它可能是user.first.name
,甚至foo_bar
应该解决到sometsing> sosity_else
- 因此,此解决方案是脆弱的< em>最少 ...instance_eval
是一个pandora框,我们应该非常小心。有思想的是,我们应该在孤立的安全上下文(一些空白的板岩对象)中称其为
为这些问题:我们可以创建一个特殊的模板构建器对象,作为我们
instance_eval
的安全空白后续上下文;然后,我们可以注入必要的绑定,以便instance_eval可以正确解析我们的智能事物(在这种情况下,我们甚至可以用更安全的魔法替换instance_eval,或者根本没有魔法 - 硬编码的东西有时不是 bad Idea)等...但是,在这个兔子洞之后,我们迟早会重新创建
Liquid
或Mustache
之类的东西,只是不那么成熟,更容易出错。因此,我的建议是不要在Regexes上玩耍,请首先尝试采用一些战斗测试的模板引擎(仅当您真正有很强的理由时,只有在自定义实施中回滚):) :)
It is possible to extract smartcodes from the template in a much simpler (cleaner?) way. We know for sure, that they always contain 4 parentheses - 2 from each side. So we can just take what
gsub
matches, and take2..-3
chars as the actual binding name:Next, we would like to resolve these matched smartcodes into something meaningful. And we would like to do it dynamically to avoid hardcoding of many-many individual smartcodes, correct?
In your example you resolve
viewer_name
intoviewer.name
andcompany_city
intocompany.city
- it looks like some pattern<receiver>.<property>
. If this is the case, we could use this "generality" to resolve things dynamically without the need to hardcode resolution for each "smartcode":Well, it could work. Probably :) But it smells as hell:
I limit the split by 2, to ensure we always stick with
receiver.property
pattern. So, something likeuser_first_name
will be resolved asuser.first_name
. But this assumption might be just wrong in general! It might be in fact something likeuser.first.name
, or evenfoo_bar
that should be resolved intosomething_else
- so this solution is fragile at minimum...instance_eval
is a Pandora box, and we should be extremely careful with it. Idealy, We should call it in an isolated, safe context (some blank slate object)Both of these problems are solvable: we can create a special template builder object as a safe blank late context for our
instance_eval
; we could then inject the necessary bindings so that instance_eval could resolve our smartcodes properly (in this case we could even replace instance_eval with safer magic or maybe no magic at all - hardcoding things sometimes is not that bad idea) etc...But following this rabbit hole, we would sooner or later recreate something like
liquid
ormustache
, just way less mature and more error-prone.So my proposal is don't play around regexes, try to adopt some battle-tested template engine first (and roll back to the custom implementation only if you have really strong reasons) :)