这可能是一个与字符编码相关的更普遍的问题,但由于我在编写两个数据帧的外部连接时遇到了这个问题,所以我将其与 Python 代码示例一起发布。
最重要的是,问题是:为什么
ö
在技术上与 ö
不同,我如何确定两者不仅在视觉上相同,而且在技术上也相同?
如果你在文本编辑器中复制粘贴两个字符并搜索其中一个,你将永远找不到两个!
现在 Python 示例尝试在“文件名”列(此处显示为 CSV 数据)上对两个数据帧进行简单的外部连接:
df1:
filename;abstract
problematic_ö.txt;abc
non-problematic_ö.txt;yxz
df2:
bytes;filename
374;problematic_ö.txt
128;non-problematic_ö.txt
Python代码:
import csv
import pandas as pd
df1 = pd.read_csv('df1.csv', header=0, sep = ';')
df2 = pd.read_csv('df2.csv', header=0, sep = ';')
print(df1)
print(df2)
df_outerjoin = pd.merge(df1, df2, how='outer', indicator=True)
df_outerjoin.to_csv('df_outerjoin.csv', sep =';', index=False, header=True, quoting=csv.QUOTE_NONNUMERIC)
print(df_outerjoin)
输出:
# filename abstract bytes _merge
1 problematic_ö.txt abc NaN left_only
2 non-problematic_ö.txt yxz 128.0 both
3 problematic_ö.txt NaN 374.0 right_only
所以有问题的文件名中的 'ö' 不会被识别为与无问题文件名中的 'ö' 相同的字符。
这里发生了什么?
我能做些什么来克服这个问题——我可以通过导入具有特殊编码设置的数据文件来做一些“聪明”的事情,还是我必须做一个愚蠢的搜索和替换?
在 Unicode 中有多种表示相同字符的方法。在您的情况下,有问题的文件名包含字符“ö”,它实际上由两个 Unicode 代码点表示:“o”(拉丁文小写字母 O)和组合字符“”。 (结合分音符)另一方面,没有问题的文件名使用字符“ö”(带分音符的拉丁文小写字母 O),它由单个 Unicode 代码字符表示。
您可以使用
unicodedata
库-unicodedata.normalize
.
它是这样工作的
import unicodedata
a = "ö"
b = "ö"
print(a == b)
a = unicodedata.normalize('NFC', a)
b = unicodedata.normalize('NFC', b)
print(a == b)
输出:
False
True
问题是带有变音符号的字符通常可以用所谓的组合变音符号或 Unicode 中所谓的预组合字符表示。
problematic_ö.txt
中的第一个实例是 U+006F U+0308
(o 带有变音符号),而 non-problematic_ö.txt
中的第二个实例是预合成的 U+00F6
.
要正常化,试试这个:
import unicodedata
oUml_combDiac = 'ö'
oUml_precomp = 'ö'
oUml_combDiac == oUml_precomp
# False
unicodedata.normalize('NFC', oUml_combDiac) == unicodedata.normalize('NFC', oUml_precomp)
# True
(
oUml
这里代表“o with umlaut”。)
而不是使用
unicodedata
,Pandas 提供以下方法Series.str.normalize(form)
,所以像:
df1['filename'] = df1['filename'].str.normalize('NFC')
df2['filename'] = df2['filename'].str.normalize('NFC')
在进行外部连接之前。