challenge 一部のHTMLタグを通すフィルタ

ユーザが入力した文字列から、一部のタグだけを許可して他をエスケープするコードを書いてください。要件は次のようになります。
  • 通すタグはAとBRとSTRONGのみ。大文字小文字は区別しない。
  • それ以外のタグとして意味を持ちうる文字列は<を&lt;に変換することで無効化する(削除するのではない。>は変換してもしなくてもよい)
  • Aタグのhrefとname以外の属性は削除する。BRやSTRONGの属性はすべて削除する。

このお題はperezvonさんの提案を元にしています。ありがとうございました。 ただ、いきなりだと難しいかと思ったので、肝の部分以外を先に出題しました。このお題は続編で徐々に難しくなっていきます。

追記:属性に<や>が含まれてしまうケースに漏れのある解答が多いようなのでテストケースを追加します。
これは「この出力なら十分」という意味です。この出力の通りでなければいけないという意味ではありません。

<script foo="<script>alert('bar')</script>">alert('foo')</script>
&lt;script foo="&lt;script&gt;alert('bar')&lt;/script&gt;"&gt;alert('foo')&lt;/script&gt;


<script foo="<a href='link'>link</a>">alert('foo')</script>
&lt;script foo="&lt;a href='link'&gt;link&lt;/a&gt;"&gt;alert('foo')&lt;/script&gt;

<a href='www.g>oogle.com'>link</a>

<a href="./www.g%3Eoogle.com">link</a>

Posted feedbacks - 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
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
88
89
90
91
using System;
using System.Text;
using System.Text.RegularExpressions;

class HtmlFilter {
    private Regex _regFilter;
        
    public HtmlFilter() {
        _regFilter = new Regex(@"(<(?<begin>\w+)(?:\s+(?<attr>\w+\s*=\s*"
             + "(?:'[^']*'|\"[^\"]*\")" + @"\s*)*)?/?>)|(</(?<end>\w+)\s*>)",
            RegexOptions.IgnoreCase | RegexOptions.Compiled);
    }
    public string escape(string s) {
        return s.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;");
    }
    
    public string filter(string input) {
        bool tagA = false;
        int index = 0, tagStrong = 0;
        StringBuilder sb = new StringBuilder(input.Length * 2);

        for (Match m = _regFilter.Match(input); m.Success; m = _regFilter.Match(input, index)) {
            sb.Append(escape(input.Substring(index, m.Index - index)));
            index = m.Index + m.Length;

            if (m.Groups["begin"].Success) {
                switch (m.Groups["begin"].Value.ToLower()) {
                    case "a":
                        string href = "";
                        foreach (Capture capture in m.Groups["attr"].Captures) {
                            string[] attribute = capture.Value.Split('=');
                            if (attribute[0].Trim().Equals("href", StringComparison.OrdinalIgnoreCase)) {
                                href = " href=" + attribute[1].Trim();
                                break;
                            }
                        }
                        sb.Append(tagA ? "</a><a" : "<a").Append(href).Append(">");
                        tagA = true;
                        break;
                    case "strong":
                        tagStrong++;
                        sb.Append("<strong>");
                        break;
                    case "br":
                        sb.Append("<br/>");
                        break;
                    default:
                        sb.Append(escape(m.Value));
                        break;
                }
            } else {
                switch (m.Groups["end"].Value.ToLower()) {
                    case "a":
                        if (tagA) {
                            sb.Append("</a>");
                            tagA = false;
                        } else {
                            sb.Append(escape(m.Value));
                        }
                        break;
                    case "strong":
                        if (tagStrong > 0) {
                            tagStrong--;
                            sb.Append("</strong>");
                        } else {
                            sb.Append(escape(m.Value));
                        }
                        break;
                    default:
                        sb.Append(escape(m.Value));
                        break;
                }
            }
        }

        sb.Append(escape(input.Substring(index, input.Length - index)));

        while (tagStrong-- > 0) sb.Append("</strong>");
        if (tagA) sb.Append("</a>");

        return sb.ToString();
    }
}

class Program {
    static void Main(string[] args) {
        HtmlFilter f = new HtmlFilter();
        string text = System.IO.File.ReadAllText("hoge.txt");
        Console.WriteLine(f.filter(text));
    }
}

Index

Feed

Other

Link

Pathtraq

loading...