Мини заметки – выпуск 4
Пришло время для очередного выпуска мини-заметок. Вас ждут парочка полезных фильтров для 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);
# выводим куда-нибудь
Если все время кодировать-декодировать данные не хочется, можно возложить эту работу на интерпретатор:
1 2 3 4 5 6 7 8 9 10 11 | #!/usr/bin/perl use strict; use utf8; binmode STDIN, ":utf8"; binmode STDOUT, ":utf8"; print "Ваше имя: "; chomp(my $name = <>); print "Привет, $name!\n"; |
Более короткий вариант:
1 2 3 4 5 6 7 8 9 | #!/usr/bin/perl 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #!/usr/bin/env perl # 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 мы уже умеем, а вот доунлоадер еще не писали:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #!/usr/bin/env perl # 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++
Этот пример я просто стырил с Винграда:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #include <iostream> #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