一部のHTMLタグを通すフィルタ
Posted feedbacks - JavaScript
正規表現置換でごり押し。 可読性最悪ですみません。
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 | var input = "<a href='www.google.com' name='hoge' title=\"fuga\">\
link</a><blink>and</blink> <strong onClick='alert(\"NG\")'>click<br/>me!</strong>";
var reg = /<\s*(a|strong|br)((?:\s+\w+\s*=\s*(["']).*?\3)*)?\s*(?:>(([^<]*|<[^<>]*[^\/]>|<[^<>]*\/>)*)<\/s*\1\s*>|\/>)/gmi;
function deleteAttr(attr) {
return attr.replace(/\s+(\w+)\s*=\s*(["'])(.*?)\2/g, function(all, name, q, value) {
if(!name.match(/name|href/i)) return '';
else return all;
});
}
function eacapeTags(str) {
var escaped = [];
str = str.replace(reg, function(all, tag, attr, q, inner) {
attr = tag.toUpperCase() == 'A' ? deleteAttr(attr) : '';
escaped .push(tag+ " " + attr, inner);
return "<A/>";
}).replace(/</g, "<");
str = str.replace(/<A\/>/g, function() {
var tag = escaped.shift(), inner = escaped.shift();
if(inner) return "<" + tag + ">" + eacapeTags(inner) + "</" + tag + ">";
else return "<" + tag + "/>";
});
return str;
}
document.body.innerHTML=(eacapeTags(input));
|
inとoutにWSHを使ってます。 cscript "javascriptファイル" フィルタしたい文字列 で実行可能です。
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 | if (WScript.Arguments.length != 1)
WScript.Quit();
var target = WScript.Arguments.item(0);
var ret = target.replace(
/<((\/?)([a-z]+)(.*?)(\/?))>/ig,
function(all, ins, head, tag, elms, tail){
switch (tag.toUpperCase())
{
case "A":
var filterElms = elms.match(/ ?(href|name) *= *[^ \/>]+/ig);
var newElement = "";
if (filterElms)
for(var i = 0; i < filterElms.length; i++)
newElement += filterElms[i];
return "<" + head + tag + newElement + tail +">";
case "BR":
case "STRONG":
return "<" + head + tag + tail + ">";
default:
return "<" + ins + ">";
break;
}
});
WScript.Echo(ret);
|
ちょっと無駄に難しく作りすぎました。 開きタグと閉じタグは個別に扱っても構わなかったのか。 ところで、(要件に含まれるのかわかりませんが)属性に">"が含まれるケースを考慮してない回答が結構ありますね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | var input = "<a title=\"(>_<;)\" href='www.google.com' name='hoge'>\
link</a><blink>and</blink> <strong onClick='alert(\"NG\")'>click<br/>me!</strong>";
function deleteAttr(attr) {
return attr.replace(/\s+(\w+)\s*=\s*(["'])(.*?)\2/g, function(all, name, q, value) {
return name.match(/name|href/i) ? all : '';
});
}
function filter(html) {
return html.replace(/<(\/?)(\w+)((?:\s+\w+\s*=\s*(["']).*?\4)*)?(\/?)>/gmi,
function(all, fslash, tag, attrs, q, rslash) {
switch(tag.toUpperCase()) {
case 'STRONG' : // drop through
case 'BR' : attrs = ''; break;
case 'A' : attrs = deleteAttr(attrs); break;
default : return all.replace('&', '&').replace('<', '<');
}
return '<' + fslash + tag + attrs + rslash + '>';
});
}
document.body.innerHTML=filter(input);
|
>http://ja.doukaku.org/comment/2722/ 失念してました。 文中に">"等が入っても通るように正規表現修正。
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 | if (WScript.Arguments.length != 1)
WScript.Quit();
var target = WScript.Arguments.item(0);
var ret = target.replace(
/<(\/?)(\w+)((\s*|\w+|\w+\s*=\s*('[^']*'|"[^"]*"|\w+))*)(\/?)>/ig,
function(all, head, tag, attr, nouse1, nouse2, tail){
switch (tag.toUpperCase())
{
case "A":
var attrs = attr.match(/\s?(href|name)\s*=\s*('[^']*'|"[^"]*"|\w+)/ig);
var newAttr = "";
if (attrs)
for(var i = 0; i < attrs.length; i++)
newAttr += attrs[i];
return "<" + head + tag + newAttr + tail +">";
case "BR":
case "STRONG":
return "<" + head + tag + tail + ">";
default:
return "<" + head + tag + attr + tail + ">";
}
});
WScript.Echo(ret);
|
DOM を使った方がより JavaScript らしいのかもしれないが…。
javascript:document.body.innerHTML=(function(s,r,x){r=/\b(?:name|href) *= *(?:".*?"|'.*?'|[^ >]*)/gi;x=/^\/?(a)|br|strong\b/i;return s.replace(/<([^ >]+ ?)((?:".*?"|'.*?'|[^\/>])*)/g,function(m,t,a){return x.test(t)?'<'+t+(RegExp.$1&&(m=a.match(r))?m.join(' '):''):'<'+t+a})})(document.body.innerHTML)
javascript:document.body.innerHTML=(function(s,r,x){r=/\b(?:name|href) *= *(?:".*?"|'.*?'|[^ >]*)/gi;x=/^\/?(a)|br|strong\b/i;return s.replace(/<([^ >]+ ?)((?:".*?"|'.*?'|[^\/>])*)/g,function(m,t,a){return x.test(t)?'<'+t+(RegExp.$1&&(m=a.match(r))?m.join(' '):''):'<'+t+a})})(document.body.innerHTML)
1 2 3 4 5 6 7 8 | function doukaku54(s){
var rx_nh = /\b(?:name|href) *= *(?:".*?"|'.*?'|[^ >]*)/gi;
var rx_ok = /^\/?(a)|br|strong\b/i, LT = '<', lt = '<', sp = ' ';
return s.replace(/<([^ >]+ ?)((?:".*?"|'.*?'|[^\/>])*)/g, function(m, tag, ats){
return rx_ok.test(tag)
? LT + tag + (RegExp.$1 && (m = ats.match(rx_nh)) ? m.join(sp) : '')
: lt + tag + ats });
}
|
色々と間違っていたのを修整。(要素中の<>にエスケープが要らないとは知らなんだ。)
この程度の処理だと大して効果が無いようなので,文字列のキャッシュはやめにした。
javascript:with(document.body)(function(s,r,g,x){r=/\b(?:name|href) *= *(?:".*?"|'.*?'|[^ >]*)/gi;g=/</g;x=/^<\/?(?:(a)|br|strong)\b/i;innerHTML=s.replace(/(<[^ >]+ ?)((?:".*?"|'.*?'|[^>])*?)(?=\/?>)/g,function(m,t,a){return x.test(t)?t+(RegExp.$1&&(m=a.match(r))?m.join(' '):''):m.replace(g,'<')})})(innerHTML)
この程度の処理だと大して効果が無いようなので,文字列のキャッシュはやめにした。
javascript:with(document.body)(function(s,r,g,x){r=/\b(?:name|href) *= *(?:".*?"|'.*?'|[^ >]*)/gi;g=/</g;x=/^<\/?(?:(a)|br|strong)\b/i;innerHTML=s.replace(/(<[^ >]+ ?)((?:".*?"|'.*?'|[^>])*?)(?=\/?>)/g,function(m,t,a){return x.test(t)?t+(RegExp.$1&&(m=a.match(r))?m.join(' '):''):m.replace(g,'<')})})(innerHTML)
1 2 3 4 5 6 7 8 | function doukaku54(s){
var rx_nh = /\b(?:name|href) *= *(?:".*?"|'.*?'|[^ >]*)/gi,
rx_ok = /^<\/?(?:(a)|br|strong)\b/i, rx_lt = /</g;
return s.replace(/(<[^ >]+ ?)((?:".*?"|'.*?'|[^>])*?)(?=\/?>)/g, function(m, tag, ats){
return rx_ok.test(tag)
? tag + (RegExp.$1 && (m = ats.match(rx_nh)) ? m.join(' ') : '')
: m.replace(rx_lt, '<') });
}
|




にしお
#3410()
Rating0/0=0.00
このお題はperezvonさんの提案を元にしています。ありがとうございました。 ただ、いきなりだと難しいかと思ったので、肝の部分以外を先に出題しました。このお題は続編で徐々に難しくなっていきます。
追記:属性に<や>が含まれてしまうケースに漏れのある解答が多いようなのでテストケースを追加します。 これは「この出力なら十分」という意味です。この出力の通りでなければいけないという意味ではありません。 <script foo="<script>alert('bar')</script>">alert('foo')</script> <script foo="<script>alert('bar')</script>">alert('foo')</script> <script foo="<a href='link'>link</a>">alert('foo')</script> <script foo="<a href='link'>link</a>">alert('foo')</script> <a href='www.g>oogle.com'>link</a> <a href="./www.g%3Eoogle.com">link</a>[ reply ]