2017-10-30 69 views
8

Chcę znaleźć częstotliwość różnych liter w tekście, a niektóre z nich zawierają znaki diakrytyczne. Przykładowo w tekście zastosowano zarówno "å", jak i "ą̊" (U + 00E5 U + 0328), a częstotliwość należy zliczać osobno.Jak poprawnie policzyć litery z znakami diakrytycznymi w tekście?

Jak to zrobić?

Próbowałem już korzystać z funkcji Counter Collection, otworzyć plik w formacie utf8, podzielić ciąg tekstowy przy użyciu zarówno text.split(), jak i list(text), ale python nadal liczy "å" i "ą̊" jako tę samą literę!

Odpowiedz

7

Problem polega na tym, że tekst w Unicode (zapomnij o utf-8, mówię po dekodowaniu danych do właściwych ciągów w języku Python 3) używa więcej niż jednego kodu unicode dla niektórych znaków: na przykład "ą̊" ma dwa znaki , więc chociaż zarówno "ą", jak i "å" mogą istnieć jako jedna postać po prawidłowej normalizacji, postać, która przyjmuje oba znaczniki, musi użyć jednego ze znaków "znaku łączącego" w kodzie Unicode.

Oznacza to, że sam Python Counter nie będzie w stanie obsłużyć go, bez co najmniej dodatkowego kroku. W kodzie Pythona sposobem na znalezienie tych znaków znaczników jest użycie unicodedata.category - i to nie jest takie przyjazne, po prostu zwraca two-character identifier for the category.

Więc, myślę, że jedną rzeczą, którą można zrobić, to przetworzyć tekst na listę, w której każda postać i jej oznaczenia są znormalizowane, za pomocą kodu "czystego Pythona". Następnie Counter może wykonać swoją pracę.

To może być coś wzdłuż:

import unicodedata 
from collections import Counter 

characters = [] 

text = ... 

# Decompose all characters into plain letters + marking diacritics: 
text = unicodedata.normalize("NFD", text) 
for character in text: 
    if unicodedata.category(character)[0] == "M": 
     # character is a composing mark, so agregate it with 
     # previous character 
     characters[-1] += character 
    else: 
     characters.append(character) 

counting = Counter(characters) 

(Zauważ, że fragment powyżej nie bierze pod uwagę potencjalny fragment tekstu zniekształcone, że zaczną z oznaczeniem znaku w pozycji 0)

+0

„charakter” nie powinno być w cudzysłowie, na linii, która brzmi 'jeśli unicodedata.category („znak”) [0] ==„M”:', gdyż odnosi się do zmiennej. – olooney

+0

dziękuję za spostrzeżenie. – jsbueno

+1

Wielkie dzięki za to! Testowałem i działa świetnie, nawet dla listów z podwójnymi znacznikami :) Musiałem sprawdzić 'unicodedata.normalize' oraz' unicodedata.category', więc tutaj są linki, jeśli inni ich potrzebują; https://docs.python.org/2/library/unicodedata.html#unicodedata.normalize https://docs.python.org/2/library/unicodedata.html#unicodedata.category http: // www .fileformat.info/info/unicode/category/index.htm Wielkie dzięki za pomoc! – user11448

0

You może zamienić znaki specjalne na inny znak, który może być reprezentowany przez pojedynczy punkt kodowy przed zliczeniem. Upewnij się, że znaki zastępcze nie pojawią się w korpusie.

text.replace('ą̊', 'Ʒ').replace('Ą̊', 'ʒ')