英語のページを書いていたはずなのに,いつのまにか日本語の文字が混じっていて,実は英語圏から見ると化け化けだった.
てなことは,自分自身が書いたページではあまりないんだけど,世の中見回すと結構あります.
というわけで,以前 ASCII じゃない文字をハイライト表示するゲートウェイ型フィルタを書いて,某所で内部的に使ってたんだけど,また最近必要になったので,手直しして,せっかくなので公開してみる.
その他の既知の問題としては,
などがあります.
ソースはこんな感じ:
#!/usr/bin/env perl -T
use strict;
use Jcode;
use CGI;
use URI;
use HTML::Parser;
use HTML::Entities;
use LWP::UserAgent;
&main;
sub main
{
my $query = new CGI;
my $script_uri_copied = URI->new($query->url());
# ヘッダ出力
print $query->header(-type => 'text/html', -charset => 'EUC-JP');
# ハイライトの色: デフォルトは cyan
my $color_str = $query->param('color');
my $color_code = &hilight_color($color_str);
# EUC に変換した HTML を取得
my $http_response = &get_html($query->param('uri'));
my $uri_base = $http_response->base;
my $html_code = Jcode->new($http_response->content)->euc;
# Parser を起動
my $handler_text = &handler_text_closure($color_code);
my $handler_start = &handler_start_closure($script_uri_copied,
$uri_base, $color_str);
my $hp
= HTML::Parser->new(default_h =>
[sub { print shift; }, 'text'],
text_h =>
[$handler_text, 'text'],
start_h =>
[$handler_start, 'tagname, attr, attrseq, text']
);
$hp->parse($html_code);
}
sub hilight_color
{
my ($color_str) = @_;
my %color_hash = ('cyan' => '#00ffff',
'magenta' => '#ff00ff',
'yellow' => '#ffff00',
);
return $color_hash{$color_str} || 'cyan';
}
sub get_html
{
my ($uri_str) = @_;
my $uri = URI->new($uri_str)->canonical;
# http と https のみ対応
if ($uri->scheme ne 'http' && $uri->scheme ne 'https') {
&print_error("scheme not supported: $uri_str");
exit;
}
# ファイルを取得して EUC に変換
my $ua = LWP::UserAgent->new;
my $res = $ua->get($uri->as_string);
if (!$res->is_success) {
print $res->error_as_HTML;
exit;
}
if ($res->content_type ne 'text/html') {
&print_error("not an HTML: " . $res->content_type);
exit;
}
return $res;
}
sub handler_text_closure
{
my ($color_code) = @_;
my $style = "color: black; background-color: $color_code;";
# テキスト部分で,8 ビットめが立っているところと立ってないところの
# 境界を検出してタグを挿入する.
return sub {
my ($text) = @_;
$text = " $text ";
$text =~ s/([\x00-\x7f])([^\x00-\x7f])/$1<b style=\"$style\">$2/g;
$text =~ s/([^\x00-\x7f])([\x00-\x7f])/$1<\/b>$2/g;
$text =~ s/^ //;
$text =~ s/ $//;
print $text;
};
}
sub handler_start_closure
{
my ($script_uri, $uri_base, $color_str) = @_;
my $is_base_set = 0;
# タグもちょっといじる
return sub {
my ($tagname, $attr, $attrseq, $text) = @_;
if (!$is_base_set && $tagname ne 'html' && $tagname ne 'head') {
# html と head 以外が初めて出て来る場所の直前に base を挿入
print "<base href=\"$uri_base\">\n";
$is_base_set = 1;
}
if ($tagname eq 'a' && defined($$attr{href})) {
# a の href の中身を,この CGI を経由するように変換する
print '<a href="',
&wrap_uri(encode_entities($$attr{href}),
$script_uri, $uri_base, $color_str),
'"';
print map {
$_ eq 'href'? '': " $_=\"" . encode_entities($$attr{$_}) . '"';
} @$attrseq;
print '>';
} elsif ($tagname eq 'meta'
&& $$attr{'http-equiv'} =~ /^Content-Type$/i) {
# content-type を指定する meta があるなら,EUC に書き換える
print '<meta http-equiv="Content-Type"',
' content="text/html; charset=EUC-JP">';
} else {
print $text;
}
};
}
sub wrap_uri
{
my ($arg, $script_uri, $uri_base, $color_str) = @_;
$script_uri->query_form(uri => URI->new_abs($arg, $uri_base),
color => $color_str);
return $script_uri->as_string;
}
sub print_error
{
my ($s) = @_;
print "<html><body>$s</body></html>\n";
}
!!!!!
2012 : 01 02 03 04 05 06 07 08 09 10 11 12
2011 : 01 02 03 04 05 06 07 08 09 10 11 12
2010 : 01 02 03 04 05 06 07 08 09 10 11 12
2009 : 01 02 03 04 05 06 07 08 09 10 11 12
2008 : 01 02 03 04 05 06 07 08 09 10 11 12
2007 : 01 02 03 04 05 06 07 08 09 10 11 12
2006 : 01 02 03 04 05 06 07 08 09 10 11 12
2005 : 01 02 03 04 05 06 07 08 09 10 11 12
2004 : 01 02 03 04 05 06 07 08 09 10 11 12
2003 : 01 02 03 04 05 06 07 08 09 10 11 12
2002 : 01 02 03 04 05 06 07 08 09 10 11 12
2001 : 01 02 03 04 05 06 07 08 09 10 11 12
2000 : 01 02 03 04 05 06 07 08 09 10 11 12
1999 : 01 02 03 04 05 06 07 08 09 10 11 12
1998 : 01 02 03 04 05 06 07 08 09 10 11 12
1997 : 01 02 03 04 05 06 07 08 09 10 11 12
1996 : 01 02 03 04 05 06 07 08 09 10 11 12
最終更新時間: 2012-02-13 02:02