Уведомления

Группа в Telegram: @pythonsu

#1 Май 25, 2015 10:25:32

Pawl
Зарегистрирован: 2015-05-25
Сообщения: 17
Репутация: +  0  -
Профиль   Отправить e-mail  

сортировка русских слов компаратором

Доброго времени суток. Сам я программирую в java и немного в Delphi, а тут попросили сделать задачку на питоне. Задача следущая: есть набор русских слов в файле, разделённых пробелами, пунктуацией, а также числами. Необходимо подсчитать количество одинаковых слов и вывести их на консоль в отсортированном по алфавиту словаре в виде (слово, количество). Проблема оказалась в том, что для русской локали е и ё - абсоллютно одинаковые буквы, в то время, как в алфавите е идет перед ё, т. е. слово “ель” должно становиться перед словом “ёлка”. Пришлось искать возможности создания правил сортировки. Я обнаружил, что для питона 2 в функции сортировки есть ключ cmp для компаратора, но делать компаратор для кирилицы в питоне 2 мне показалось нетривиальной задачей. У питона 3 с UTF-8 дела обстоят получше, но компаратор, как таковой, в нём использовать уже нельзя. Зато там есть костыль в виде функции cmp_to_key, которым я в итоге и воспользовался. Вот что у меня получилось:

from codecs import open
from functools import cmp_to_key
from re import split
text = open("load", "r", "utf-8")
s = text.read()
words = split('[\d\W]+', s)
d = {}
for w in words:
    if w != '':
        if w in d:
            d[w] += 1
        else:
            d[w] = 1
items = list(d.items())
def comparator(a, b):
    x = str(a)
    y = str(b)
    t = len(x) if len(x) < len(y) else len(y)
    for j in range(t):
        if x[j] == y[j]:
            continue
        if x[j] != 'ё' and y[j] != 'ё':
            if x[j] < y[j]:
                return -1
            else:
                return 1
        elif x[j] == 'ё':
            if y[j] > 'е':
                return -1
            else:
                return 1
        elif y[j] == 'ё':
            if x[j] > 'е':
                return 1
            else:
                return -1
    if len(x) < len(y):
        return -1
    elif len(x) > len(y):
        return 1
    else:
        return 0
items.sort(key=cmp_to_key(comparator))
for i in items:
    print(i)
Код работает, понятно, что он не идеален и не учитывает заглавные буквы, но это можно доделать. Меня удивляет другое. Я слышал, что у питона очень развиты библиотеки работы с текстом, но я, если честно, этого не почувствовал. В java подобный компаратор создать на порядок проще - там для этого есть класс RuleBasedCollator. Неужели в питоне для такой типовой задачи надо делать костыли? Или есть более простой путь, который я не нашел? Буду рад, если вы меня просветите.
Спасибо!
З. Ы. Вообще, питон - интересный язык, можно побаловаться. Напрягают только различия 2 и 3 версий.

Офлайн

#2 Май 25, 2015 10:51:36

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

сортировка русских слов компаратором

#!/usr/bin/env python
# -* coding: utf-8 -*-
d = [u'ё', u'ель', u'ёлочка', u'ёжик', u'ё моё', u'е',  u'ельник', u'ежовый']
import sys
print (sys.version)
for i in sorted(d):
    print i

2.7.5+ (default, Sep 19 2013, 13:48:49) 
[GCC 4.8.1]
е
ежовый
ель
ельник
ё
ё моё
ёжик
ёлочка

Вроде всё правильно сортирует, нет?



Отредактировано FishHook (Май 25, 2015 10:52:22)

Офлайн

#3 Май 25, 2015 10:54:48

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2843
Репутация: +  186  -
Профиль   Отправить e-mail  

сортировка русских слов компаратором

Если не правильно, то это поможет:

sorted([u"а", u"ё", u"е"], key=ord)



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Отредактировано Rodegast (Май 25, 2015 10:55:39)

Офлайн

#4 Май 25, 2015 10:56:28

sander
Зарегистрирован: 2015-02-19
Сообщения: 317
Репутация: +  53  -
Профиль   Отправить e-mail  

сортировка русских слов компаратором

Rodegast

>>> ord('е')
1077
>>> ord('ё')
1105

Офлайн

#5 Май 25, 2015 11:17:04

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2843
Репутация: +  186  -
Профиль   Отправить e-mail  

сортировка русских слов компаратором

> в алфавите е идет перед ё
1077 < 1105
Разве что-то не так?



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#6 Май 25, 2015 11:19:20

Pawl
Зарегистрирован: 2015-05-25
Сообщения: 17
Репутация: +  0  -
Профиль   Отправить e-mail  

сортировка русских слов компаратором

sander
>>> ord('е') 1077 >>> ord('ё') 1105
понятно, а ord('я') - 1103, т. е. ё идет вообще последней буквой.
Rodegast
sorted(, key=ord)
а sorted(, key=ord) - выводит ‘е’, ‘я’, ‘ё’, т. е ё - последняя.
FishHook
d = import sys print (sys.version) for i in sorted(d): print i
тоже самое, если добавить в список слово на букву “я”, оно выведется перед словом на ё и потом, print i - это питон 2, в 3-м надо print(i), а я делаю на 3-м.

Отредактировано Pawl (Май 25, 2015 11:20:54)

Офлайн

#7 Май 25, 2015 11:29:40

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

сортировка русских слов компаратором

Да, действительно, ord, кстати, не помогает.

Тупенько, зато работает

#!/usr/bin/env python
# -* coding: utf-8 -*-
d = [u'ё', u'ель', u'ямка', u'ёлочка', u'упырь', u'ёжик', u'ё моё', u'е',  u'ельник', u'ежовый', u'ягель']
ALPHABET = {i[1]: i[0] for i in enumerate(u"абвгдеёжзийклмнопрстуфхцчшщъыьэюя")}
for i in sorted(d, key=lambda x: ALPHABET[x[0].lower()]):
    print (i)



Отредактировано FishHook (Май 25, 2015 11:30:44)

Офлайн

#8 Май 25, 2015 11:39:38

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2843
Репутация: +  186  -
Профиль   Отправить e-mail  

сортировка русских слов компаратором

Да похоже что Ё это слабое место юникода Тогда как-то так:

idx = [u"а", u"ё", u"е", u"я"]
sorted([u"а", u"ё", u"е"], key=lambda x: idx.index(x[0]))



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#9 Май 25, 2015 11:43:47

Pawl
Зарегистрирован: 2015-05-25
Сообщения: 17
Репутация: +  0  -
Профиль   Отправить e-mail  

сортировка русских слов компаратором

FishHook
Тупенько, зато работает
почему-то в таком виде
from codecs import open
from re import split
text = open("load", "r", "utf-8")
s = text.read()
words = split('[\d\W]+', s)
d = {}
for w in words:
    if w != '':
        if w in d:
            d[w] += 1
        else:
            d[w] = 1
items = list(d.items())
ALPHABET = {i[1]: i[0] for i in enumerate(u"абвгдеёжзийклмнопрстуфхцчшщъыьэюя")}
for i in sorted(items, key=lambda x: ALPHABET[x[0].lower()]):
    print(i)
когда я считываю слова из файла load в словарь d, выбрасывается ошибка
Traceback (most recent call last):
File “CUsers/Pawl/IdeaProjects/pyFirst/first.py”, line 18, in <module>
for i in sorted(items, key=lambda x: ALPHABET[x.lower()]):
File “CUsers/Pawl/IdeaProjects/pyFirst/first.py”, line 18, in <lambda>
for i in sorted(items, key=lambda x: ALPHABET[x.lower()]):
KeyError: ‘метла’

Офлайн

#10 Май 25, 2015 11:45:52

Pawl
Зарегистрирован: 2015-05-25
Сообщения: 17
Репутация: +  0  -
Профиль   Отправить e-mail  

сортировка русских слов компаратором

FishHook
Да похоже что Ё это слабое место юникода Тогда как-то так:
так тоже такая же ошибка

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version