Unix, часть 2
Заходим на web-corpora.net.
ls ls /srv/data/ ls /srv/data/ngrams/ ls /srv/data/ngrams/2012-1-gram/
И обнаруживаем там 1-граммы гугла. (Т.е. частотные списки словоформ).
Вспоминаем команды, которые мы знаем:
- служебные:
- cd, pwd, ls
- cp, mv
- mkdir, rmdir, rm
- man
- less
- и для обработки текста:
- cat
- head, tail
- sort, uniq
- egrep
- tr
- wc
Есть ещё смешная команда tac – обратная к cat – вывести строки в обратном порядке. (И если уж туда пошло, то есть ещё rev – вывести строки в том же порядке, но буквы в строке в обратном порядке).
ls | tac
Посмотрим. что у нас в частотных списках есть.
ls /srv/data/ngrams/2012-1-gram/ tail /srv/data/ngrams/2012-1-gram/00001.csv less /srv/data/ngrams/2012-1-gram/00001.csv
Первая колонка – словоформа или словоформа с разбором, далее пробел, вторая колонка – частота.
Будем искать слова с фе в середине.
egrep 'фе' /srv/data/ngrams/2012-1-gram/00001.csv egrep 'фе' /srv/data/ngrams/2012-1-gram/00002.csv
По одному файлу можем.
egrep 'фе' /srv/data/ngrams/2012-1-gram/
egrep показывает содержимое файла, а не директории, директорию ему мы дать не можем.
egrep 'фе' /srv/data/ngrams/2012-1-gram/*.csv egrep 'фе' /srv/data/ngrams/2012-1-gram/*.* egrep 'фе' /srv/data/ngrams/2012-1-gram/*c* egrep 'фе' /srv/data/ngrams/2012-1-gram/*
зато мы можем дать ему все имена файлов; правда, если мы ему даём больше одного имени файла на вход, он приписывает к каждой строке выдачи имя файла, от этого нужно избавиться
egrep 'фе' /srv/data/ngrams/2012-1-gram/* -o
Не помогло
cat /srv/data/ngrams/2012-1-gram/ cat /srv/data/ngrams/2012-1-gram/* | egrep фе
cat тоже показывает содержимое файла, а не директории. Но если он собрал все файлы в один поток, то тот поток можно пофильтровать через egrep. Вообще, удобно потоковые преобразования текста начинать с cat.
cat /srv/data/ngrams/2012-1-gram/* | 'egrep' 'фе'
Кавычки в шелле не играют смысловой роли, только обозначают, что между ними пробел и некоторые спецсимволы не играют особой роли. Лучше пользоваться одинарными, они экранируют от всего, кроме самих себя. Кавычками можно окружать и имя команды – это такой же аргумент, как и все.
cat /srv/data/ngrams/2012-1-gram/* | egrep фе cat /srv/data/ngrams/2012-1-gram/* | egrep фе -c cat /srv/data/ngrams/2012-1-gram/* | egrep фе | wc
Можно выучить про десяток команд, какой у какой команды флаг про подсчёт объёма данных, но лучше пользоваться отдельной командочкой wc, которую мы можем пришлёпнуть к любой выдаче.
cat /srv/data/ngrams/2012-1-gram/* | egrep фе | sort cat /srv/data/ngrams/2012-1-gram/* | egrep фе | sort | less
С сортировкой лучше.
cat /srv/data/ngrams/2012-1-gram/* | egrep фе -i | wc cat /srv/data/ngrams/2012-1-gram/* | egrep фе -i | less
egrep -i игнорирует регистр букв. Как и в питоне параметр re.I у регулярных выражений. Как и в sed параметр /i после регулярных выражений (см. ниже), и в javascript он же. I всегда значит ignore case.
Задача всё-таки найти буквы фе в середине слова, нужно избавиться от находок, где фе по краям:
cat /srv/data/ngrams/2012-1-gram/* | egrel .фе. -i | less cat /srv/data/ngrams/2012-1-gram/* | egrep .фе. -i | wc -l
Находок многовато. Если привести всё к нижнему регистру, мы сможем избавиться от лишнего.
tr не умеет работать с русскими кодировками, особенно, с уникодом. Зато с ним умеет работать sed, который, впрочем, не очень удобен для транслитерации:
cat /srv/data/ngrams/2012-1-gram/* | egrep .фе. -i | sed -r 'y/АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ/абвгдеёжзийклмнопрстуфхцчшщъыьэюя/' | less cat /srv/data/ngrams/2012-1-gram/* | egrep .фе. -i | sed -r 'y/АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ/абвгдеёжзийклмнопрстуфхцчшщъыьэюя/' | sort | less
sed -r от слов stream text editor – очень мощный инструмент; в его основе маленький и очень простой язык программирования из двух понятий и десяти команд. Среди команд есть:
s/регвыр/замена/ – найти регулярку и заменить её на текст замены; здесь можно использовать обозначения \0, \1 ... \9 для того, чтобы подставить содержимое всей строки и скобок по номерам открывающих скобок (большинство пользователей sed считают, что кроме этой возможности в sed нет ничего, но это очень далеко от истины)
y/множество букв/множество букв/ – каждую находку буквы из первого множества заменить на соответствующую ей букву из второго множества (по правде сказать, весьма неудобная команда – мы это уже прочувствовали)
Можно доращивать наш pipeline и дальше, но давайте сохраним его результат в файл, чтобы не ждать каждый раз полминуты, пока прочитаются все файлы со всеми 1-граммами (их у гугла очень уж много).
cat /srv/data/ngrams/2012-1-gram/* | egrep .фе. -i | sed -r 'y/АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ/абвгдеёжзийклмнопрстуфхцчшщъыьэюя/' | sort > fegrams.txt ls pwd less fegrams.txt tail fegrams.txt
Вроде получилось. Теперь хотим избавиться от дубликатов.
cat fegrams.txt | sed -r 's/[_A-Z]| //' | tail cat fegrams.txt | sed -r 's/[_A-Z]*| //' | tail
Нет, так регулярные выражения не пишутся. Нам хочется взять всё от подчёркивания или пробела и до конца, и удалить, т.е. заменить на пустоту. Так и переведём же это в регулярные выражения дословно:
cat fegrams.txt | sed -r 's/[_ ].*//' | tail
Теперь можно избавиться от дублей (благо файл уже отсортирован, нам нет необходимости добавлять sort перед uniq):
cat fegrams.txt | sed -r 's/[_ ].*//' | uniq | less cat fegrams.txt | sed -r 's/[_ ].*//' | uniq | tail
Лемматизируем, чтобы убрать дубли лемм:
mystem -h cat fegrams.txt | sed -r 's/[_ ].*//' | uniq | mystem -e utf-8 -l -n | tail cat fegrams.txt | sed -r 's/[_ ].*//' | uniq | mystem -e utf-8 -l -n | uniq | wc -l
Многовато. Да и там есть альтернативы разбор1|разбор2, надо от них избавиться:
cat fegrams.txt | sed -r 's/[_ ].*//' | uniq | mystem -e utf-8 -l -n | sort | uniq | sed -r 's/\|/\n/g' | wc -l
У sed после команды s/// вплотную после третьего слэша можно ставить флаги. Самые главные два:
g – применять поиск с заменой ко всем местам в строке, а не только к первому
i – игнорировать регистр букв
Только после того, как мы разбили по | нужно снова сортировать и убирать дубли:
cat fegrams.txt | sed -r 's/[_ ].*//' | uniq | mystem -e utf-8 -l -n | sed -r 's/\|/\n/g' | sort | uniq | wc -l
Тогда уж уберём и бастардов:
cat fegrams.txt | sed -r 's/[_ ].*//' | uniq | mystem -e utf-8 -l -n | sed -r 's/\|/\n/g' | sort | uniq | egrep -v '[?]' | wc -l cat fegrams.txt | sed -r 's/[_ ].*//' | uniq | mystem -e utf-8 -l -n | sed -r 's/\|/\n/g' | sort | uniq | egrep -v '[?]' | less
И вот ещё что. После лемматизации некоторые словоформы потеряли фе. Нужно снова проверить, что он остался:
cat fegrams.txt | sed -r 's/[_ ].*//' | uniq | mystem -e utf-8 -l -n | sed -r 's/\|/\n/g' | sort | uniq | egrep -v '[?]' | egrep '.фе.' | wc -l
А вот эта командочка очень помогла мне написать конспект. Да воспоможет в этом деле она и вам!
history | less
Flask, шаблоны: циклы и условия
В flask в шаблонах можно писать такие штуковины:
Если мы это выполняем с items = [1,2,3], то получается:
То есть мы можем пройтись по списку, и для каждого элемента сгенерировать кусок шаблона. И для этого фактически никаких лишних телодвижений делать не нужно.
Аналогично существует конструкция if:
{% if ... %} {% elif ... %} {% else %} {% endif %}
которая ведёт себя совершенно аналогично питоновской, только снова вместо того, чтобы выполнять тело ветви она обрабатывает соответствующий шаблон.