challenge 改行をBRタグに置き換える

一部のHTMLタグを通すフィルタ どう書く?の続編です。 前回の条件を満たしつつ、入力中の改行を<br/>に置き換えてください。ただし、たとえば"<a\nhref=...>"といったようにタグの中に改行がある場合、単純に置換するわけには行かないことに注意してください。

また、ユーザの入力注の<br>は<br/>に変換してください。

このお題はperezvonさんの提案を元にした三部作の二問目です。ご協力ありがとうございました。

Posted feedbacks - Python

前のお題の#2759で実装したクラスを継承します。
#2759には下の方にテスト用の式をトップレベルに
書いてあるので適当に処理してください。

置き換えたタグ内の改行も、引用符にくくられていようと
無視して<br/>に置換しています。
 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
from HTMLParser2 import HTMLParser2

class HTMLParser3(HTMLParser2):

  def replace(self, s):
    return s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('\n', '<br/>')

  def handle_starttag(self, tag, attrs):
    if tag == 'br':
      self.buf += '<br/>'
    else:
      HTMLParser2.handle_starttag(self, tag, attrs)

  def handle_data(self, data):
    self.buf += data.replace('\n', '<br/>')
  
def f(s):
  h = HTMLParser3()
  h.feed(s)
  print s
  print h.buf

if __name__ == '__main__':
  f('''<script foo="<script>alert('bar')</script>">alert('foo')</script>''')
  f('''<script foo="<a href='link'>link</a>">alert('foo')</script>''')
  f('''<a href='www.g>oogle.com'>link</a>''')
  f('''<br>abc\ndef\n<br>''')

同じく前回の投稿 #2763 を再利用して。

折角、フィルタ登録型にしたのに、
フィルタ探索関数をクロージャにしてしまったのが裏目にでた。
MyHTMLParserを継承してますが、変更部分は filterメソッド内の find_filter のみです。

今回のお題の追加分は、
fix_br_tag, nl_to_br_in_text 。

 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
# wget http://ja.doukaku.org/comment/2763/download/ -O MyHTMLParser.py
 

from MyHTMLParser import MyHTMLParser, TEXT,TAG


class MyHTMLParser2(MyHTMLParser):

    def filter(self, (state,tag,attrs,text)):
        #  find_filter = lambda x:x.get((state,tag.lower()), lambda x:x)
        def find_filter(filters):
            tag_ = tag.lower()
            if filters.has_key((state,tag_)):
                return filters.get((state,tag_))
            return filters.get((state,None), lambda x:x)


        tag,attrs = find_filter(self.tag_filters)((tag,attrs))
        attrs = find_filter(self.attr_filters)(attrs)
        text = find_filter(self.text_filters)(text)

        return state,tag,attrs,text


def test(html):
    import re

    def allow_attrs(*names):
        return lambda attrs: [(k,quote(v)) for k,v in attrs if k.lower() in names]

    def remove_all_attrs(attrs):
        return []

    def fix_br_tag((tag,attrs)):
        return ('br/',attrs)

    def nl_to_br_in_text(text):
        return re.sub(text, r"(\r\n|\r|\n)","<br />")

    p = MyHTMLParser2()
    p.allow_tags += ['a', 'br', 'strong']
    p.attr_filters[(TAG,'a')] = allow_attrs('href', 'name') 
    p.attr_filters[(TAG,'br')] = remove_all_attrs
    p.attr_filters[(TAG,'strong')] = remove_all_attrs
    p.tag_filters[(TAG,'br')] = fix_br_tag
    p.text_filters[(TEXT,None)] = nl_to_br_in_text
    p.parse(html)


	
 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
import re

def filter(html):
    def repl(m):
        beg_slash, tag_name, attrs, _, end_slash = m.groups()
        def combine(*names):
            s = "<" + beg_slash + tag_name
            for m in re.finditer(r"""(\w+)\s*=\s*(["']).+?\2""", attrs, re.S):
                if m.group(1).lower() in names:
                    s += " " + m.group(0)
            return s + end_slash + ">"
        if tag_name.lower() == "a":
            return combine("href", "name")
        elif tag_name.lower() == "strong":
            return combine()
        elif tag_name.lower() == "br": # shortcut
            return "<br/>"
        else:
            return m.group(0).replace("<", "&lt;")
    html = re.compile(r"""<(/?)(\w+)((?:\s*\w+\s*=\s*(["']).+?\4)*)\s*(/?)>""", re.S).sub(repl, html)
    return re.compile('(<[^>]*>)|(\n)', re.S).sub(lambda m: m.group(1) or "<br/>", html)

def main():
    print filter("""<a href='www.google.com'>link</a> <blink>and</blink> <strong onClick='alert("NG")'>click<br>me!</strong>""")
    print filter(""" <z foo='<script>alert("Boo")</script>'>""")
    print filter("""<a href="foo.com"
name="foo">foo
bar</a>baz
boo""")

if __name__ == '__main__':
    main()

Index

Feed

Other

Link

Pathtraq

loading...