программирование
Python iterstrip: itertools для чайников
Я общел рассказать как работает конструкция, которую мы, в итоге, в Ваней породили для тех, кто не знаком с itertools в Python. Для начала формулировка задачи: есть список (list) последовательности строк. В нём все поледовательности пустых строк, длиной более двух надо заменить на одну пустую строку, а пустые строке в начале и конце списка удалить.
Из [’’, 1, 2, 3, ’’, ’’, ’’, ’’, 4, ’’, ’’] мы должны получить аккуратное [1, 2, 3, ’’, 4].
Код, который получился в итоге, с некоторыми упращениями, выглядит вот так:
return list(
chain(
*(
[[''], grp][item or len(grp)<3]
for item, grp in (item, list(grp))
for item, grp in groupby(chain(['']*3, letter, ['']*3), lambda x:x))
)
)
)[1:-1]Заголовок функции я приводить не буду, чтобы не плодить отступы, в функцию входит параметр letter, который содержит обрабатываемый список, возвращается, соответственно, обработанный список. Я постараюсь обойтись без определения генераторов и итераторов, просто представьте, что данные «текут» по функциям, что позволяет их обрабатывать очень экономично, даже если они бесконечные.
Центральное место этой программы, функция groupby группирует входящий список, пользуясь результатом функции, записанной во втором параметре, как признаком группировки. Список не пересортируются, в группы объединяются данные, идущие подряд. На выходе появляется список туплов (tuples), состоящих из результата работы функции, применительно к группе и списка (точнее объекта _grouper) объединённых результатов:
[(x, list(k)) for x, k
Я тут прошёлся по списку [1, 2, 3, -4, -1, 2], объединяя его значения при помощи функции x>=0. Т. е. все подряд идущие числа с одинаковым знаком будут сгруппированы. Получится вот что:
[(True, [1, 2, 3]), (False,
сверху на groupby я навесил генератор — по сути, цикл, который проходит по всем элементам groupby, раскладывая тупл (tuple) в два элемента — x и k. Этот цикл для каждой итерации возвращает результат, форма которого записана перед циклом. Это тупл, состоящий из двух элементов: k (где записан результат группировочной функции) я оставил неизменным, а объект _grouper я преобразовал в список.
Функция chain объединяет итератор, для простоты можно пока представить, что она склеивает списки. Конструкция «[’’]*3» эквивалентна [’’, ’’, ’’] — трём пустым строкам. Таким образом, строка «for item, grp in groupby(chain([’’]*3, letter, [’’]*3), lambda x:x))» делает следующее: по итератору, состоящему из трёх пустых строк, нашего списка letter и ещё трёх пустых строк, проходит функция groupby, которая группирует элементы по самому простому признаку: «lambda x: x», т. е. группируются одинаковые элементы, далее по получившемуся списку туплов проходит цикл, каждый тупл раскладывается на два элемента: item и grp, где из grp делается список (при помощи вызова «list»).
Выше находится конструкция «[ [’’, grp] ][item or len(grp)<n]», выглядит она страшно и кажется «птичим языком», но на деле широко применяется в самых разнообразных языках, включая PHP, сейчас я её объясню. Результатом «item or len(grp)<n» будет True или False. Условие, на мой взгляд, очевидное: если строка не пустая или последовательность меньше 3, то True. True и False используются как индекс списка и выбирают, соответственно, первый или нулевой элемент массива, т. е. список, содержащий пустую строку или группу символов.
Цепочка такая:
Иcходная последовательность: [’’, ’1’, ’1’, ’’, ’’, ’’, ’3’, ’’, ’5’] Добавили с двух сторон пробельные строки: [’’, ’’, ’’, ’’, ’1’, ’1’, ’’, ’’, ’3’, ’’, ’5’, ’’, ’’, ’’] Прошли groupby и генератор: [ (’’, [’’, ’’, ’’, ’’]), (’1’, [’1’, ’1’]), (’’, [’’, ’’]), (’3’, [’3’]), (’’, [’’]), (’5’, [’5’]), (’’, [’’, ’’, ’’]) ] Прошли через условие на птичьем языке: [ [’’], [’1’, ’1’], [’’, ’’], [’3’], [’’], [’5’], [’’] ]
Далее у нас стоит chain, который принимает аргументом всё, что получилось, но с префиксом звёздочка. Chain, как я писал выше, объединяет итераторы, для простоты мы считаем, что это, с натяжкой, эквивалентно объединению списков. У нас есть список, содержащий списки. Хорошо бы эти списки склеить.
В PHP есть функция call_user_func_array, которая принимает на вход два параметра: фукнцию, которую надо вызывать и массив её параметров. В PHP я бы склеил эти списки вот так: call_user_func_array(’array_merge’, $letter). В Python делается всё то же самое, только синтаксис этого вызова другой: func(*args). Это означает, что когда будет вызвана функция func, список args станет списком её аргументов, chain принимает на вход любое количество элементов.
Таким образом мы получим вызов chain(*[ [’’], [’1’, ’1’], [’’, ’’], [’3’], [’’], [’5’], [’’] ]), что эквивалентно chain([’’], [’1’, ’1’], [’’, ’’], [’3’], [’’], [’5’], [’’]). На выходе мы получим следующий итератор, который как список выглядит вот так: [’’, ’1’, ’1’, ’’, ’’, ’3’, ’’, ’5’, ’’].
Легко заметить, что какое бы количество пробельных строк не было по краям, в конце всегда остаётся по одной. От них нам нужно избавиться. Делается это просто, в Python есть срезы, которыми я и пользуюсь: список[1: -1] означает «вернуть список с первого элемента, убрав ещё один с конца». В PHP это будет array_slice($list, 1, -1).
В итоге [’’, ’1’, ’1’, ’’, ’’, ’3’, ’’, ’5’,
Мда.
Спираль истории: @font-face
Когда на земле было всего два браузера — IE и Netscape Navigator, они оба поддерживали разные виды внедряемых шрифтов. IE поддерживал своё, но бесплатное решение, Netscape использовал платное решение от BitStream. В те времена вебмастера интересовались возможностями браузеров ещё меньше, чем сейчас и этой возможностью мало кто пользовался.
Хотя в Татарстане, где я жил, технологию внедряемых шрифтов использовали очень часто для поддержки татарского алфавита на сайтах.
Суть технологии очень проста: шрифт подключается как любой внешний ресурс (другие примеры — графика, CSS, JS) и им можно писать
На данный момент, оказывается, во всех браузерах, включая альтернативный,
- у Internet Explorer есть наиболее удачная из всего зоопарка разработка — поддержка шрифтов в формате EOT
- у Opera эта поддержка есть в лабораторном билде, значит появится и в самом браузере (поддерживается TTF)
- Safari (WebKit) поддерживает эту технологию ещё с октября прошлого года
- у FireFox, вероятно, поддержка появится в версии 3.1, по крайней мере сейчас существуют сборки, в которых она уже есть
Хочу сразу сказать почему я считаю, что у IE наиболее удачное решение: разработчик может указать какие именно знаки оставить в шрифте, что даёт огромную экономию по размеру. Другие же браузеры поддерживают шрифты в форматах TrueTypeFont и OpenType. Легко представить к чему это приведёт: подключать будут гигантскиеUnicode-шрифты, содержащие всё что только возможно, вплоть до вымерших алфавитов.
PHP: мануалы читать необходимо
Я изучаю новый язык следующим образом: сначала всегда полностью читаю руководство (вот с «Пайтоном» мне не повезло — в руководстве, которое я выбрал, об itertools было упомянуто вскользь), потом уже пробую
Конечно, руководство полностью наизусть я не помню, но зато всегда помню, что
В свежей статье на «Хабре» — один из подобных велосипедов:
function uptime() {
$fp=@popen('uptime','r');
$s=@fgets($fp);
@fclose($fp);
@preg_match('#load average: ([0-9\.]+)#', $s, $m);
return $m[1];
};В этой статье вообще масса забавного: в разделе «временные припарки», где index.php заменили для снятия нагрузки,
Расширение RSS: «Яндекс», поиск по блогам
«Яндекс» выпустил специальный
В чём же заключается смысл плагина? Поскольку я в курсе, давайте расскажу.
Сервис поиска по блогам «Яндекса», как вытекает из названия, индексирует блоги и многим кажется, что на этом его отличие от основного поиска заканчивается. Как бы не так! Поисковик «Яндекса» индексирует
Проблема, как несложно догадаться, в том, что существую сайты, которые старше сервиса, а так же такие, до которых поисковик добрался недавно. Львиную часть их содержимого индексатор поиска по блогам не видит — из RSS они
Дима с командой поиска по блогам придумали очень простую и эффективную штуку. RSS — формат расширяемый, для него уже масса расширений, это нормальная практика. Если заглянуть в RSS любого диминого сайта, то можно увидеть, что в нём упоминается новое расширение: «ya:more», т. е. новый тег «more» в пространстве имён «ya».
Для того, чтобы его использовать, в тег «rss» нужно дописать строку
xmlns:ya="http://blogs.yandex.ru/"и вставить тег «ya:more», содержащий URL, указывающий на RSS, содержащий предыдущие N постов:
<rss xmlns:ya="http://blogs.yandex.ru/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" version="2.0">
<ya:more>http://coprophagous.ru/rss/posts/740</ya:more>Получается много связанных этим тегом документов, в последнем из которых тег «ya:more» отсутствует. Таким образом индексатор поиска по блогам может пройтись по всем постам блога и проиндексировать их. СЕОшники должны оценить.
Заслуга Димы заключается не только в том, что он придумал простое решение проблемы и мотивировал команду поиска реализовать её, но ещё и в том, что он написал готовые плагины, которые добавляют эту функциональность для трёх популярных форумов на языке PHP: PHPBB, vBulletin и IP.Board.
Кроме этого, формат позволяет индексировать и комментарии к записям, в том числе и древовидные. Подробнее об этом можно прочитать в файле readme.html, который находится внутри архива с плагинами.
Chrome: не к добру
Интересно, через какое время сообщество обнаружит about:network в «Хроме», научится включать «I/O Tracking», увидит там, что каждый день «Хром» качает
И сколько умных людей сходит в поисковик и выяснит, что это подгрузка чёрных и белых списков фишинговых и вредоносных сайтов (Safe Browsing API)?
Речь идёт об URL вида «http://static.cache.l.google.com/safebrowsing/» и других со словом «safe», браузер сначала получает данные о том, что ему нужно получить, а потом потихоньку скачивает необходимые данные. Кстати, Google Safe Browsing используется и в FireFox3.
IE8beta2: ACID3
Opera 9.60beta1 — 85% FireFox 3.1 beta1 — 85% Chrome 0.2 beta — 79% WebKit r36309 — падает на 26% Internet Explorer 8 beta 2 — 21%
Ошибка в валидации поля: виноват PHP
function validateDigit(e) {
var re = /[0-9x0Dx08]/i;
var code;
if (!e || !e.which) {
if (window.event) {
code = event.keyCode;
}
}
else code = e.which;
if(!code) return;
if (!re.test(String.fromCharCode(code))) return false;
}Что бывает от невнимательности (скрипт с сайта управления ГИБДД МВД от РТ): пропали слеши и в поле ввода вводятся буквы «d» и «x». А всё от stripslashes.
Chrome: война клоническая началась
Хорошо, я выскажусь о «Хроме», тем более многие ждут. К «Хрому» я абсолютно равнодушен, вплоть до того, что даже его не поставил и не удосужился
Microsoft взялась серьёзно за браузер: IE8
Microsoft серьёзно взялась за стандартизацию своего браузера. В блоге IE появилась статья, где рассказывается о дальнейших шагах по преобразованию браузера. Например, все расширения CSS будут теперь начинаться с префикса
Хорошая новость: фильтры будут! только теперь они будут называться
Для сайтов, которые переделать невозможно
PHP: compliler_halt_offset
Малоизвестная возможность PHP, появившаяся с версии 5.1 — аналог секции DOC из Perl. Позволяет создать специальную текстовую секцию в конце файла скрипта, откуда можно будет читать данные, например, туда можно поместить страницу помощи к программе
Секция начинается вызовом специальной конструкции __halt_compiler(), всё, что дальше этой строки интерпретатор не считывает и не выполняет. Смещение, по которому начинаются данные за конструкцией, доступно через константу __COMPILER_HALT_OFFSET__. Почему нельзя было сделать константу, указывающую на файловый ресурс (по аналогии с STDERR) для меня загадка.
Использовать можно, например, так:
echo file_get_contents(__FILE__, null, null, __COMPILER_HALT_OFFSET__);
// the end of the script execution
__halt_compiler();Hello, world!На печать программа выведет строку «Hello, world!».
Python
Memcached
Люди, не используйте memcached, если можно этого не делать! Статьи на «Хабре» говорят о том, что:
a) люди не понимают когда нужно использовать memcached, а когда нельзя б) люди не знают о других способах использования разделяемой памяти, memcached самый «раскрученный»
IE8beta2
Вышла вторая бета Internet Explorer 8.0, в списке поддерживаемых операционных систем
Печальная новость — CSS expression больше не будут функционировать стандартном режиме этого браузера, но они всё ещё поддерживаются в режимах IE7Strict и IE7Quirks. Не понимаю для чего это. Как теперь эмулировать недостающее?
Интересных новых штук несколько: новая стартовая страница, цветные закладки, нормальный autocomplete строки адреса. Из технических штук мне понравились методы для безопасного разбора и проверки JSON (JSON.parse, JSON.stringify).
DOM storage, XDomainRequest и Connectivity Events были, кажется, и в первой бете.
Ощущение, что ребята серьёзно взялись за свой браузер. С версии 8.5 это даже можно будет использовать.
Ogg и тег VIDEO, ActiveX Canvas для IE
Из других интересных новостей — Vladimir Vukićević разработал ActiveX для IE, который повторяет функциональность этого тега пока только частично, но работа продолжается. Тот же автор обещает в будущем поддержку тегов video и audio, тоже, видимо, в формате ActiveX.
HTML5 и IE
Оказывается, есть немного кривой, но способ заставить IE показывать незнакомые ему теги в глобальном namespace! В частности, это поможет уже сейчас использовать семантические теги из HTML5.
Решение основано на интересном хаке:
Btw, if you want CSS rules to apply to unknown elements in IE, you just have to do document.createElement(elementName). This somehow lets the CSS engine know that elements with that name exist.
Есть другое решение, но оно требует использования namespace. В IE есть всеми забытая технология custom tags. Когда появился черновик HTML5 я пытался использовать её, чтобы внедрить в документ новые теги:
<html xmlns:html5="http://www.w3.org/html/wg/html5/">
<head>
<style type="text/css">
html5\:footer {
display: block;
border: 1px solid black;
padding: 10px;
}
</style>
</head>
<body>
<html5:footer>This is footer!</html5:footer>
</body>
</html>Не совсем то, что нужно, если не использовать сторонние средства. Если использовать, то для альтернативного браузера можно оставлять как есть, а для правильных — вычищать ненужное пространство заменой на уровне
Далее дело техники. Например, если взять Nginx, в нём есть модули rewrite, browser и sub. Первый умеет выполнять условия, второй — определять браузеры, третий — заменять одну строку на другую. Получается
modern_browser msie 1.0;
if ($ancient_browser) {
sub_filter 'html5:' ''
}Надо сразу оговориться, что это не готовое решение, а намётки: кроме «html5:» надо так же вычистить «html5\:».
Raphaël — графические эффекты на JS
«Raphaël» — небольшая (18 килобайт) библиотечка для быстрого применения графических эффектов (на сайте есть примеры отражения, вращения картинки и текста) и работы с графическими примитивами.
Работает под Safari 3.0+, FireFox 3.0+, Opera 9.50+, IE 6.0+. Используются SVG и VML. Как видно, большинство браузеров самых последних версий, именно
VML и PNG
Совершенно случайно обнаружил поразительную штуку: оказывается IE, загружая картинку через VML, понимает
<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />
<style>
v\:* { behavior: url(#default#VML); display: inline-block; }
</style>
<v:image src="http://www.w3.org/Graphics/PNG/alphatest.png" style="width: 380px; height: 287px"></v:image>К сожалению, есть существенный недостаток: картинка отображается чувствительно медленнее.
Closures в PHP: подробности
Внимательно прочитав документ по замыканиям в PHP, я вынес для себя следующее. Патч работает очень просто и довольно изящно. Замыкания — это
class Example {
public function __invoke () {
echo "Hello World!\n";
}
}
$foo = new Example;
$foo ();Слово «use», которое появилось в полной версии создания функции — это, конечно, уже полностью новый синтаксис, а не просто косметические изменения. Для тех, кто не прочитал документ, поясняю, что анонимная функция может быть создана, например, так:
function getAdder($x) {
return function ($y) use ($x) {
// or: lexical $x;
return $x + $y;
}
}«Use» вытекает из идеологии PHP, где глобальные переменные не видны сразу внутри функции, а определяются программистом (тоже хаком, кстати). «Use» именно «доставляет» переменную. Причём не из глобального уровня, а с родительского уровня. Что (ура) реализует мою давнюю мечту об изоляции переменных.
Замыкания в PHP 5.3.0
В PHP 5.3.0 будут замыкания. Бог ты мой! Не прошло и 15 лет! Надеюсь, это будут действительно анонимные функции, хотя возможность замыкания сама по себе тоже значительное событие.
Напомню как сейчас обстоит дело в PHP с «анонимными» функциями. Сделаны они хаком, поэтому я их взял в кавычки. Каждый раз, когда вы вызываете create_function PHP создаёт функцию (в глобальной зоне видимости, других нет) «\0lambda_N», где N — номер по внутреннему счётчику PHP, а «\0» — символ с кодом ноль, чтобы пользователь не смог самостоятельно создать «анонимную» функцию с произвольным номером, иначе пришлось бы просматривать все фукции с определённым префиксом и искать в нём «дыры» в номерах.
В частности, это значит, что все «анонимные» функции доступны в глобальной зоне видимости и всегда берут оттуда «свежую» копию переменной, а не то значение, которое было на момент её создания (т. е. замыкания нет), самое же мерзкое, с моей точки зрения, что анонимными функциям сложно нормально пользоваться: в цикле их легко нашлёпать столько, сколько раз вызовется цикл, а вставив её в метод, получить столько функций, сколько раз вызван этот метод.
От последнего эффекта можно избавиться, используя статические переменный, но это варварский способ, да и многие программисты (даже среднего уровня) не подозревают об этих особенностях.
Habr, WTF?
Хабр не устаёт меня удивлять всё снижающимся качеством статей и кода. Ну вот что это:
if(strpos($name, 'fetchRowBy') === 0) {
array_unshift($arguments, substr($name, 10));
return call_user_func_array(array($this, 'fetchRowBy'), $arguments);
}Ещё бы регулярное выражение использовал,