【问题标题】:What strategies are there for escaping character entities?逃避角色实体有哪些策略?
【发布时间】:2009-12-15 07:59:42
【问题描述】:

我们正在对一系列英语文档(主要是科学文档)进行自然语言处理,但在通过各种组件传输非 ANSI 字符时遇到了问题。文档可以是“ASCII”、UNICODE、PDF 或 HTML。在这个阶段,我们无法预测我们的链中将包含哪些工具,或者它们是否允许使用 ANSI 以外的字符编码。即使以 UNICODE 表示的 ISO-Latin 字符也会出现问题(例如,在浏览器中显示不正确)。我们很可能会遇到一系列符号,包括数学符号和希腊符号。我们希望将这些“扁平化”为一个文本字符串,该字符串将在多步处理(包括 XML 和正则表达式工具)中幸存下来,然后可能在最后一步重新构建它(尽管它是语义而不是我们关心的排版,所以这是一个小问题)。

我很欣赏没有绝对的答案——在某些情况下,任何转义都可能发生冲突——但我正在寻找类似于 XML 的 <![CDATA[ ...]]> 的东西,它可以在大多数非递归 XML 操作中存活下来。 [ 这样的字符很糟糕,因为它们在正则表达式中很常见。所以我想知道是否有一种普遍采用的方法,而不是发明我们自己的方法。

一个典型的例子是“度”符号:

HTML Entity (decimal)   °
HTML Entity (hex)   °
HTML Entity (named)     °
How to type in Microsoft Windows    Alt +00B0
Alt 0176
Alt 248
UTF-8 (hex)     0xC2 0xB0 (c2b0)
UTF-8 (binary)  11000010:10110000
UTF-16 (hex)    0x00B0 (00b0)
UTF-16 (decimal)    176
UTF-32 (hex)    0x000000B0 (00b0)
UTF-32 (decimal)    176
C/C++/Java source code  "\u00B0"
Python source code  u"\u00B0"

我们也有可能遇到TeX

$10\,^{\circ}{\rm C}$

\degree

所以反斜杠、卷曲和美元不是一个好主意。

例如,我们可以使用如下标记:

__deg__
__#176__

这可能会奏效,但我会感谢那些有类似问题的人的建议。

更新我接受 @MichaelB 坚持我们始终使用 UTF-8。我担心我们的一些工具可能不符合要求,如果是这样,我会重新审视这一点。请注意,我最初的问题措辞不好 - 请阅读他的答案和其中的链接。

【问题讨论】:

  • 如果您不提及任何架构或编程语言,很难对此发表评论。您打算如何存储文档?问题出在哪里?在您的内部架构中?在你的文件加载器中?
  • @xcut:我认为问题在于,当您在一般级别过滤和操作数据时,您没有明确定义的“标记”这些实体的方式,以防止它们不是由这些过滤器混合到管道中。在数据源附近,数据类型和转义是已知的,但在更一般的层面上,您需要一个非常通用、非常健壮的分隔符/标记来防止被非常通用的过滤器破坏。
  • @xcut @Stefano 的诊断是正确的。我们不知道这些会通过什么工具。例如,我们曾经使用 NLTK (Python) 工具包,现在已将其中的一部分切换到 Java (ANTLR)。下个月我们可能需要一些不同的东西。

标签: character-encoding escaping


【解决方案1】:
  • 找一个真正了解字符编码的人来做这件事。看起来你没有,因为你没有正确使用术语。或者,read this
  • 不要制定自己的逃生计划——它会给你带来比它解决的问题更多的问题。相反,将各种源编码规范化为 UTF-8(这实际上只是一种这样的转义方案,除了高效和标准化)并正确处理字符编码。如果你真的害怕高位,也许可以使用 UTF-7。
  • 在当今时代,不能正确处理字符编码。如果一个工具没有,请放弃它 - 它很可能是在许多其他方面质量非常差的代码,不值得麻烦使用。

【讨论】:

  • 我的最后一条评论消失了……请指出我在哪里正确使用术语,我会努力学习。
  • 您正在混合定义抽象字符 (Unicode)、具体编码(ASCII、ISO-Latin)和文件格式(PDF、HTML,支持任意编码)的标准。您使用的是不合格的术语“ANSI”,它具有各种相互矛盾的含义。您说“以 UNICODE 表示的 ISO-Latin 字符”,这完全是倒退。请仔细阅读我链接的文章,它应该会让事情更清楚。
【解决方案2】:

也许我没有正确解决问题,但我会创建一个不太可能被触摸的非常独特的转义标记,然后使用它来包含编码为 base32 字符串的实体。

最终,您可以通过单独的通道沿链传输唯一标记及其编号,并在最后检查它们的存在和编号。

例如,类似

the value of the temperature was 18 cd48d8c50d7f40aeb6a164181b17feee EZSGKZY= cd48d8c50d7f40aeb6a164181b17feee

你的标记是一个 uuid,实体是 &deg 编码在 base32 中的。然后传递标记 cd48d8c50d7f40aeb6a164181b17feee。它不能被破坏(如果它被破坏,你的过滤器可能会破坏任何由字母和数字组成的东西,但至少你可以排除它们,因为它们是固定长度的),你总是可以通过查看两个标记来恢复内容。

当然,如果您的文档中有 uuid,这可能是个问题,但由于您没有将它们作为授权标记沿横向通道传输,因此它们不会被识别(无论如何,什么是无论如何,inbetween 都不会验证为 base32 字符串)。

如果您需要搜索它们,那么您可以保留 uuid 细分,然后使用适当的正则表达式来发现这些事件。示例:

>>> re.search("(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})(.*?)(\\1)", s)
<_sre.SRE_Match object at 0x1003d31f8>
>>> _.groups()
('6d378205-1265-44e4-80b8-a47d1ceaad51', ' EZSGKZY= ', '6d378205-1265-44e4-80b8-a47d1ceaad51')
>>> 

如果你真的需要一个特定的“令牌”来测试,你可以使用一个 uuid1,一个非常定义的节点规范:

>>> uuid.uuid1(node=0x1234567890)  
UUID('bdcce554-e95d-11de-bd0f-001234567890')
>>> uuid.uuid1(node=0x1234567890)  
UUID('c4c57a91-e95d-11de-90ca-001234567890')
>>> 

您可以使用任何您喜欢的节点作为节点,uuid 将是唯一的,但您仍然可以测试是否存在(尽管您可能会得到误报)。

【讨论】:

  • 您确实准确地理解了问题,并且您的解决方案是合乎逻辑的。我不介意长度,我们可以在代码中放入符号常量。但是,这些实体何时开始和结束并没有明确的词汇指示 - 例如,您不能搜索它们。
猜你喜欢
  • 2021-02-21
  • 1970-01-01
  • 2016-06-14
  • 1970-01-01
  • 1970-01-01
  • 2021-02-06
  • 2013-09-11
  • 1970-01-01
  • 2022-01-19
相关资源
最近更新 更多