2015-10-26 4 views
9

Wenn ich eine Python Unicode-Zeichenfolge habe, die kombinierende Zeichen enthält, meldet len einen Wert, der nicht der Anzahl der Zeichen "gesehen" entspricht.Wie bekomme ich die "sichtbare" Länge einer kombinierenden Unicode-Zeichenfolge in Python?

Zum Beispiel, wenn ich eine Zeichenfolge mit der Kombination von Überstrichen und Unterstreichungen wie u'A\u0332\u0305BC', len(u'A\u0332\u0305BC') Berichte 5 habe; Die angezeigte Zeichenfolge ist jedoch nur 3 Zeichen lang.

Wie bekomme ich die "sichtbar" - das heißt, die Anzahl der verschiedenen Positionen von der Zeichenfolge, die der Benutzer sieht - Länge einer Unicode-Zeichenfolge mit kombinierenden Glyphen in Python?

+0

hmm das ist interessant, das beste ich ca n denke daran, nur die unerwünschten Zeichen zu entfernen. – postelrich

+0

@riotburn: Das wird schwierig sein. Die Zeichen könnten beliebig sein (vom Benutzer bereitgestellt). Ich müsste eine Liste der Unicode-Glyphen zusammensuchen - es sei denn, dies ist ein systematischer Teil der Kodierung. – orome

Antwort

4

Die unicodedata module hat eine Funktion combining, mit der festgestellt werden kann, ob ein einzelnes Zeichen ein kombinierendes Zeichen ist. Wenn es 0 zurückgibt, können Sie das Zeichen als nicht kombinierend zählen.

import unicodedata 
len(u''.join(ch for ch in u'A\u0332\u0305BC' if unicodedata.combining(ch) == 0)) 

oder, etwas einfacher:

sum(1 for ch in u'A\u0332\u0305BC' if unicodedata.combining(ch) == 0) 
+1

Oder: 'sum (nicht unicodedata.combining (ch) für ch in u'a \ u0332 \ u0305BC '). – Bakuriu

+0

@Bakuriu zuerst dachte ich, das würde nicht funktionieren, da 'combining' ganze Zahlen zurückgibt, die nicht' 0' oder '1' sind, aber' not' kümmert sich darum. Gut gemacht! –

+2

Dies funktioniert nicht bei Graphem-Clustern, die aus nicht markierenden Zeichen bestehen, z. B. 'u '\ u1100 \ u1161 \ u11A8'' (각). –

4

Wenn Sie einen regex Geschmack haben, die grapheme passend unterstützt, Sie \X

Demo

Während die Standard-Python-Modul re tut verwenden können nicht unterstützt \X, Matthew Barnetts regex module tut:

>>> len(regex.findall(r'\X', u'A\u0332\u0305BC')) 
3 

Auf Python 2, müssen Sie u im Muster verwenden:

>>> regex.findall(u'\\X', u'A\u0332\u0305BC') 
[u'A\u0332\u0305', u'B', u'C'] 
>>> len(regex.findall(u'\\X', u'A\u0332\u0305BC')) 
3 
2

Zeichen sind nicht das einzige Null-Breite Zeichen Kombination:

>>> sum(1 for ch in u'\u200c' if unicodedata.combining(ch) == 0) 
1 

("\u200c" oder "‌" ist Null-Breiten-Nicht-Verbinder; es ist ein nicht-druckbare Zeichen)

In diesem Fall wird die Regex-Modul funktioniert auch nicht.

>>> len(regex.findall(r'\X', u'\u200c')) 
1 

ich wcwidth gefunden, die korrekt die oben Griffe:

>>> from wcwidth import wcswidth 
>>> wcswidth(u'A\u0332\u0305BC') 
3 
>>> wcswidth(u'\u200c') 
0 

Aber doesn noch Es scheint nicht zu funktionieren mit dem Beispiel des Benutzers 596219:

>>> wcswidth('각') 
4 
Verwandte Themen