【发布时间】:2021-10-29 10:43:12
【问题描述】:
我需要对来自数据库的文本进行多次替换,然后再将其显示给用户。
我的示例是最有可能在 CRM 上找到的数据,输出是用于 Web 的 HTML,但该问题可推广到任何其他文本替换需求。这个问题对于任何编程语言都是通用的。就我而言,我使用 PHP,但它更多的是算法问题而不是 PHP 问题。
问题
我在下面编写的 3 个示例中的每一个都可以通过正则表达式非常容易地完成。但是即使我进行多步替换,将它们组合在一起也不是那么直接。他们干扰。
问题
是否有用于执行多个干扰文本替换的设计模式?
替换示例 #1:ID。
我们使用 ID。 ID 是 sha-1 摘要。 ID 是通用的,可以代表公司中的任何实体,从用户到机场,从发票到汽车。
所以在数据库中我们可以找到要显示给用户的文本:
User d19210ac35dfc63bdaa2e495e17abe5fc9535f02 paid 50 EUR
in the payment 377b03b0b4e92502737eca2345e5bdadb1262230. We sent
an email a49c6737f80eadea0eb16f4c8e148f1c82e05c10 to confirm.
我们希望将所有 ID 转换为链接,以便观看信息的用户可以点击。有一个用于解码 ID 的通用 URL。假设它是http://example.com/id/xxx
转换后的文本是这样的:
User <a href="http://example.com/id/d19210ac35dfc63bdaa2e495e17abe5fc9535f02">d19210ac35dfc63bdaa2e495e17abe5fc9535f02</a> paid 50 EUR
in the payment <a href="http://example.com/id/377b03b0b4e92502737eca2345e5bdadb1262230">377b03b0b4e92502737eca2345e5bdadb1262230</a>. We sent
an email <a href="http://example.com/id/a49c6737f80eadea0eb16f4c8e148f1c82e05c10">a49c6737f80eadea0eb16f4c8e148f1c82e05c10</a> to confirm
替换示例 #2:链接
我们希望任何类似于 URI 的东西都是可点击的。让我们只关注 http 和 https 协议,忘记其他的。
如果我们在数据库中找到这个:
Our website is http://mary.example.com and the info
you are requesting is in this page http://mary.example.com/info.php
会被转换成这个:
Our website is <a href="http://mary.example.com">http://mary.example.com</a> and the info
you are requesting is in this page <a href="http://mary.example.com/info.php">http://mary.example.com/info.php</a>
替换示例#3:HTML
当原始文本包含 HTML 时,它不能被发送 raw,因为它会被解释。我们想将&lt; 和&gt; 字符更改为转义形式&lt; 和&gt;。 HTML-5 的翻译表还包含要转换为 &amp; 的 & 符号,例如,这也会影响电子邮件的 Message Id 的翻译。
例如,如果我们在数据库中找到这个:
We need to change the CSS for the <code> tag to a pure green.
Sent to John&Partners in Message-ID: <aaa@bbb.ccc> this morning.
得到的替换将是:
We need to change the CSS for the <code> tag to a pure green.
Sent to John&Partners in Message-ID: <aaa@bbb.ccc> this morning.
好吧...但是...组合?
到这里为止,每一个“本身”的改变都超级简单。
但是当我们组合事物时,我们希望它们对用户来说仍然是“自然的”。假设原始文本包含 HTML。其中一个标签是<a> 标签。我们仍然希望看到完整的标签“显示”并且 HREF 是可点击的。如果是链接,还有锚的文本。
组合示例:#2(注入链接)然后 #3(扁平化 HTML)
假设我们在数据库中有这个:
Paste this <a class="dark" href="http://example.com/data.xml">Download</a> into your text editor.
如果我们首先应用 #2 来转换链接,然后应用 #3 来编码 HTML,我们将拥有:
将规则#2(注入链接)应用于原始链接http://example.com/data.xml被检测并替换为<a href="http://example.com/data.xml">http://example.com/data.xml</a>
Paste this <a class="dark" href="<a href="http://example.com/data.xml">http://example.com/data.xml</a>">Download</a> into your text editor.
这显然是一个损坏的 HTML,没有任何意义,但此外,在 #2 的输出上应用规则 #3(扁平化 HTML)我们会得到:
Paste this <a class="dark" href="<a href="http://example.com/data.xml">http://example.com/data.xml</a>">Download</a> into your text editor.
这又是损坏的 HTML 的纯 HTML 表示,不可点击。 错误输出:#2 和#3 都不满意。
反向组合:首先 #3(扁平化 HTML)然后 #2(注入链接)
如果我首先将规则 #3 应用于“解码所有 HTML”,然后将规则 #2 应用于“注入链接 HTML”,则会发生以下情况:
原文(同上):
Paste this <a class="dark" href="http://example.com/data.xml">Download</a> into your text editor.
应用 #3 的结果(扁平化 HTML)
Paste this <a class="dark" href="http://example.com/data.xml">Download</a> into your text editor.
然后我们应用规则#2(注入链接)它似乎工作:
Paste this <a class="dark" href="<a href="http://example.com/data.xml">http://example.com/data.xml</a>">Download</a> into your text editor.
之所以有效,是因为 " 不是有效的 URL 字符,并将 http://example.com/data.xml 检测为确切的 URL 限制。
但是...如果原始文本在链接文本中也有一个链接怎么办?这是一个非常常见的情况。喜欢这个原文:
Paste this <a class="dark" href="http://example.com/data.xml">http://example.com/data.xml</a> into your text editor.
然后应用 #2 会得到这个:
Paste this <a class="dark" href="http://example.com/data.xml"<http://example.com/data.xml</a> into your text editor.
这里有问题
由于所有 &、; 和 / 都是有效的 URL 字符,因此 URL 解析器会发现:http://example.com/data.xml&lt;/a&gt; 作为 URL,而不是在 .xml 点结束。
这会导致这个错误输出:
Paste this <a class="dark" href="<a href="http://example.com/data.xml">http://example.com/data.xml</a>"<<a href="http://example.com/data.xml</a>">http://example.com/data.xml</a></a> into your text editor.
所以http://example.com/data.xml&lt;/a&gt; 被<a href="http://example.com/data.xml&lt;/a&gt;">http://example.com/data.xml&lt;/a&gt;</a> 替换,但问题是没有正确检测到 URL。
让我们把它和规则 #1 混合起来
如果规则 #2 和 #3 在一起处理时变得一团糟,想象一下如果我们将它们与规则 #1 混合在一起,并且我们有一个包含 sha-1 的 URL,如下面的数据库条目:
Paste this <a class="dark" href="http://example.com/id/89019b16ab155ba1c19e1ab9efdb9134c8f9e2b9">http://example.com/id/89019b16ab155ba1c19e1ab9efdb9134c8f9e2b9</a> into your text editor.
你能想象吗??
分词器?
我曾想过创建一个语法标记器。但我觉得这有点矫枉过正。
是否有设计模式
我想知道是否有一个设计模式可供阅读和研究,它是如何被调用的,它在哪里记录,当涉及到多个文本替换时。
如果没有任何模式……那么……构建语法标记器是唯一的解决方案吗?
我觉得必须有一个更简单的方法来做到这一点。我真的必须在语法树中标记文本,然后通过遍历树重新渲染吗?
【问题讨论】:
标签: parsing token tokenize abstract-syntax-tree string-substitution