{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Инфраструктура Python. Строки, даты, коллекции"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Строки"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Упоминаются библиотеки `string`, `unicodedata`, `PyICU`, `transliterate`, `base64`, `chardet`, `pycld2`, `python-Levenshtein`, `difflib`, `python-finediff`, `bsdiff4`, `re`, `regex`, `lark-parser`, `datrie`."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"AB\n",
"aaaaaBBB\n",
"65 A\n",
"Й Й\n"
]
}
],
"source": [
"print 'ABC'[:-1]\n",
"print 'a' * 5 + '\\x42' * 3\n",
"print ord('A'), chr(65)\n",
"print unichr(0x419), u'\\u0419'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Часто используемые методы строк:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True False\n",
"2\n",
"23\n",
"-1\n"
]
}
],
"source": [
"s = 'what was that? antonovka'\n",
"print s.startswith('what'), s.endswith('golden')\n",
"print s.find('a')\n",
"print s.rfind('a')\n",
"print s.find('x')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5\n"
]
}
],
"source": [
"print s.count('a')"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"what was that? antonovka\n",
"WHAT WAS THAT? ANTONOVKA\n",
"What Was That? Antonovka\n",
"What was that? antonovka\n"
]
}
],
"source": [
"print s.lower()\n",
"print s.upper()\n",
"print s.title()\n",
"print s.capitalize()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"'abc'\n",
"'__abc'\n"
]
}
],
"source": [
"print repr(' abc '.strip())\n",
"print repr('abc'.rjust(5, '_'))"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['what', 'was', 'that?', 'antonovka']\n",
"['wh', 't w', 's th', 't? ', 'ntonovk', '']\n",
"what|was|that?|antonovka\n"
]
}
],
"source": [
"print s.split()\n",
"print s.split('a')\n",
"print '|'.join(s.split())"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"wh[A]t w[A]s th[A]t? [A]ntonovk[A]\n"
]
}
],
"source": [
"print s.replace('a', '[A]')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Python поддерживает форматированный вывод в стиле C `printf`. Подробнее о форматной строке https://docs.python.org/2/library/stdtypes.html#string-formatting-operations"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"hi 00042 3.1416 deadbeef\n"
]
}
],
"source": [
"from math import pi\n",
"print '%s %05d %.4f %x' % ('hi', 42, pi, 3735928559)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"007\n"
]
}
],
"source": [
"print '%0*d' % (3, 7)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"repr is {'abc': 'def'}\n"
]
}
],
"source": [
"print 'repr is %r' % {'abc': 'def'}"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"42\n",
"hello\n"
]
}
],
"source": [
"var = 'hello'\n",
"print '%(var)d' % {'var': 42}\n",
"print '%(var)s' % globals()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Если вам понадобился аналогичный метод `str.format` со своим более мощным синтаксисом форматной строки, где-то ваша жизнь свернула не туда."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"'***1,234,567,890****'"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"'{:*^20,}'.format(1234567890)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import string"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"'this was a triumph'"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tpl = string.Template('$subj was a $obj')\n",
"tpl.substitute(subj='this', obj='triumph')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Классы символов https://docs.python.org/2/library/string.html#string-constants"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ\n",
"0123456789\n",
"True False\n"
]
}
],
"source": [
"print string.ascii_letters\n",
"print string.ascii_uppercase\n",
"print string.digits\n",
"print 'A'.isupper(), '221B'.isdigit()"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Й CYRILLIC CAPITAL LETTER SHORT I\n",
"Lu\n",
"u'\\u0418\\u0306'\n",
"CYRILLIC CAPITAL LETTER I + COMBINING BREVE\n"
]
}
],
"source": [
"import unicodedata\n",
"u = u'Й'\n",
"print unicodedata.lookup('CYRILLIC CAPITAL LETTER SHORT I'), unicodedata.name(u)\n",
"print unicodedata.category(u) # 'L'etter, 'u'ppercase\n",
"print repr(unicodedata.normalize('NFD', u))\n",
"print ' + '.join([unicodedata.name(ch) for ch in unicodedata.normalize('NFD', u)])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"NFD это способ приведения Unicode-строки, которая может записывать один и тот же видимый символ несколькими разными последовательностями Unicode-символов, к «общему знаменателю». NFD пытается каждый символ разбить на составляющие (й → и + бреве), NFC наоборот, собрать."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Для активной работы с интернационализацией и региональными языковыми стандартами используется отраслевой стандарт, библиотека ICU (International Components for Unicode) и враппер над ней `PyICU`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```\n",
"Из VC++2008 command prompt\n",
"conda list\n",
"Найти номер версии icu в списке\n",
"\n",
"set ICU_VERSION=58.2 -- подставить номер версии\n",
"set PYICU_INCLUDES=%USERPROFILE%/Anaconda2/Library/include\n",
"set LIB=%LIB%;%USERPROFILE%/Anaconda2/Library/lib\n",
"\n",
"pip install PyICU --global-option build_ext --global-option --compiler=msvc\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import icu"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ß I\n",
"SS I\n",
"SS İ\n"
]
}
],
"source": [
"s = u'ß i'\n",
"print s.upper()\n",
"print unicode(icu.UnicodeString(s).toUpper(icu.Locale('de_DE')))\n",
"print unicode(icu.UnicodeString(s).toUpper(icu.Locale('tr_TR')))"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"жикё\n",
"ёжик\n"
]
}
],
"source": [
"print ''.join(sorted(u'ёжик'))\n",
"collator = icu.Collator.createInstance(icu.Locale('ru_RU'))\n",
"print ''.join(sorted(u'ёжик', key=collator.getSortKey))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Хорошее введение в проблемы, связанные с Unicode-строками, можно найти здесь https://github.com/CppCon/CppCon2014/blob/master/Presentations/Unicode%20in%20C%2B%2B/Unicode%20in%20C%2B%2B%20-%20McNellis%20-%20CppCon%202014.pdf"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"cent vingt-trois\n"
]
}
],
"source": [
"print icu.RuleBasedNumberFormat(icu.URBNFRuleSetTag.SPELLOUT, icu.Locale('fr')).format(123)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"21 липня 2019 р. о 20:06:56\n"
]
}
],
"source": [
"from datetime import datetime\n",
"formatter = icu.DateFormat.createDateTimeInstance(icu.DateFormat.LONG, icu.DateFormat.kDefault, icu.Locale('uk_UA'))\n",
"print formatter.format(datetime.now())"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Sʺyeshʹ yeshchë etikh myagkikh frantsuzskikh bulok da vypey chayu\n"
]
}
],
"source": [
"transl = icu.Transliterator.createInstance('Russian-Latin/BGN')\n",
"print transl.transliterate('Съешь ещё этих мягких французских булок да выпей чаю')"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"578"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(list(icu.Transliterator.getAvailableIDs()))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Несколько более привычный вариант транслитерации предоставляет библиотека `transliterate`. Вообще же задача транслитерации кириллицы в латиницу непроста и насчитывает минимум 15 конкурирующих стандартов https://ru.wikipedia.org/wiki/Транслитерация_русского_алфавита_латиницей"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```\n",
"pip install transliterate\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"S'esh' esche etih mjagkih frantsuzskih bulok da vypej chaju\n"
]
}
],
"source": [
"import transliterate\n",
"print transliterate.translit(u'Съешь ещё этих мягких французских булок да выпей чаю', reversed=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Если видишь на клетке надпись \"бНОПНЯ\", не верь глазам своим. Текст был записан в кодировке CP1251, а отобразили его, считая, что это кодировка KOI8-R. https://docs.python.org/2.7/library/codecs.html#standard-encodings"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Вопрос\n"
]
}
],
"source": [
"print (u'бНОПНЯ'.encode('koi8_r').decode('cp1251'))"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"d092d0bed0bfd180d0bed181\n",
"u'\\u0412\\u043e\\u043f\\u0440\\u043e\\u0441'\n",
"'\\xd0\\x92\\xd0\\xbe\\xd0\\xbf\\xd1\\x80\\xd0\\xbe\\xd1\\x81'\n",
"c2eeeff0eef1\n"
]
}
],
"source": [
"print 'Вопрос'.encode('hex')\n",
"print repr(u'Вопрос')\n",
"print repr(u'Вопрос'.encode('utf-8'))\n",
"print u'Вопрос'.encode('cp1251').encode('hex')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"В целевой кодировке нужных символов запросто может и не оказаться, в этом случае вылетит `UnicodeEncodeError`. Избежать этого можно дополнительным параметром, сообщающим, как поступить с нетранслирующимся символом: `ignore`, `replace` или `xmlcharrefreplace`."
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Example: \n",
"Example: ????? ???????\n",
"Example: اللغة العربية\n"
]
}
],
"source": [
"s = u'Example: اللغة العربية'\n",
"print s.encode('cp1251', 'ignore')\n",
"print s.encode('cp1251', 'replace')\n",
"print s.encode('cp1251', 'xmlcharrefreplace')"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"'0JLQvtC/0YDQvtGB\\n'\n"
]
}
],
"source": [
"print repr('Вопрос'.encode('base64'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Метод `.encode('base64')` имеет неприятную привычку добавлять каждые 76 символов перевод строки. Избежать этого позволит встроенная библиотека `base64`, в которой, кроме обычного base64 реализован еще и url-safe вариант, в котором вместо неподходящих для файловых путей и URL символов `+/` используются `-_`."
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"'0JLQvtC/0YDQvtGB'\n",
"'0JLQvtC_0YDQvtGB'\n"
]
}
],
"source": [
"import base64\n",
"print repr(base64.b64encode('Вопрос'))\n",
"print repr(base64.urlsafe_b64encode('Вопрос'))"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"'BZh91AY&SYuy^a\\x00\\x00\\x03\\x00j`\\x00\\x10\\x00\\x00\\x01\\xe0\\x00 \\x001\\x0c\\x00\\x94\\x1az\\x88\\x86\\xc9\\xcd\\xf8\\xbb\\x92)\\xc2\\x84\\x83\\xab\\xca\\xf3\\x08'\n",
"'x\\x9c\\xbb0\\xe9\\xc2\\xbe\\x0b\\xfb/6\\\\\\xd8w\\xb1\\x11\\x009\\x9c\\x08\\xb1'\n"
]
}
],
"source": [
"print repr('Вопрос'.encode('bz2'))\n",
"print repr('Вопрос'.encode('zlib'))"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Вопрос\n"
]
}
],
"source": [
"print '=D0=92=D0=BE=D0=BF=D1=80=D0=BE=D1=81'.decode('quoted_printable')"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"xn--ac3c6jbe0jbbcjd.com\n"
]
}
],
"source": [
"print 'xn--' + 'Вопрос'.encode('punycode') + '.com'"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"смартхаус\n"
]
}
],
"source": [
"print '80aa8arcefjq'.decode('punycode')"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"pnrfne plcure\n"
]
}
],
"source": [
"print 'caesar cypher'.encode('rot13')"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"307\n"
]
}
],
"source": [
"import encodings.aliases\n",
"print len(encodings.aliases.aliases)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Определить кодировку может помочь библиотека `chardet`, входящая в Anaconda."
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"'\\x8f\\xe0\\xa8\\xa2\\xa5\\xe2, \\xac\\xa8\\xe0'\n"
]
}
],
"source": [
"print repr(u'Привет, мир'.encode('cp866'))"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'confidence': 0.99, 'language': 'Russian', 'encoding': 'IBM866'}\n",
"Привет, мир\n"
]
}
],
"source": [
"import chardet\n",
"bytes = '\\x8f\\xe0\\xa8\\xa2\\xa5\\xe2, \\xac\\xa8\\xe0'\n",
"cp = chardet.detect(bytes)\n",
"print cp\n",
"print bytes.decode(cp['encoding'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Для распознавания языка текста можно использовать библиотеку `pycld2`, которая является враппером над библиотекой CLD2, использующейся внутри Chrome для этой цели. Рассмотрим очень известную интернациональную фразу (из Википедии, первый вариант)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```\n",
"pip install pycld2\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import pycld2"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"phrases = '''\\\n",
"Абхазский: Апролетарцәа атәылақәа ӡегьы рҿы иҟоу, шәҽеидышәкыл!\n",
"Аварский: Тlолго дунялалъул хlалтlухъаби, цолъе нуж!\n",
"Азербайджанский: Bütün ölkələrin proletarları, birləşin!\n",
"Албанский: Punetoret e te gjithe vendeve bashkohuni!\n",
"Английский: Workers of the world, unite!\n",
"Арабский: !يا عمال العالم اتحدوا\n",
"Армянский, Восточный: Պրոլետարներ բոլոր երկրների, միացե՜ք։\n",
"Армянский, Западный: Բոլոր երկրներու աշխատաւորներ, միացէ՜ք։\n",
"Африкаанс: Werkers van alle lande, verenig!\n",
"Баскский: Herrialde guztietako proletarioak, elkar zaitezte!\n",
"Башкирский: Бөтә илдәрҙең пролетарийҙәре, берләшегеҙ!\n",
"Белорусский: Пралетарыі ўсіх краін, яднайцеся!\n",
"Бенгальский: দুনিযার মজদুর, এক হও!\n",
"Боснийский: Proleteri svih zemalja, ujedinite se!\n",
"Болгарский: Пролетарии от всички страни, съединявайте се!\n",
"Бурятский: Бүхы оронуудай пролетаринар, нэгэдэгты!\n",
"Валлийский: Gweithwyr yr holl wledydd, uno!\n",
"Венгерский: Világ proletárjai, egyesüljetek!\n",
"Вьетнамский: Vô sản toàn thế giới, đoàn kết lại!\n",
"Гаитянский креольский: Travayè nan tout peyi, ini!\n",
"Галисийский: Traballadores do mundo, unídevos!\n",
"Грузинский: პროლეტარებო ყველა ქვეყნისა, შეერთდით!\n",
"Греческий: Προλετάριοι όλων των χωρών, ενωθείτε!\n",
"Гуджарати: બધા દેશોમાં કામદાર સંગઠિત!\n",
"Датский: Proletarer i alle lande, foren jer!\n",
"Иврит: !פועלי כל העולם התאחדו\n",
"Идиш: !פראָלעטאריער פון אלע לענדער, פאראייניקט זיך\n",
"Индонезийский: Para pekerja di seluruh dunia, bersatulah!\n",
"Ирландский: Oibrithe an domhain, aontaigh!\n",
"Исландский: Verkamenn allra landa, sameinist!\n",
"Испанский: ¡Trabajadores del mundo, uníos!\n",
"Итальянский: Lavoratori di tutto il mondo, unitevi!\n",
"Казахский: Барлық елдердің пролетарлары, бірігіңдер!\n",
"Калмыцкий: Цуг орн-нутгудын пролетармуд, нэгдцхәтн!\n",
"Каннада: ಎಲ್ಲಾ ದೇಶಗಳ ಸಹೋದ್ಯೋಗಿಗಳು, ಯುನೈಟ್!\n",
"Карачаево-балкарский: Бютеу дунияны пролетарлары, бирлешигиз!\n",
"Карельский: Kaikkien maiden proletaarit, liittykää yhteen!\n",
"Каталанский: Proletaris de tots els països, uniu-vos!\n",
"Китайский (КНР): 全世界无产者,联合起来!\n",
"Китайский (Тайвань): 全世界無產者,聯合起來!\n",
"Коми: Став мувывса пролетарийяс, отувтчöй!\n",
"Корейский: 만국의 노동자여, 단결하라!\n",
"Крымскотатарский: Bütün memleketlerniñ proletarları, birleş!\n",
"Курдский: Kirêkaranî/karkerên dinya/cîhanê yekgirin/hevgirin!\n",
"Киргизский: Бардык өлкөлөрдүн пролетарлары, бириккиле!\n",
"Латынь: Laborantes universis terris iunguntur!\n",
"Латышский: Visu zemju proletārieši, savienojieties!\n",
"Литовский: Visų šalių proletarai, vienykitės!\n",
"Македонский: Пролетери од сите земји, обединете се!\n",
"Малагасийский: Mpiasa eran’izao tontolo izao, mampiray!\n",
"Малайский: Pekerja semua negara, bersatu!\n",
"Мальтийский: Ħaddiema tal-pajjiżi kollha, jingħaqdu!!\n",
"Марийский: Чыла элласе пролетарий-влак ушныза\n",
"Молдавский: Proletari din toate ţările, uniţi-vă!\n",
"Монгольский: Орон бүрийн пролетари нар нэгдэгтүн!\n",
"Немецкий: Proletarier aller Länder, vereinigt Euch!\n",
"Нидерландский: Proletariërs aller landen, verenigt U!\n",
"Норвежский, Букмол: Arbeidere i alle land, foren dere!\n",
"Норвежский, Нюнорск: Arbeidarar i alle land, samein dykk!\n",
"Окситанский: Proletaris de totes los païses, unissètz-vos!\n",
"Осетинский: Ӕппӕт бӕстӕты пролетартӕ, баиу ут!\n",
"Персидский: کارگران جهان متحد شوید\n",
"Польский: Proletariusze wszystkich krajów, łączcie się!\n",
"Португальский: Trabalhadores do mundo, uni-vos!\n",
"Румынский: Proletari din toate ţările, uniţi-vă!\n",
"Сербский: Пролетери свих земаља, уједините се!\n",
"Словацкий: Proletári všetkých krajín, spojte sa!\n",
"Словенский: Proletarci vse dezel, zdruzite se!\n",
"Суахили: Wafanyakazi wa nchi zote, kuungana!\n",
"Таджикский: Пролетарҳои ҳамаи мамлакатҳо, як шавед!\n",
"Тайский: แรงงานจากทุกประเทศรวมกัน!\n",
"Тамильский: அனைத்து நாடுகளின் தொழிலாளர்கள், இணைக்க!\n",
"Татарский: Барлык илләрнең пролетарийлары, берләшегез!\n",
"Телугу: అన్ని దేశాల వర్కర్స్, ఐక్యం!\n",
"Тувинский: Бүгү чурттарның пролетарийлери, каттыжыңар!\n",
"Турецкий: Bütün ülkelerin işçileri, birleşin!\n",
"Туркменский: Ähli ýurtlaryň proletarlary, birleşiň!\n",
"Удмуртский: Вань кунъёсысь пролетарийёс, огазеяське!\n",
"Узбекский: Butun dunyo proletarlari, birlashingiz!\n",
"Украинский: Пролетарі всіх країн, єднайтеся!\n",
"Урду: !،تمام ممالک کے ورکرز متحد\n",
"Филиппинский: Mga manggagawa ng mundo, magkaisa!\n",
"Финский: Kaikkien maiden proletaarit, liittykää yhteen!\n",
"Французский: Prolétaires de tous les pays, unissez-vous!\n",
"Хинди: दुनिया के मज़दूरों, एक हों!\n",
"Хорватский: Proleteri svih zemalja, ujedinite se!\n",
"Чешский: Proletáři všech zemí, spojte se!\n",
"Чувашский: Пĕтĕм тĕнчери пролетарисем, пĕрлешĕр!\n",
"Шведский: Arbetare i alla länder, förenen eder!\n",
"Эсперанто: Proletoj el ĉiuj landoj, unuiĝu!\n",
"Эстонский: Kõigi maade proletaarlased, ühinege!\n",
"Якутский: Бүтүн дойдулар пролетарийдара, биир буолуҥ!\n",
"Японский: 万国の労働者よ、団結せよ!\n",
"'''.splitlines()"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"93"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(phrases)"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Абхазский ('ABKHAZIAN', 'ab', 98, 800.0)\n",
"Аварский ('Unknown', 'un', 0, 0.0)\n",
"Азербайджанский ('AZERBAIJANI', 'az', 97, 1313.0)\n",
"Албанский ('ALBANIAN', 'sq', 97, 1148.0)\n",
"Английский ('ENGLISH', 'en', 96, 1289.0)\n",
"Арабский ('ARABIC', 'ar', 97, 640.0)\n",
"Армянский, Восточный ('ARMENIAN', 'hy', 100, 1024.0)\n",
"Армянский, Западный ('ARMENIAN', 'hy', 100, 1024.0)\n",
"Африкаанс ('AFRIKAANS', 'af', 96, 495.0)\n",
"Баскский ('BASQUE', 'eu', 98, 1755.0)\n",
"Башкирский ('BASHKIR', 'ba', 98, 781.0)\n",
"Белорусский ('BELARUSIAN', 'be', 98, 614.0)\n",
"Бенгальский ('BENGALI', 'bn', 98, 433.0)\n",
"Боснийский ('CROATIAN', 'hr', 97, 625.0)\n",
"Болгарский ('BULGARIAN', 'bg', 98, 786.0)\n",
"Бурятский ('MONGOLIAN', 'mn', 98, 568.0)\n",
"Валлийский ('WELSH', 'cy', 96, 1843.0)\n",
"Венгерский ('HUNGARIAN', 'hu', 97, 1505.0)\n",
"Вьетнамский ('VIETNAMESE', 'vi', 97, 1472.0)\n",
"Гаитянский креольский ('HAITIAN_CREOLE', 'ht', 96, 1251.0)\n",
"Галисийский ('GALICIAN', 'gl', 97, 682.0)\n",
"Грузинский ('GEORGIAN', 'ka', 100, 1024.0)\n",
"Греческий ('GREEK', 'el', 100, 1024.0)\n",
"Гуджарати ('GUJARATI', 'gu', 100, 1024.0)\n",
"Датский ('Unknown', 'un', 0, 0.0)\n",
"Иврит ('HEBREW', 'iw', 97, 972.0)\n",
"Идиш ('YIDDISH', 'yi', 98, 1113.0)\n",
"Индонезийский ('INDONESIAN', 'id', 97, 1348.0)\n",
"Ирландский ('IRISH', 'ga', 96, 1624.0)\n",
"Исландский ('ICELANDIC', 'is', 96, 448.0)\n",
"Испанский ('GALICIAN', 'gl', 96, 648.0)\n",
"Итальянский ('ITALIAN', 'it', 97, 802.0)\n",
"Казахский ('KAZAKH', 'kk', 98, 727.0)\n",
"Калмыцкий ('MONGOLIAN', 'mn', 98, 406.0)\n",
"Каннада ('KANNADA', 'kn', 100, 1024.0)\n",
"Карачаево-балкарский ('TURKMEN', 'tk', 98, 341.0)\n",
"Карельский ('FINNISH', 'fi', 97, 806.0)\n",
"Каталанский ('CATALAN', 'ca', 97, 844.0)\n",
"Китайский (КНР) ('Chinese', 'zh', 96, 1984.0)\n",
"Китайский (Тайвань) ('ChineseT', 'zh-Hant', 96, 1920.0)\n",
"Коми ('Unknown', 'un', 0, 0.0)\n",
"Корейский ('Korean', 'ko', 97, 3754.0)\n",
"Крымскотатарский ('TURKISH', 'tr', 97, 1024.0)\n",
"Курдский ('Unknown', 'un', 0, 0.0)\n",
"Киргизский ('KYRGYZ', 'ky', 98, 682.0)\n",
"Латынь ('LATIN', 'la', 97, 512.0)\n",
"Латышский ('LATVIAN', 'lv', 97, 1448.0)\n",
"Литовский ('LITHUANIAN', 'lt', 97, 1328.0)\n",
"Македонский ('MACEDONIAN', 'mk', 98, 1008.0)\n",
"Малагасийский ('MALAGASY', 'mg', 97, 1076.0)\n",
"Малайский ('INDONESIAN', 'id', 96, 1483.0)\n",
"Мальтийский ('MALTESE', 'mt', 97, 1923.0)\n",
"Марийский ('Unknown', 'un', 0, 0.0)\n",
"Молдавский ('ROMANIAN', 'ro', 97, 998.0)\n",
"Монгольский ('MONGOLIAN', 'mn', 98, 657.0)\n",
"Немецкий ('GERMAN', 'de', 97, 599.0)\n",
"Нидерландский ('DUTCH', 'nl', 97, 646.0)\n",
"Норвежский, Букмол ('NORWEGIAN', 'no', 97, 899.0)\n",
"Норвежский, Нюнорск ('NORWEGIAN_N', 'nn', 97, 526.0)\n",
"Окситанский ('OCCITAN', 'oc', 97, 734.0)\n",
"Осетинский ('Unknown', 'un', 0, 0.0)\n",
"Персидский ('PERSIAN', 'fa', 97, 755.0)\n",
"Польский ('POLISH', 'pl', 97, 1706.0)\n",
"Португальский ('PORTUGUESE', 'pt', 96, 660.0)\n",
"Румынский ('ROMANIAN', 'ro', 97, 998.0)\n",
"Сербский ('SERBIAN', 'sr', 98, 1008.0)\n",
"Словацкий ('SLOVAK', 'sk', 97, 1356.0)\n",
"Словенский ('SLOVENIAN', 'sl', 97, 496.0)\n",
"Суахили ('SWAHILI', 'sw', 97, 1234.0)\n",
"Таджикский ('TAJIK', 'tg', 98, 1096.0)\n",
"Тайский ('THAI', 'th', 100, 1024.0)\n",
"Тамильский ('TAMIL', 'ta', 100, 1024.0)\n",
"Татарский ('TATAR', 'tt', 98, 793.0)\n",
"Телугу ('TELUGU', 'te', 100, 1024.0)\n",
"Тувинский ('Unknown', 'un', 0, 0.0)\n",
"Турецкий ('TURKISH', 'tr', 97, 1459.0)\n",
"Туркменский ('TURKMEN', 'tk', 97, 1219.0)\n",
"Удмуртский ('Unknown', 'un', 0, 0.0)\n",
"Узбекский ('UZBEK', 'uz', 97, 835.0)\n",
"Украинский ('UKRAINIAN', 'uk', 98, 759.0)\n",
"Урду ('URDU', 'ur', 97, 1069.0)\n",
"Филиппинский ('TAGALOG', 'tl', 97, 1303.0)\n",
"Финский ('FINNISH', 'fi', 97, 806.0)\n",
"Французский ('FRENCH', 'fr', 97, 1047.0)\n",
"Хинди ('HINDI', 'hi', 98, 587.0)\n",
"Хорватский ('CROATIAN', 'hr', 97, 625.0)\n",
"Чешский ('CZECH', 'cs', 97, 848.0)\n",
"Чувашский ('Unknown', 'un', 0, 0.0)\n",
"Шведский ('SWEDISH', 'sv', 97, 673.0)\n",
"Эсперанто ('ESPERANTO', 'eo', 97, 1086.0)\n",
"Эстонский ('ESTONIAN', 'et', 97, 525.0)\n",
"Якутский ('Unknown', 'un', 0, 0.0)\n",
"Японский ('Japanese', 'ja', 97, 2720.0)\n"
]
}
],
"source": [
"for phrase in phrases:\n",
" lang, text = phrase.split(': ')\n",
" print lang, pycld2.detect(text)[2][0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"CLD2 не угадал языки (вместо этого решил, что): аварский, боснийский (хорватский), бурятский (монгольский), датский, испанский (галисийский), калмыцкий (монгольский), карачаево-балкарский (туркменский), карельский (финский), коми, крымско-татарский (турецкий), курдский, малайский (индонезийский), марийский, молдавский (румынский), осетинский, тувинский, удмуртский, чувашский, якутский.\n",
"\n",
"74/93."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Расстояние Левенштейна (библиотека `python-Levenshtein`) и генерирование диффов (дельт) над строками (встроенная библиотека `difflib` и дающая обычно лучшие результаты библиотека `python-finediff`)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```\n",
"pip install python-Levenshtein\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3\n",
"[('delete', 0, 0), ('replace', 2, 1), ('insert', 6, 5)]\n"
]
}
],
"source": [
"import Levenshtein\n",
"print Levenshtein.distance('abcdef', 'badefo')\n",
"print Levenshtein.editops('abcdef', 'badefo')"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['+ b', ' a', '- b', '- c', ' d', ' e', ' f', '+ o']"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import difflib\n",
"list(difflib.Differ().compare('abcdef', 'badefo'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```\n",
"pip install https://github.com/sharpden/python-finediff/tarball/master\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"'abcadefo'"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import finediff\n",
"finediff.FineDiff('abcdef', 'badefo').renderDiffToHTML()"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def show_diff(A, B, engine='finediff', format='html'):\n",
" def compact_difflib_diff(A, B):\n",
" import difflib\n",
" prev_type = ''\n",
" s = []\n",
" for typ, _, ch in difflib.Differ().compare(A, B):\n",
" if prev_type != typ and prev_type:\n",
" yield prev_type, ''.join(s)\n",
" s = []\n",
" prev_type = typ\n",
" s.append(ch)\n",
" if s:\n",
" yield prev_type, ''.join(s)\n",
" \n",
" def compact_finediff_diff(A, B):\n",
" import finediff\n",
" fd = finediff.FineDiff(A, B)\n",
" in_offset = 0\n",
" result = []\n",
" for edit in fd.getOps():\n",
" n = edit.getFromLen()\n",
" if isinstance(edit, finediff.FineDiffCopyOp):\n",
" yield ' ', A[in_offset : in_offset + n]\n",
" elif isinstance(edit, finediff.FineDiffDeleteOp):\n",
" yield '-', A[in_offset : in_offset + n]\n",
" elif isinstance(edit, finediff.FineDiffInsertOp):\n",
" yield '+', edit.getText()\n",
" else: # elif isinstance(edit, finediff.FineDiffReplaceOp):\n",
" yield '-', A[in_offset : in_offset + n]\n",
" yield '+', edit.getText()\n",
" in_offset += n\n",
" \n",
" if engine == 'finediff':\n",
" generator = compact_finediff_diff\n",
" elif engine == 'difflib':\n",
" generator = compact_difflib_diff\n",
"\n",
" if format == 'html':\n",
" import IPython, cgi\n",
" html = []\n",
" for typ, s in generator(A, B):\n",
" if typ == ' ':\n",
" html.append(cgi.escape(s))\n",
" elif typ == '-':\n",
" html.append('' + cgi.escape(s) + '')\n",
" elif typ == '+':\n",
" html.append('' + cgi.escape(s) + '')\n",
" html = ''.join(html)\n",
" html = '''\\\n",
" \n",
"
%s\n", " ''' % html\n", " IPython.display.display(IPython.display.HTML(html))\n", " elif format == 'text':\n", " from colorama import Fore, Back, Style\n", " result = []\n", " for typ, s in generator(A, B):\n", " if typ == ' ':\n", " result.append(s)\n", " elif typ == '-':\n", " result.append(Fore.YELLOW + Back.RED + s + Style.RESET_ALL + Fore.BLACK)\n", " elif typ == '+':\n", " result.append(Fore.YELLOW + Back.GREEN + s + Style.RESET_ALL + Fore.BLACK)\n", " print ''.join(result)" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ " \n", "
\n", " " ], "text/plain": [ "abcadefo
string | timelib.strtodatetime | dateutil.parser.parse | parsedatetime.Calendar().parseDT |
---|---|---|---|
May 21, 2016 | 2016-05-21 00:00:00 | 2016-05-21 00:00:00 | 2016-05-21 20:07:01 |
15/05/2016 | Unexpected character (while parsing date '15/05/2016') | 2016-05-15 00:00:00 | 2019-07-21 20:07:01 |
15.05.2016 00:03:05+4:00 | 2016-05-15 00:03:05 | 2016-05-15 00:03:05+04:00 | 2019-07-21 00:03:05 |
friday | 2019-07-26 00:00:00 | 2019-07-26 00:00:00 | 2019-07-26 20:07:01 |
2012/12/30 05:20:21+2 | 2012-12-30 05:20:21 | 2012-12-30 05:20:21+02:00 | 2012-12-30 05:20:21 |
now -1 month | 2019-06-21 17:07:01 | (u'Unknown string format:', 'now -1 month') | 2019-06-21 20:07:01 |
next Easter | The timezone could not be found in the database (while parsing date 'next Easter') | (u'Unknown string format:', 'next Easter') | 2019-07-21 20:07:01 |
+1d | 2019-07-21 17:07:01 | (u'Unknown string format:', '+1d') | 2019-07-22 20:07:01 |
previous Friday | 2019-07-19 00:00:00 | (u'Unknown string format:', 'previous Friday') | 2019-07-19 09:00:00 |
week ago | The timezone could not be found in the database (while parsing date 'week ago') | (u'Unknown string format:', 'week ago') | 2019-07-21 20:07:01 |
last Saturday | 2019-07-20 00:00:00 | (u'Unknown string format:', 'last Saturday') | 2019-07-20 09:00:00 |
08 Mar 1908 | 1908-03-08 00:00:00 | 1908-03-08 00:00:00 | 1908-03-08 20:07:01 |
1917-07-11 21:40 | 1917-07-11 21:40:00 | 1917-07-11 21:40:00 | 1917-07-11 21:40:00 |