Мини заметки — выпуск 4
1 сентября 2011
Пришло время для очередного выпуска мини-заметок. Вас ждут парочка полезных фильтров для WordPress, несколько Perl-скрипов и другие приятные мелочи. Предыдущие выпуски мини-заметок можно найти здесь (#3) и там (#2).
1. Работа с UTF-8 в Perl
Perl хранит строки в виде массивов целых чисел. Чтобы работать с данными в кодировке UTF-8, сначала нужно преобразовать их во внутреннее представление интерпретатора. Делается это очень просто:
use utf8;
my $str;
# ... $str := данные в кодировке utf8 ...
# декодируем строку из utf8 во внутреннее представление
utf8::decode($str);
# теперь $str можно обрабатывать
Прежде, чем вывести данные в консоль или файл, их нужно преобразовать из внутреннего представления обратно в кодировку UTF-8:
utf8::encode($str);
# выводим куда-нибудь
Если все время кодировать-декодировать данные не хочется, можно возложить эту работу на интерпретатор:
use strict;
use utf8;
binmode STDIN, ":utf8";
binmode STDOUT, ":utf8";
print "Ваше имя: ";
chomp(my $name = <>);
print "Привет, $name!\n";
Более короткий вариант:
use strict;
use utf8;
use open qw/:std :utf8/;
print "Ваше имя: ";
chomp(my $name = <>);
print "Привет, $name!\n";
По-моему, все просто и логично. Соответствующая инфа прекрасно гуглится (я же ее как-то нашел в свое время). Однако почему-то этот вопрос довольно часто всплывает на форумах и в IRC.
Следует учесть, что описанный выше рецепт позволяет «нормально» работать даже с кодами, еще не используемыми в Unicode. В некоторых случаях (например, если вы пишите свой веб-фреймворк) вам может потребоваться более строгая работа с UTF-8. Подробности можно узнать в статье Know the difference between utf8 and UTF-8.
Подробнее о том, как Perl работает с различными кодировками, можно прочитать в этой статье.
2. Скрипт для скачивания видео с Vimeo.com
Как выяснилось, Vimeo легко ковыряется с помощью Firebug.
# vimeo.com downloader v 0.1
# (c) Alexandr A Alexeev 2011 | http://eax.me/
use strict;
my $url = shift;
my $vid;
unless(($vid) = $url =~ m#^http://(?:www\.)?vimeo\.com/(\d+)$#i) {
die "Usage: $0 http://vimeo.com/1234567\n";
}
my $data = `wget '$url' -O -`;
if($?) {
die "Download failed: wget returns $?";
}
my $regex = qr#"signature":"([0-9a-f]{32})","timestamp":([0-9]+),[^\}]+\},"video":\{"id":(\d+)#i;
my ($sign, $time, $clip_id);
unless(($sign, $time, $clip_id) = $data =~ $regex) {
die "Failed to parse html code";
}
my $url =
"http://player.vimeo.com/play_redirect".
"?clip_id=$clip_id&sig=$sign&time=$time".
"&quality=hd,sd,mobile&codecs=H264,VP8,VP6";
`wget '$url' -O $vid.mp4`;
if($?) {
print "Download failed: wget returns $?";
} else {
print "Video saved to $vid.mp4\n";
}
Также в этом блоге вы можете найти аналогичные скрипты для YouTube и RuTube.
Дополнение: См также CPAN-модули WWW::YouTube::Download и WWW::Vimeo::Download.
3. Скрипт для скачивания файлов с DepositFiles
Загружать на DepositFiles мы уже умеем, а вот доунлоадер еще не писали:
# quick-deposit.pl script v 0.1
# (c) Alexandr A Alexeev 2011 | http://eax.me/
use strict;
use File::Temp;
# проверяем наличие всех необходимых утилит
{
my @depends = qw/wget/;
my $not_found;
for(@depends) {
print "ERROR: $_ not found" and ++$not_found
if(system("which $_ > /dev/null"));
}
exit 1 if($not_found);
}
my $url = shift;
die "Usage: $0 <url>\n"
unless($url && $url !~ /'/);
# валидация url
if($url !~ m#depositfiles\.com/(.*)$#i) {
die "Step 0: invalid url!\n";
}
$url = $1;
if($url !~ m#^[a-z]{2}/#i) {
$url = "ru/$url"; # обязательно нужен двубуквенный префикс!
}
$url = "http://depositfiles.com/$url";
my $cookies = tmpnam();
my $data;
STEP1:
$data = `wget -q '$url' --post-data='gateway_result=1' --save-cookies=$cookies -O -`;
die "Step 1: wget returns $?\n" if($?);
if($data =~ m#<span class="html_download_api-limit_parallel">#i) {
print "Parallel limit, sleeping 2 min...\n";
sleep 120;
goto STEP1;
}
if($data =~ m#<span class="html_download_api-limit_interval">(\d+)</span>#i) {
my $sleep = $1;
print "limit_interval = $sleep (~ ".int($sleep/60)." min)\n";
sleep 60; # $sleep;
goto STEP1;
}
my $get_file_url;
if($data !~ m#(get_file\.php\?fid=[0-9a-f]+)#i) {
die "Step 1: get_file url not found!\n";
}
$get_file_url = "http://depositfiles.com/$1";
print "Sleeping 60 seconds...\n";
sleep 61;
STEP2:
$data = `wget -q '$get_file_url' --load-cookies=$cookies -O -`;
die "Step 2: wget returns $?\n" if($?);
# тут _теоретически_ может возникнуть ситуация, когда кто-то нас опередил
# но на практике такое не происходит
my $download_url;
if($data !~ m#<form action="(http://fileshare[^"]+)"#i) {
if($data =~ m#Please wait \d{1,2} sec#i) {
# Please wait 60 sec or use GOLD account to download with no time limits
print "Sleeping 5 seconds...\n";
sleep 5;
goto STEP2;
}
die "Step 2: failed to get download url!\n";
}
$download_url = $1;
die "Invalid download url: $download_url\n"
if($download_url =~ /'/);
print "Downloading $download_url\n";
system("wget '$download_url' --load-cookies=$cookies");
Просто скармливаем скрипту ссылку и занимаемся дальше своими делами. Он сам подождет 60 или сколько-там-надо секунд, после чего бережно скачает требуемый файл на диск.
4. Запрещаем комментаторам блога оставлять ссылки
Чтобы меньше беспокоиться по поводу ручного спама в ваших WordPress-блогах, пропишите следующий код в functions.php:
function fltr_get_comment_text($str) {
$str = preg_replace(
'/<a href=["\']{1}([^"\']+)["\']{1}[^>]*>([^<]+)<\/a>/i',
'$2 [$1]',
$str
);
$str = str_replace('tp://', 'tp://', $str);
return $str;
}
add_filter('get_comment_text', 'fltr_get_comment_text');
Теперь все ссылки в комментариях будут заменяться на последовательность «текст_ссылки [url_простым_текстом]». Таким образом мы избавимся от всех гиперссылок в комментах. Пусть комментаторы ссылаются, на что хотят :)
5. Скрытие ссылок средствами JavaScript
А вот такой прием можно использовать в агрегаторах новостей:
$str = mb_convert_encoding($str, 'UTF-16', 'UTF-8');
$out = '';
for($i = 0; $i < mb_strlen($str, 'UTF-16'); $i++)
$out .= '%u'.bin2hex(mb_substr($str, $i, 1, 'UTF-16'));
return $out;
}
function hide_link($matches) {
$url = $matches[1];
$str = $matches[2];
$id = md5("SECRET123456".$url);
return
"<span id='$id'>".(($str === $url) ? $url : "$str [$url]").
"</span><script type='text/javascript'><!--\n".
'document.getElementById("'.$id.'").innerHTML = '.
'unescape("'.js_urlencode('<a href="'.$url.'">'.$str.'</a>').
"\");\n//--></script>";
}
// вывести архив с зашифрованными ссылками
function js_the_content($str) {
$str = preg_replace_callback(
'#<a href="([^"]+)">([^<]+)</a>#i',
"hide_link",
$str
);
return $str;
}
add_filter('the_content', 'js_the_content');
Теперь поисковые системы не увидят ни одной ссылки, а реальные пользователи (с включенным JavaScript) не заметят никакой разницы.
6. Определение оператора вывода для контейнеров в C++
Этот пример я просто стырил с Винграда:
#include <iterator>
#include <string>
#include <vector>
#include <list>
#include <deque>
template<
typename T, typename A,
template <class, class> class C
> std::ostream& operator<< (std::ostream& os, const C<T, A>& o)
{
std::copy(
o.begin(), o.end(),
std::ostream_iterator<T>(std::cout, " ")
);
return os << std::flush;
}
int main() {
std::vector<std::string> myVector;
std::list<std::string> myList;
std::deque<std::string> myDeque;
myVector.push_back("aaa");
myVector.push_back("bbb");
std::cout << myVector;
std::cout << myList;
std::cout << myDeque;
}
Авось когда-нибудь пригодится.
7. Как доказать, что у пользователя отключены кукисы
К сожалению, иногда приходится заниматься такой ерундой:
var d = new Date();
var ref = escape(document.referrer);
document.write(
'<a href="<%= url_for '/' %>">' +
'<img src="<%= url_for '/logo.png' %>' +
// **** DEBUG ****
'?' + d.getTime() +
';' + escape(document.cookie) +
';' + ref.replace(/\//g, '_') +
// **************
'" style="border: 0;" /></a>'
);
//--></script>
Допустим, пользователь не может залогиниться на сайт, а симптомы напоминают отключенные кукисы. Чтобы не переться в бухгалтерию и не рыться в настройках браузера (нарушив тем самым должностную инструкцию), добавляем в шаблон приведенный выше код (предполагается, что сайт работает на Mojolicious) и просим пользователя попробовать еще разок. Затем открываем /var/log/httpd-access.log и тыкаем пальчиком.
8. Как удалить скрипт, поставленный с помощью setup.py
Говорим:
Внимательно просматриваем список файлов, после чего удаляем их:
Так-то!
9. Список модулей, используемых проектом на Perl
С помощью такого однострочника можно получить список модулей, используемых в проекте:
perl -lne 'if(/^use(?: base)? ([^ ;]+)/){print $1;}' | \
grep -v strict | sort -u
Список, к примеру, можно скопировать в README.TXT. Для упрощения деплоймента проектов на Perl Ярослав Коршак посоветовал мне использовать Module::Starter. К сожалению, на момент написания этих строк, руки до указанного модуля у меня не дошли.
Подробнее про однострочники на Perl можно прочитать на Хабре.
10. Как получить основной текст веб-страницы
Чтобы отделить основной текст страницы от заголовка, подвала и меню, можно использовать примерно такую последовательность шагов:
wget http://eax.me/perl5-oop/ -O page.html
diff index.html page.html | perl -lne 'if(/^>(.*)$/){print $1;}'
Дальше можно избавиться от лишнего HTML-кода (каких-нибудь div и span), отыскать самую длинную измененную часть страницы и тп. Подозреваю, что поисковые системы используют похожий метод.
Как всегда, любые замечания и дополнения приветствуются. Да пребудет с вами Великая Сила!
Дополнение: Мини заметки — выпуск 5
Метки: Всячина.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.