Python 字符串中的特殊字符存储不一致
Python Inconsistent Special Character Storage In String
版本是 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
目录。
您需要规范化字符串以使用相同的表示形式。现在,其中一个使用 n
字符 + 波浪号字符(2 个字符),而另一个使用单个字符表示带有波浪号的 n。
unicodedata.normalize
应该做你想做的。请参阅文档 here.
您可以这样称呼它:unicodedata.normalize('NFC', s1)
。 'NFC'
告诉 unicodedata.normalize
您想要对所有内容使用组合形式,例如ñ
的 1 个字符版本。除了 'NFC'
之外,文档中还提供了其他选项,您使用哪个完全取决于您。
现在,您在什么时候规范化取决于您(我不知道您的应用程序是如何构建的)。例如,您可以在插入数据库之前进行规范化,或者在每次从数据库读取时进行规范化。
版本是 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
目录。
您需要规范化字符串以使用相同的表示形式。现在,其中一个使用 n
字符 + 波浪号字符(2 个字符),而另一个使用单个字符表示带有波浪号的 n。
unicodedata.normalize
应该做你想做的。请参阅文档 here.
您可以这样称呼它:unicodedata.normalize('NFC', s1)
。 'NFC'
告诉 unicodedata.normalize
您想要对所有内容使用组合形式,例如ñ
的 1 个字符版本。除了 'NFC'
之外,文档中还提供了其他选项,您使用哪个完全取决于您。
现在,您在什么时候规范化取决于您(我不知道您的应用程序是如何构建的)。例如,您可以在插入数据库之前进行规范化,或者在每次从数据库读取时进行规范化。