【问题标题】:Python Inconsistent Special Character Storage In StringPython在字符串中的特殊字符存储不一致
【发布时间】:2019-11-07 15:14:08
【问题描述】:

版本是 Python 3.7。我刚刚发现 python 有时会将字符 ñ 存储在具有多种表示形式的字符串中,我完全不知道为什么或如何处理它。

我不确定展示这个问题的最佳方式,所以我只展示一些代码输出。

我有两个字符串,s1 和 s2 都设置为等于 'Dan Peña'

它们都是字符串类型。

我可以运行代码:

print(s1 == s2) # prints false
print(len(s1)) # prints 8
print(len(s2)) # prints 9
print(type(s1)) # print 'str'
print(type(s2)) # print 'str'
for i in range(len(s1)):
    print(s1[i] + ", " + s2[i])

循环的输出是:

D, D
a, a
n, n
 ,  
P, P
e, e
ñ, n
a, ~

那么,是否有任何 python 方法来处理这些不一致,或者至少有一些关于 python 何时使用哪种表示的规范?

如果知道 Python 为何会选择以这种方式实现也很高兴。

编辑:

一个字符串是从 django 数据库中检索的,另一个字符串是从从列表目录调用解析文件名获得的字符串。

from app.models import Model
from django.core.management.base import BaseCommand

class Command(BaseCommand):

    def handle(self, *args, **kwargs):
        load_dir = "load_dir_name"
        save_dir = "save_dir"

        files = listdir(load_dir)
        save_file_map = {file[:file.index("_thumbnail.jpg")]: f"{save_dir}/{file}" for file in files}
        for obj in Model.objects.all():
            s1 = obj.title
            save_file_path = save_file_map[s1] # Key error when encountering ñ.

但是,当我搜索 save_file_map 字典时,我发现一个与 s1 完全相同的键,除了 ñ 被编码为字符 n~ 而不是字符 ñ

请注意,我在上面的代码中使用 list dir 加载的文件首先基于 obj.title 字段命名,因此应保证具有该名称的文件位于 load_dir 目录中。

【问题讨论】:

  • 字符的二进制编码有很多种。看起来您正在比较二进制编码,而不是将它们转换为字符串。
  • 显示您如何设置s1s2
  • 对我来说,s='D​​an Peña' 只显示 len(s) = 9。
  • @Barmar 它们都是我检查过的字符串类型。其中一个字符串是从 listdir 读取并从文件名中解析出来的,而其中一个字符串是从 Django 数据库 char 字段中读取的。
  • 问题可能与字符串在数据库中的编码方式有关,您在获取它时没有正确转换它。

标签: python python-3.x string python-3.7 unicode-normalization


【解决方案1】:

您需要规范化字符串以使用相同的表示。目前,其中一个使用n 字符 + 波浪号字符(2 个字符),而另一个使用单个字符表示带有波浪号的 n。

unicodedata.normalize 应该做你想做的事。请参阅文档here

您需要这样称呼它:unicodedata.normalize('NFC', s1)'NFC' 告诉 unicodedata.normalize 您想对所有内容使用组合表单,例如 的 1 字符版本。除了'NFC' 之外,文档中还提供了其他选项,您使用哪个完全取决于您。

现在,您在什么时候进行标准化取决于您(我不知道您的应用程序的结构如何)。例如,您可以在插入数据库之前进行规范化,或者在每次从数据库中读取时进行规范化。

【讨论】:

  • 类型是str,不是unicode数据。我想可以转换为 unicode 数据,规范化,然后再转换回来,但这仍然留下了一个问题“为什么 python str 对特殊字符有多种表示形式?”
  • 这是我会发布的答案(如果问题实际上是分解,但似乎不是,因为似乎正在打印实际的波浪号,而不是组合波浪号这可能是字体支持的差异),但有一个小例外:您几乎总是想要'NFC'(或'NFKC')而不是'NFD''NFC' 让您尽可能接近一个字符 == 一个字素(它无法处理所有情况,因为并非所有组合字符的组合都有专用的代码点来编写)。
  • @YungGun:你使用的是 Python 3; str 类型 保存 Unicode 数据的类型。在 Python 3 中,只有一种文本类型,str,它可以保存任何 Unicode 文本;只有在 Python 2 中,str(ASCII 或区域设置特定文本,或二进制数据)和 unicode(任何文本)之间存在区别。
  • @CoffeeTableEspresso:我赞成这个改变,但我已经赞成了。 :-)
  • @YungGun 关于为什么有多种方法来表示像 n 波浪号这样的特殊字符,这是 unicode 的事情,而不是 python 的事情。如果我没记错的话,它或多或少是为了向后兼容其他编码。
猜你喜欢
  • 1970-01-01
  • 2011-09-18
  • 1970-01-01
  • 2023-03-26
  • 2014-07-22
  • 2022-01-22
  • 2011-05-11
  • 1970-01-01
  • 2022-11-13
相关资源
最近更新 更多