سؤال

لدي سلسلة Unicode في Python، وأرغب في إزالة كافة العلامات (علامات التشكيل).

لقد وجدت على الويب طريقة رائعة للقيام بذلك في Java:

  1. تحويل سلسلة Unicode إلى شكلها الطبيعي الطويل (مع حرف منفصل للأحرف وعلامات التشكيل)
  2. قم بإزالة كافة الأحرف التي يكون نوع Unicode الخاص بها "علامة التشكيل".

هل أحتاج إلى تثبيت مكتبة مثل pyICU أم أن هذا ممكن باستخدام مكتبة python القياسية فقط؟وماذا عن بايثون 3؟

ملاحظة مهمة:أرغب في تجنب التعليمات البرمجية ذات التعيين الواضح من الأحرف المحركة إلى نظيرتها غير المحركة.

هل كانت مفيدة؟

المحلول

يونيكود هو الجواب الصحيح لهذا.يقوم بترجمة أي سلسلة Unicode إلى أقرب تمثيل ممكن في نص ascii.

مثال:

accented_string = u'Málaga'
# accented_string is of type 'unicode'
import unidecode
unaccented_string = unidecode.unidecode(accented_string)
# unaccented_string contains 'Malaga'and is of type 'str'

نصائح أخرى

وماذا عن هذا:

import unicodedata
def strip_accents(s):
   return ''.join(c for c in unicodedata.normalize('NFD', s)
                  if unicodedata.category(c) != 'Mn')

يعمل هذا على الحروف اليونانية أيضًا:

>>> strip_accents(u"A \u00c0 \u0394 \u038E")
u'A A \u0394 \u03a5'
>>> 

ال فئة الشخصية "من" لتقف على Nonspacing_Mark, ، والذي يشبه unicodedata.combining في إجابة MiniQuark (لم أفكر في unicodedata.combining، لكنه ربما يكون الحل الأفضل، لأنه أكثر وضوحًا).

وتذكر أن هذه التلاعبات قد تغير بشكل كبير معنى النص.لهجات، علامات تغير في الصوت وما إلى ذلك.ليست "زخرفة".

لقد وجدت هذه الإجابة للتو على الويب:

import unicodedata

def remove_accents(input_str):
    nfkd_form = unicodedata.normalize('NFKD', input_str)
    only_ascii = nfkd_form.encode('ASCII', 'ignore')
    return only_ascii

إنه يعمل بشكل جيد (بالنسبة للغة الفرنسية، على سبيل المثال)، ولكن أعتقد أن الخطوة الثانية (إزالة العلامات) يمكن التعامل معها بشكل أفضل من إسقاط الأحرف غير ASCII، لأن هذا سيفشل بالنسبة لبعض اللغات (اليونانية، على سبيل المثال).من المحتمل أن يكون الحل الأفضل هو إزالة أحرف Unicode التي تم وضع علامة عليها كعلامات تشكيل بشكل صريح.

يحرر:هذه هي الحيلة:

import unicodedata

def remove_accents(input_str):
    nfkd_form = unicodedata.normalize('NFKD', input_str)
    return u"".join([c for c in nfkd_form if not unicodedata.combining(c)])

unicodedata.combining(c) سيعود صحيحا إذا كانت الشخصية c يمكن دمجها مع الحرف السابق، وذلك بشكل أساسي إذا كانت علامة تشكيل.

تحرير 2: remove_accents يتوقع أ يونيكود سلسلة، وليس سلسلة بايت.إذا كان لديك سلسلة بايت، فيجب عليك فك تشفيرها إلى سلسلة Unicode مثل هذا:

encoding = "utf-8" # or iso-8859-15, or cp1252, or whatever encoding you use
byte_string = b"café"  # or simply "café" before python 3.
unicode_string = byte_string.decode(encoding)

في الواقع أنا أعمل على إصدارات python 2.6 و2.7 و3.4 المتوافقة مع المشروع ويجب علي إنشاء معرفات من إدخالات المستخدم المجانية.

بفضلك، قمت بإنشاء هذه الوظيفة التي تصنع العجائب.

import re
import unicodedata

def strip_accents(text):
    """
    Strip accents from input String.

    :param text: The input string.
    :type text: String.

    :returns: The processed String.
    :rtype: String.
    """
    try:
        text = unicode(text, 'utf-8')
    except (TypeError, NameError): # unicode is a default on python 3 
        pass
    text = unicodedata.normalize('NFD', text)
    text = text.encode('ascii', 'ignore')
    text = text.decode("utf-8")
    return str(text)

def text_to_id(text):
    """
    Convert input text to id.

    :param text: The input string.
    :type text: String.

    :returns: The processed String.
    :rtype: String.
    """
    text = strip_accents(text.lower())
    text = re.sub('[ ]+', '_', text)
    text = re.sub('[^0-9a-zA-Z_-]', '', text)
    return text

نتيجة:

text_to_id("Montréal, über, 12.89, Mère, Françoise, noël, 889")
>>> 'montreal_uber_1289_mere_francoise_noel_889'

لا يتعامل هذا مع اللهجات فحسب، بل يتعامل أيضًا مع "السكتات الدماغية" (كما في ø وما إلى ذلك):

import unicodedata as ud

def rmdiacritics(char):
    '''
    Return the base character of char, by "removing" any
    diacritics like accents or curls and strokes and the like.
    '''
    desc = ud.name(unicode(char))
    cutoff = desc.find(' WITH ')
    if cutoff != -1:
        desc = desc[:cutoff]
    return ud.lookup(desc)

هذه هي الطريقة الأكثر أناقة التي يمكنني التفكير فيها (وقد ذكرها Alexis في تعليق على هذه الصفحة)، على الرغم من أنني لا أعتقد أنها أنيقة جدًا بالفعل.

لا تزال هناك أحرف خاصة لا يمكن التعامل معها بهذه الطريقة، مثل الحروف المقلوبة والمقلوبة، نظرًا لأن اسمها الموحد لا يحتوي على "WITH".ذلك يعتمد على ما تريد القيام به على أي حال.كنت أحتاج أحيانًا إلى تجريد اللكنة لتحقيق ترتيب فرز القاموس.

ردًا على إجابة @MiniQuark:

كنت أحاول القراءة في ملف CSV كان نصفه فرنسيًا (يحتوي على لهجات) وأيضًا بعض السلاسل التي ستصبح في النهاية أعدادًا صحيحة وعائمات.كاختبار، قمت بإنشاء test.txt الملف الذي بدا مثل هذا:

مونتريال، أوبر، 12.89، مير، فرانسواز، نويل، 889

كان علي أن أدرج الخطوط 2 و 3 لتشغيله (الذي وجدته في تذكرة بايثون)، بالإضافة إلى تضمين تعليق @Jabba:

import sys 
reload(sys) 
sys.setdefaultencoding("utf-8")
import csv
import unicodedata

def remove_accents(input_str):
    nkfd_form = unicodedata.normalize('NFKD', unicode(input_str))
    return u"".join([c for c in nkfd_form if not unicodedata.combining(c)])

with open('test.txt') as f:
    read = csv.reader(f)
    for row in read:
        for element in row:
            print remove_accents(element)

النتائج:

Montreal
uber
12.89
Mere
Francoise
noel
889

(ملحوظة:أنا أستخدم نظام التشغيل Mac OS X 10.8.4 وأستخدم Python 2.7.3)

gensim.utils.deaccent(نص) من Gensim - نمذجة الموضوع للبشر:

deaccent("Šéf chomutovských komunistů dostal poštou bílý prášek") 'Sef chomutovskych komunistu dostal postou bily prasek'

الحل الآخر هو com.unidecode.

لا أن الحل المقترح مع com.unicodedata عادةً ما يزيل اللهجات في بعض الأحرف فقط (على سبيل المثال.انه يتحول 'ł' داخل '', ، وليس في 'l').

تحتوي بعض اللغات على علامات التشكيل كحروف لغوية وعلامات التشكيل لتحديد اللكنة.

أعتقد أنه من الآمن أن تحدد بشكل صريح ما هي التشكيلات التي تريد تجريدها:

def strip_accents(string, accents=('COMBINING ACUTE ACCENT', 'COMBINING GRAVE ACCENT', 'COMBINING TILDE')):
    accents = set(map(unicodedata.lookup, accents))
    chars = [c for c in unicodedata.normalize('NFD', string) if c not in accents]
    return unicodedata.normalize('NFC', ''.join(chars))
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top