2010-06-29 13 views
7

Ich habe eine UTF8-Zeichenfolge mit Diakritika kombinieren. Ich möchte es mit der Regex-Sequenz \w übereinstimmen. Es passt zu Zeichen, die Akzente haben, aber nicht, wenn ein lateinisches Zeichen mit Diakritika kombiniert ist.Python regex w passt nicht zusammen Diakritika kombinieren?

>>> re.match("a\w\w\wz", u"aoooz", re.UNICODE) 
<_sre.SRE_Match object at 0xb7788f38> 
>>> print u"ao\u00F3oz" 
aoóoz 
>>> re.match("a\w\w\wz", u"ao\u00F3oz", re.UNICODE) 
<_sre.SRE_Match object at 0xb7788f38> 
>>> re.match("a\w\w\wz", u"aoo\u0301oz", re.UNICODE) 
>>> print u"aoo\u0301oz" 
aóooz 

(Sieht aus wie der SO Abschlag processer ist in der oben mit den Kombinations diakritischen Schwierigkeiten hat, aber es gibt ein in der letzten Zeile)

Gibt es trotzdem mit \w Kombinieren diakritische Zeichen entsprechen ? Ich möchte den Text nicht normalisieren, weil dieser Text von Dateiname ist, und ich möchte noch nicht eine ganze 'Dateiname-Unicode-Normalisierung' machen müssen. Das ist Python 2.5.

Antwort

5

Ich habe gerade ein neues "regex" Paket auf Pypi bemerkt. (Wenn ich richtig verstehe, ist es eine Testversion eines neuen Pakets, das eines Tages das Paket stdlib re ersetzen wird).

Es scheint (unter anderem) mehr Möglichkeiten in Bezug auf Unicode zu haben. Zum Beispiel unterstützt es \X, die verwendet wird, um ein einzelnes Graphem (ob es kombiniert oder nicht verwendet) zu entsprechen. Es unterstützt auch das Anpassen von Unicode-Eigenschaften, Blöcken und Skripten, sodass Sie \p{M} verwenden können, um sich auf Kombinationsmarken zu beziehen. Die zuvor erwähnte \X entspricht \P{M}\p{M}* (ein Zeichen, das KEINE Kombinationsmarke ist, gefolgt von null oder mehr Kombinationsmarken).

Beachten Sie, dass dies macht \X mehr oder weniger die Unicode-Äquivalent ., nicht von \w, so in Ihrem Fall \w\p{M}* ist das, was Sie brauchen.

Es ist (vorerst) ein nicht-stdlib-Paket, und ich weiß nicht, wie bereit es ist (und es kommt nicht in einer Binärdistribution), aber Sie möchten es vielleicht versuchen, als es scheint die einfachste/"richtigste" Antwort auf Ihre Frage zu sein. (Ansonsten glaube ich, dass Sie explizit Zeichenbereiche verwenden, wie in meinem Kommentar zur vorherigen Antwort beschrieben).

Siehe auch this page mit Informationen zu regulären Unicode-Ausdrücken, die möglicherweise auch nützliche Informationen für Sie enthalten (und als Dokumentation für einige der im regex-Paket implementierten Dinge dienen können).

1

Sie können unicodedata.normalize verwenden, um die kombinierenden diakritischen Zeichen zu einem Unicode-Zeichen zusammenzusetzen.

>>> import re 
>>> from unicodedata import normalize 
>>> re.match(u"a\w\w\wz", normalize("NFC", u"aoo\u0301oz"), re.UNICODE) 
<_sre.SRE_Match object at 0x00BDCC60> 

Ich weiß, Sie sagen, Sie nicht normalisieren wollten, aber ich glaube nicht, dass es ein Problem mit dieser Lösung, da Sie nur die Zeichenfolge Normalisierung gegen anzupassen, und nicht habe um den Dateinamen selbst oder etwas zu ändern.

+1

Ja, das wird mir sagen, ob ich ein Match habe, aber nachdem ich das Match gemacht habe, ziehe ich passende Gruppen heraus und mache dann Sachen mit ihnen. Wenn ich Ihren Ansatz verwendet habe, dann sind die Bytes, die ich später habe, nicht die gleichen Bytes wie im Dateinamen – Rory

+0

Ich sehe. Wissen Sie, ob die Zeichenfolgen in der Verwendung von diakritischen Zeichen konsistent sind (immer kombinieren oder zumindest immer kombinieren oder nicht innerhalb einer einzelnen Zeichenfolge)? Wenn dies der Fall ist, können Sie die Ergebnisse bei Bedarf erneut auf NFC oder NFD normalisieren. Andernfalls denke ich, dass Sie auf Tricks zurückgreifen müssen, um die Position der Kombination von diakritischen Zeichen in der ursprünglichen Zeichenfolge zu ermitteln und diese Informationen zu verwenden, um nur die benötigten Zeichen zu zerlegen (was natürlich mehr Arbeit wäre, als alles zu zerlegen) ganz und gar nicht). – Steven

+0

Oder vielleicht nur den Ausdruck ändern und verwenden Sie die Bereiche für die Kombination Diakritika, die Sie interessiert sind, und verwenden Sie etwas wie \ w [\ u0300- \ u036F]? anstelle von nur \ w – Steven