программирование

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 in groupby([1,2,3,-4,-1,2], lambda x: x>=0)]

Я тут прошёлся по списку [1, 2, 3, -4, -1, 2], объединяя его значения при помощи функции x>=0. Т. е. все подряд идущие числа с одинаковым знаком будут сгруппированы. Получится вот что:

[(True, [1, 2, 3]), (False, [-4, -1]), (True, [2])]

сверху на 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’, ’’][1:-1] даст нам искомое: [’1’, ’1’, ’’, ’’, ’3’, ’’, ’5’].

Мда. Что-то как-то не очень всё просто получилось :)

13 комментариев

Спираль истории: @font-face

Когда на земле было всего два браузера — IE и Netscape Navigator, они оба поддерживали разные виды внедряемых шрифтов. IE поддерживал своё, но бесплатное решение, Netscape использовал платное решение от BitStream. В те времена вебмастера интересовались возможностями браузеров ещё меньше, чем сейчас и этой возможностью мало кто пользовался.

Хотя в Татарстане, где я жил, технологию внедряемых шрифтов использовали очень часто для поддержки татарского алфавита на сайтах.

Суть технологии очень проста: шрифт подключается как любой внешний ресурс (другие примеры — графика, CSS, JS) и им можно писать что-то на странице. Netscape помер, а решение Microsoft всё-таки вошло в CSS, хотя и в изменённом виде.

На данный момент, оказывается, во всех браузерах, включая альтернативный, на какой-то стадии есть поддержка внедрения шрифтов (@font-face):

  • у Internet Explorer есть наиболее удачная из всего зоопарка разработка — поддержка шрифтов в формате EOT
  • у Opera эта поддержка есть в лабораторном билде, значит появится и в самом браузере (поддерживается TTF)
  • Safari (WebKit) поддерживает эту технологию ещё с октября прошлого года
  • у FireFox, вероятно, поддержка появится в версии 3.1, по крайней мере сейчас существуют сборки, в которых она уже есть
    Хочу сразу сказать почему я считаю, что у IE наиболее удачное решение: разработчик может указать какие именно знаки оставить в шрифте, что даёт огромную экономию по размеру. Другие же браузеры поддерживают шрифты в форматах TrueTypeFont и OpenType. Легко представить к чему это приведёт: подключать будут гигантские Unicode-шрифты, содержащие всё что только возможно, вплоть до вымерших алфавитов.

17 комментариев

PHP: мануалы читать необходимо

Я изучаю новый язык следующим образом: сначала всегда полностью читаю руководство (вот с «Пайтоном» мне не повезло — в руководстве, которое я выбрал, об itertools было упомянуто вскользь), потом уже пробую что-то писать, изредка показывая куски кода для критики.

Конечно, руководство полностью наизусть я не помню, но зато всегда помню, что «что-то где-то было», это частно избавляет от изобретения велосипедов.

В свежей статье на «Хабре» — один из подобных велосипедов:

function uptime() {
    $fp=@popen('uptime','r');
    $s=@fgets($fp);
    @fclose($fp);

    @preg_match('#load average: ([0-9\.]+)#', $s, $m);
    return $m[1];
};

Во-первых, в PHP есть функция sys_getloadavg, во-вторых, (если версия PHP ниже 5.1.3) эту информацию можно добыть значительно проще: «(float) substr(strstr(`uptime`, „load average:“), 13)», в третих, можно (на Линуксах) читать /proc/loadavg.

В этой статье вообще масса забавного: в разделе «временные припарки», где index.php заменили для снятия нагрузки, для чего-то использовался print, вместо того, чтобы выдать сообщение голым html, memcached используется как база данных и так далее.

8 комментариев

Расширение RSS: «Яндекс», поиск по блогам

«Яндекс» выпустил специальный RSS-плагин к популярным PHP-форумам для сервиса «Поиск по блогам». Автор — известный PHP-программист Дима Смирнов. На медленно стухающей «Хабре» немедленно появились те, кто «не читал, но обсуждают».

В чём же заключается смысл плагина? Поскольку я в курсе, давайте расскажу.

Сервис поиска по блогам «Яндекса», как вытекает из названия, индексирует блоги и многим кажется, что на этом его отличие от основного поиска заканчивается. Как бы не так! Поисковик «Яндекса» индексирует HTML-страницы, поисковик поиска по блогам индексирует RSS, а в 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, который находится внутри архива с плагинами.

16 комментариев

Chrome: не к добру

Интересно, через какое время сообщество обнаружит about:network в «Хроме», научится включать «I/O Tracking», увидит там, что каждый день «Хром» качает что-то некислое с «Гугла» и поднимет панику?

И сколько умных людей сходит в поисковик и выяснит, что это подгрузка чёрных и белых списков фишинговых и вредоносных сайтов (Safe Browsing API)?

Речь идёт об URL вида «http://static.cache.l.google.com/safebrowsing/» и других со словом «safe», браузер сначала получает данные о том, что ему нужно получить, а потом потихоньку скачивает необходимые данные. Кстати, Google Safe Browsing используется и в FireFox3.

9 комментариев

IE8beta2: ACID3

Как-то все забыли про ACID3. Проверил им Internet Explorer 8 beta 2 и Chrome (специально для этого скачал!). Итак, по сравнению с ближайшими конкурентами:

Opera 9.60beta1 — 85% FireFox 3.1 beta1 — 85% Chrome 0.2 beta — 79% WebKit r36309 — падает на 26% Internet Explorer 8 beta 2 — 21%

14 комментариев

Ошибка в валидации поля: виноват 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.

3 комментария

Chrome: война клоническая началась

Хорошо, я выскажусь о «Хроме», тем более многие ждут. К «Хрому» я абсолютно равнодушен, вплоть до того, что даже его не поставил и не удосужился у кого-то посмотреть. Я лишь пролистал скриншоты на «Хабре» и просмотрел многочисленные статьи о сравнениях его с другими браузерами. Этот браузер меня интересует не больше, чем «Amaya» или «Arachne».

34 комментария

Microsoft взялась серьёзно за браузер: IE8

Microsoft серьёзно взялась за стандартизацию своего браузера. В блоге IE появилась статья, где рассказывается о дальнейших шагах по преобразованию браузера. Например, все расширения CSS будут теперь начинаться с префикса («-ms-»), как того требуют стандарты. Причём речь идёт не о нововведениях (IE7 уже поддерживает свойство «-ms-interpolation-mode» с префиксом), а о существующих свойствах. К примеру, «zoom» будет теперь называтся «-ms-zoom».

Хорошая новость: фильтры будут! только теперь они будут называться «-ms-filter» и выглядеть как обычное свойство, взятое в кавычки. Т. е. для указания прозрачности (загибайте пальцы) мы будем использовать: opacity (CSS3), -moz-opacity (старые FF), -khtml-opacity (старые Konqueror), filter (IE ниже 8) и -ms-filter (IE8 и выше).

Для сайтов, которые переделать невозможно (из-за объёма или запущенности), остаётся возможность использовать Compatibility View (режим обратной совместимости).

4 комментария

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!».

4 комментария

Python

В последние три дня прочитал кучу документации по Python (язык программирования). Уже без труда пишу и читаю что-то подобное (Ваня, зацени):

[r'% r',][~0] % {(): '''^''' uR'|' in 2**2*__name__[::-8//(lambda _:~_)(3 or 2)]*2}<2>3j,(`3`) is ([])

Кто-нибудь скажет, не запуская,чему это будет равно?

14 комментариев

Memcached

Люди, не используйте memcached, если можно этого не делать! Статьи на «Хабре» говорят о том, что:

a) люди не понимают когда нужно использовать memcached, а когда нельзя б) люди не знают о других способах использования разделяемой памяти, memcached самый «раскрученный»

16 комментариев

IE8beta2

Вышла вторая бета Internet Explorer 8.0, в списке поддерживаемых операционных систем всё-таки есть Windows XP.

Печальная новость — CSS expression больше не будут функционировать стандартном режиме этого браузера, но они всё ещё поддерживаются в режимах IE7Strict и IE7Quirks. Не понимаю для чего это. Как теперь эмулировать недостающее?

Интересных новых штук несколько: новая стартовая страница, цветные закладки, нормальный autocomplete строки адреса. Из технических штук мне понравились методы для безопасного разбора и проверки JSON (JSON.parse, JSON.stringify).

DOM storage, XDomainRequest и Connectivity Events были, кажется, и в первой бете.

Ощущение, что ребята серьёзно взялись за свой браузер. С версии 8.5 это даже можно будет использовать.

15 комментариев

Ogg и тег VIDEO, ActiveX Canvas для IE

Так-так, вот и FireFox 3.1, вслед за «Оперой» начинает поддерживать тег VIDEO и стандарт Ogg Theora для этого видео. Если так дело дальше пойдёт, то Ogg станет форматом для тега VIDEO де факто.

Из других интересных новостей — Vladimir Vukićević разработал ActiveX для IE, который повторяет функциональность этого тега пока только частично, но работа продолжается. Тот же автор обещает в будущем поддержку тегов video и audio, тоже, видимо, в формате ActiveX.

13 комментариев

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\:».

3 комментария

Raphaël — графические эффекты на JS

«Raphaël» — небольшая (18 килобайт) библиотечка для быстрого применения графических эффектов (на сайте есть примеры отражения, вращения картинки и текста) и работы с графическими примитивами.

Работает под Safari 3.0+, FireFox 3.0+, Opera 9.50+, IE 6.0+. Используются SVG и VML. Как видно, большинство браузеров самых последних версий, именно из-за SVG. Надеюсь, автор со временем сделает degradation через Canvas, который работает медленее, но зато поддерживается предыдущими версиями Safari, FireFox и Opera.

16 комментариев

VML и PNG

Совершенно случайно обнаружил поразительную штуку: оказывается IE, загружая картинку через VML, понимает альфа-прозначность у PNG:

<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>

К сожалению, есть существенный недостаток: картинка отображается чувствительно медленнее.

7 комментариев

Closures в PHP: подробности

Внимательно прочитав документ по замыканиям в PHP, я вынес для себя следующее. Патч работает очень просто и довольно изящно. Замыкания — это не какой-то новый базовый тип, а экземпляр класса Closure. Причём, для того, чтобы объект вёл себя как функция, вводится новый «магический» метод __invoke:

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» именно «доставляет» переменную. Причём не из глобального уровня, а с родительского уровня. Что (ура) реализует мою давнюю мечту об изоляции переменных.

13 комментариев

Замыкания в PHP 5.3.0

В PHP 5.3.0 будут замыкания. Бог ты мой! Не прошло и 15 лет! Надеюсь, это будут действительно анонимные функции, хотя возможность замыкания сама по себе тоже значительное событие.

Напомню как сейчас обстоит дело в PHP с «анонимными» функциями. Сделаны они хаком, поэтому я их взял в кавычки. Каждый раз, когда вы вызываете create_function PHP создаёт функцию (в глобальной зоне видимости, других нет) «\0lambda_N», где N — номер по внутреннему счётчику PHP, а «\0» — символ с кодом ноль, чтобы пользователь не смог самостоятельно создать «анонимную» функцию с произвольным номером, иначе пришлось бы просматривать все фукции с определённым префиксом и искать в нём «дыры» в номерах.

В частности, это значит, что все «анонимные» функции доступны в глобальной зоне видимости и всегда берут оттуда «свежую» копию переменной, а не то значение, которое было на момент её создания (т. е. замыкания нет), самое же мерзкое, с моей точки зрения, что анонимными функциям сложно нормально пользоваться: в цикле их легко нашлёпать столько, сколько раз вызовется цикл, а вставив её в метод, получить столько функций, сколько раз вызван этот метод.

От последнего эффекта можно избавиться, используя статические переменный, но это варварский способ, да и многие программисты (даже среднего уровня) не подозревают об этих особенностях.

13 комментариев

Habr, WTF?

Хабр не устаёт меня удивлять всё снижающимся качеством статей и кода. Ну вот что это:

if(strpos($name, 'fetchRowBy') === 0) {
      array_unshift($arguments, substr($name, 10));
      return call_user_func_array(array($this, 'fetchRowBy'), $arguments);
    }

Ещё бы регулярное выражение использовал, ей-богу!

39 комментариев

← 1 55 56 57 58 59 67 →