« メールから記事を投稿 | メイン | 小悪魔の悲劇 »
2005年11月25日
正規表現でタグを処理 [Perl]
掲示板やチャットなど、不特定多数の人からの入力を受け付ける場合、タグの入力をそのまま受け付けると、非常に危険な状態になる。全てのタグを無効化するのは一つの手だが、表現力を出したいときにはある程度のタグを使えたほうがよい場合もある。
また比較的安全なタグでも、正しく閉じられていないとその後ろ全体に書式が適用されてしまって変な表示になるときもある。何よりも(X)HTMLにこだわる人には、書き出されるログは well-formed (もしくはValied)じゃなくなるのが許せないだろう。
特定のタグだけを許可し、かつ閉じられていないタグを閉じる処理を、Perlの正規表現で実装してみることにした。これは現在作成中のMjCha4に含めたコードだが、汎用性を持たせられそうなので関数化してみた。
# 不要タグの除去
sub removeTags{
my($str, $tags) = @_;
my $stag = '_TAG_START_';
my $etag = '_TAG_END_';
# 予約文字のエスケープ
$str =~ s/$stag/_TAGSTART_/g;
$str =~ s/$etag/_TAGEND_/g;
foreach my $i(@{$tags}){
# 許可タグのエスケープ
while($str =~ m/<$i[^>]*>.*<\/$i>/){
$str =~ s/<($i[^>]*)>(.*)<\/$i>/$stag$1$etag$2$stag\/$i$etag/;
}
# 空要素も考慮
while($str =~ m/<$i[^>]*\/>/){
$str =~ s/<($i[^>]*)\/>/$stag$1\/$etag/;
}
# 閉じられてないタグを補完
while($str =~ m/<$i[^>]*>/){
$str =~ s/<($i[^>]*)>/$stag$1$etag$stag\/$i$etag/;
}
}
# その他のタグの除去
$str =~ s/<[^>]*>//g;
$str =~ s/</</g;
$str =~ s/>/>/g;
# 許可タグの復帰
$str =~ s/$stag/</g;
$str =~ s/$etag/>/g;
# 予約文字の復帰は無し。どうせ使わないだろうと勝手に予測。
$_[0] = $str;
}