Saya memiliki file csv dengan kolom yang berisi daftar string. Sepertinya string itu memiliki karakter tersembunyi yang hanya bisa saya lihat saat menghapus karakter tertentu dari setiap string.

#string copied from column
print(len('kommunikationsfähigkeit'))
#same string entered by me 
print(len('kommunikationsfähigkeit'))

24
23

Saat menghapus bagian dari string yang disalin kolom, saya mendapatkan ini:

''̈igkeit'

Ada yang tahu apa yang terjadi di sana? Saya mencoba membaca csv dengan encoding='utf8', tetapi tidak mengubah apa pun. Saya jelas ingin menyingkirkan karakter-karakter itu.

2
Michael 17 Januari 2020, 12:48

2 jawaban

Jawaban Terbaik

Keduanya adalah UTF-8, tetapi ada cara berbeda untuk merender karakter visual yang sama. String pertama berisi U+00E4 — Huruf KECIL LATIN A DENGAN DIAERESIS. String kedua Anda berisi “a” diikuti oleh U+0308 — MENGABUNGKAN DIAERESIS< /a> ( ), yang, dalam kombinasi, diterjemahkan sebagai "ä".

Anda dapat memeriksa sendiri string menggunakan unicodedata:

import unicodedata

for c in string:
    print(unicodedata.name(c))

Kedua hal di atas adalah cara yang valid untuk merepresentasikan “ä”, dan keduanya dianggap setara di bawah normalisasi Unicode yang sesuai. Anda dapat menggunakan unicodedata.normalize untuk menormalkan representasi yang berbeda. Misalnya, Anda dapat mengubah kedua string menjadi bentuk normal C (meskipun yang pertama sudah ada di NFC):

a = 'kommunikationsfähigkeit'
b = 'kommunikationsfähigkeit'
print(f'len(a) = {len(a)}')
# len(a) = 23
print(f'len(b) = {len(b)}')
# len(b) = 24
print(f'a == b: {a == b}')
# a == b: False

norm_a = unicodedata.normalize('NFC', a)
norm_b = unicodedata.normalize('NFC', b)
print(f'len(norm_a) = {len(norm_a)}')
# len(norm_a) = 23
print(f'len(norm_b) = {len(norm_b)}')
# len(norm_b) = 23
print(f'norm_a == norm_b: {norm_a == norm_b}')
# norm_a == norm_b: True
3
Konrad Rudolph 17 Januari 2020, 10:09

Ini adalah salah satu alasan saya tidak menyukai Unicode. Alih-alih mengatakan "ini adalah satu-satunya cara yang benar", standar mendefinisikan beberapa cara untuk mewakili karakter. Dalam hal ini, satu string menggunakan bentuk "tersusun", sedangkan yang lain menggunakan bentuk "terurai" (huruf dan diaeresis terpisah).

Anda mungkin ingin mempertimbangkan untuk menormalkan data:

import unicodedata
s1 = 'kommunikationsfähigkeit'
s2 = 'kommunikationsfähigkeit'
ns1 = unicodedata.normalize('NFC', s1)
ns2 = unicodedata.normalize('NFC', s2)
print(s1 == s2, ns1 == ns2)
# prints False True

Cuplikan di atas menormalkan string ke bentuk komposisi, yang digunakan banyak sistem. Bentuk yang didekomposisi cenderung muncul di sistem macOS karena itu adalah default di sana. Anda dapat melihat string awalnya tidak sebanding, tetapi mereka lakukan setelah normalisasi.

1
John Szakmeister 17 Januari 2020, 10:10