[Из песочницы] Работа с иностранными текстами. Как увеличить процент понимания и выучить язык?
По жизни или по работе иногда приходится сталкиваться с текстами на иностранном языке, знания которого еще далеки от совершенства. Чтобы прочесть и понять, о чем идет речь (и, в лучшем случае, выучить несколько новых слов), я обычно использовал два варианта. Первый — это перевод текста в браузере, второй — перевод каждого слова по отдельности с помощью, например, ABBYY Lingvo. Но у этих методов есть множество недостатков. Во-первых, браузер предлагает перевод предложениями, а значит, он может менять порядок слов и перевод может оказаться еще более непонятным, чем оригинальный текст. Во-вторых, браузер не предлагает ни альтернативных вариантов перевода, ни синонимов к словам, а значит, учить новые слова становится проблематично. Другие варианты и синонимы можно получить при поиске конкретного слова в переводчике, а это требует некоторого времени, особенно если таких слов много. Наконец, читая текст, мне хотелось бы знать, какие слова наиболее популярны в этом языке, чтобы я мог их запомнить и потом использовать в своей письменной или разговорной речи.Я подумал, что иметь под рукой подобный «переводчик» было бы неплохо, и поэтому решил реализовать его на python. Всех, кого заинтересовало, прошу под кат.
Подсчет словПри написании программы я руководствовался следующей логикой. Сначала необходимо переписать весь текст строчными буквами, убрать ненужные знаки и символы (.?! и т.д.) и подсчитать, сколько раз каждое слово встречается в тексте. Вдохновленный кодом от Google, я сделал это без малейшего труда, но полученные результаты решил записать в несколько ином виде, а именно {1: [group of words that is with frequency 1], 2: [--//-- with frequency 2], etc.}. Это удобно, если требуется сортировка в том числе и внутри каждой группы слов, например, если мы хотим, чтобы слова шли в том же порядке, как в тексте. Итого, я хочу получить двойную сортировку: чтобы в начале шли наиболее часто встречающиеся слова, а если они встречаются с одинаковой частотой, то чтобы они были упорядочены в соответствии с исходным текстом. Эта идея получила отражение в следующем коде. def word_count_dict (filename, dictList=de500): count = {} txt = re.sub ('[,.?!»:;()*]', '', open (filename, 'r').read ().lower ()) words = txt.split () for word in words: if not word in count: count[word] = 1 else: count[word] += 1 return {i: sorted ([w for w in count if (count[w]==i and w not in dictList.values ())], key=lambda x: txt.index (x)) for i in set (count.values ())} Отлично, все работает, как и хотелось, но есть подозрение, что в топе списка будут вспомогательные слова (типа the) и другие, перевод которых очевиден (например, you). Избавиться от них можно, создав специальный список наиболее употребляемых слов, чтобы при формировании словаря исключать все слова, которые находятся в этом списке. Почему это еще удобно? Потому что, выучив нужное слово, мы можем добавить его в список, и соответствующий перевод больше не будет показан. Обозначим список переменной dictList и забудем о нем на некоторое время.Перевод слов Потратив несколько минут на поиски удобного онлайн-переводчика, решено было проверить в действии Google и Yandex. Так как ровно 3 года и 1 день назад Google закрыл Translate API, то будем использовать обходной вариант, предложенный WNeZRoS. В ответе на запрос того или иного слова Google предлагает перевод, альтернативные варианты перевода и их обратный перевод (то есть, синонимы). Использование Yandex’a как обычно требует получения ключа, и в ответе на запрос можно найти не только перевод, но и примеры, и наверное, еще что-то. В обоих случаях ответ будет содержать список в формате json, довольно простой у Google, и несколько усложненный у Yandex. По этой причине, а также потому, что Google знает больше языков (и зачастую слов), решено было остановиться именно на нем.Запросы будем отправлять с помощью замечательной библиотеки grab, а ответы записывать во вспомогательный текстовый файл (dict.txt). В нем попробуем найти основной перевод, альтернативные варианты и синонимы, и если они есть, напечатать их. Сделаем так, чтобы последние две опции можно было отключить. Соответствующий код будет выглядеть следующим образом.
def tranlsate (word, key, lan1='de', lan2='ru', alt=True, syn=True): g = Grab (log_file = 'dict.txt') link = 'http://translate.google.ru/translate_a/t? client=x&text='\ + word + '&sl=' + lan1 + '&tl=' + lan2 g.go (link) data = json.load (open ('dict.txt')) translation, noun, alternatives, synonims = 0, 0, 0, 0 try: translation = data[u’sentences'][0][u’trans'] noun = data[u’dict'][0][u’pos'] alternatives = data['dict'][0]['terms'] synonims = data['dict'][0]['entry'][0]['reverse_translation'] except: pass if lan1=='de' and noun==u’имя существительное': word = word.title () if translation: print ('['+str (key)+']', word, ': ', translation) if alt and alternatives: [print (i, end=', ') for i in alternatives] print ('\r') if syn and synonims: [print (i.encode ('cp866', errors='replace'), end=', ') for i in synonims] print ('\n') Как можно заметить, дефолтный перевод настроен с немецкого на русский. Переменная key соответствует частоте слова в тексте. Ее будем передавать из другой функции, которая и будет вызывать перевод для каждого слова.Вызов функции перевода Здесь все просто: я хочу получить группы слов с соответствующей частотой в виде словаря (функция word_count_dict) и найти перевод каждого слова (функция tranlsate). Также я хочу, чтобы были показаны только первые n групп наиболее употребляемых слов. def print_top (filename, n=100): mydict = word_count_dict (filename) mydict_keys = sorted (mydict, reverse=True)[0: n] [[tranlsate (word, key) for word in mydict[key]] for key in mydict_keys] Список наиболее употребляемых слов Отлично, программа практически готова, осталось только составить список наиболее употребляемых слов. Их легко найти в интернете, и я составил список 50, 100 и 500 наиболее употребляемых слов в немецком языке и записал его в отдельный файл, чтобы не засорять код.Если кто-то захочет составить подобный список в английском или другом языке, я буду благодарен, если он или она поделится им, чтобы я мог добавить его в свой.
Предварительные результаты Запустив программу, можно получить результаты приблизительно в следующем виде: [частота повторения слова] слово: перевод альтернативный перевод, синонимы Хорошо, код написан, программа работает, однако насколько это удобно и эффективно? Чтобы попытаться ответить на этот вопрос, я взял пару текстов на немецком языке для проверки.
Первая статья из Deutsche Welle посвящена теме финансирования добычи угля Deutsche Bank рядом с Австралией. Статья содержит 498 слов, из которых 15 наиболее часто встречаемых в тексте (воспользуемся списком 50 наиболее употребляемых немецких слов для исключения) соответствуют 16.87% всего текста. Грубо говоря, это означает, что если предположить, что человек не знает этих слов, то после прочтения перевода 6.67% всех слов, встречающихся в тексте, его уровень понимания увеличится почти на 17% (если измерять уровень понимания только количеством знакомых слов в тексте). На первый взгляд довольно неплохо.
Вторая статья из Spiegel рассказывает о том, как немецкий биржевой индекс DAX отреагировал на победу Порошенко в выборах президента на Украине (да-да, он вырос). Статья содержит 252 слова, из которых 8 наиболее встречаемых (6.06%) аналогично соответствуют 11.9% текста.
Кроме того, следует заметить, что если переводимый текст достаточно короткий, чтобы каждое слово встречалось только один раз (например, сообщение, полученное по электронной почте), то следовать предложенному переводу в том же порядке, как слова идут в тексте, весьма удобно.
Звучит красиво (es klingt schön), однако это очень грубые тесты, поскольку я ввел слишком много предпосылок. Думаю, что проверить, насколько эта идея может облегчить работу с текстами на иностранном языке, возможно лишь при некотором регулярном использовании этой программы, что, к сожалению, пока не очень удобно. Для того чтобы перевести текст нужно скопировать его сначала в .txt файл и присвоить имя файла переменной filename, а затем запустить функцию print_top.
Чего не хватает? Вместо заключения хотелось бы поразмышлять, чего не хватает на данном этапе, и как это можно было бы улучшить.Во-первых, как только что было сказано, удобства. Код использовать неудобно — нужно копировать текст, + зависимость от python и библиотеки grab. Что делать? Как вариант, написать расширение для браузера, чтобы можно было выбирать определенный элемент на странице (например, аналогично тому, как это реализовано в Reedy) и получать его перевод. Во-вторых, списка слов для исключения наиболее употребляемых на других языках. Наконец, возможны различные косяки с кодировками.
Скорее всего, в ближайшее время мои руки не дойдут до внесения вышеописанных изменений (так как код написан, пора приступать к более глубокому изучению языка!), поэтому если кто-то захочет присоединиться, я буду рад компании и помощи.
Весь код целиком можно найти под спойлером, а также на github.
Исходный код # -*- coding: utf-8-sig -*-
from __future__ import print_function import re import json from pprint import pprint from grab import Grab
from dictDe import *
def tranlsate (word, key, lan1='de', lan2='ru', alt=True, syn=True): »«Prints the number of counts, word, translation, and example from lan1 to lan2 according to Translate.Google.»« # First, write down a translation in some auxiliary txt file # and load it in json format g = Grab (log_file = 'dict.txt') link = 'http://translate.google.ru/translate_a/t? client=x&text='\ + word + '&sl=' + lan1 + '&tl=' + lan2 g.go (link) data = json.load (open ('dict.txt')) # Then, let’s try to get all the necessary elements in json translation, noun, alternatives, synonims = 0, 0, 0, 0 try: translation = data[u’sentences'][0][u’trans'] noun = data[u’dict'][0][u’pos'] alternatives = data['dict'][0]['terms'] synonims = data['dict'][0]['entry'][0]['reverse_translation'] except: pass # German nouns should begin with capital letter if lan1=='de' and noun==u’имя существительное': word = word.title () # Finally, print out counts, word, translation with alternatives # and synonims, if applicable. Encoding is added up to allow # printing in cmd if you have a russian version of Windows if translation: print ('['+str (key)+']', word, ': ', translation) if alt and alternatives: [print (i, end=', ') for i in alternatives] print ('\r') if syn and synonims: [print (i.encode ('cp866', errors='replace'), end=', ') for i in synonims] print ('\n')
def word_count_dict (filename, dictList=de50): »«Returns a dictionary with key being number of counts and value being a list of words with that key. dictList is an optional argument: it is to eliminate the most common words. Default is the dictionary of the 50 most common German words»« count = {} txt = open (filename, 'r').read ().lower () txt = re.sub ('[,.?!»:;()*]', '', txt) words = txt.split () for word in words: if not word in count: count[word] = 1 else: count[word] += 1 return {i: sorted ([w for w in count if (count[w]==i and w not in dictList.values ())], key=lambda x: txt.index (x)) for i in set (count.values ())}
def print_top (filename, n=100): »«Generates the top count groups for the given file. Default number equals 10. Drop reverse if you want to print the less frequent words in the text.»« mydict = word_count_dict (filename) mydict_keys = sorted (mydict, reverse=True)[0: n] [[tranlsate (word, key) for word in mydict[key]] for key in mydict_keys]
filename = 'dictext.txt' print (print_top (filename))