了解有关编码 U+30C9 与 U+30C8U+3099 的更多信息

To Understand More about Encoding U+30C9 vs U+30C8U+3099

ド(U+30C9) vs ド(U+30C8U+3099)

顺便说一句,情况是

  1. 用户从网络应用程序上传了名称包含 ド(U+30C8U+3099) 的文件到 AWS s3。
  2. 然后,该网站向 AWS lambda 函数发送了一个 POST 请求,其中包含没有 url 编码的文件名,以便使用 Python 进行进一步处理。到达Lambda时的名字变成了ド(U+30C9)。 Python 然后由于unicode的不同,无法访问存储在s3中的文件。

我认为解决方案是在发送请求之前在前端进行 url 编码,然后使用 urllib.parse.unquote 进行 url 解码以获得相同的 unicode。

我的问题是

  1. url编码能解决那个问题吗?我无法重现相同的问题,可能是因为我与用户的 OS.

    处于不同的 OS
  2. 这两个请求(上传到 s3 并将第二个请求发送到 lambda)都发生在用户的机器上,究竟是如何发生的?

谢谢。

您遇到了一个常见情况(在拉丁文字中可能更常见):规范对等。 Unicode 要求以相同的方式处理规范的等效序列。

如果您查看 UnicodeData.txt,您会发现:

30C8;KATAKANA LETTER TO;Lo;0;L;;;;;N;;;;;
30C9;KATAKANA LETTER DO;Lo;0;L;30C8 3099;;;;N;;;;;

所以,30C9 等价于 30C8 3099。

通常,最好将 Unicode 字符串规范化为常见的规范形式。不幸的是,我们有两个:NFC 和 NFD:归一化形式规范组合和规范化形式规范分解。 Apple 更喜欢后者(而 Unicode 原始 design/preference 是关于这种形式的),而大多数其他供应商都是第一种。

所以不要相信网络浏览器会保持相同的形式。但也要考虑到用户端的输入法可能会给您带来不同的变化(并且对于键盘,您可能还有 non-canonical 应该规范化的形式 [这可能发生在多个组合字符中])。

所以,在你的后端你应该选择一个规范化形式,并以这种形式转换所有输入数据(或者只是确保所有搜索和比较函数都能正确处理等效序列,但这需要在每次调用时进行规范化,所以它可能效率较低)。

Python 有 unicodedata.normalize()(在标准库中,参见 unicodedata module),以标准化 Unicode 字符串。最终在其他语言上你应该使用 ICU 库。无论如何,您应该规范化 Unicode 字符串。

注意:这与编码无关,但它直接内置于 Unicode 设计中。原因是要求与旧编码兼容,而旧编码有两种方式来描述相同的字符。