题记
无论发生什么,记住对自己好。
前言
终于,收到了知乎的回复,一面就被拒了(此处应该有一个悲伤的表情)。不过也没什么遗憾了,申请了好多次,终于申请到了笔试和面试的机会。通过这次的经历,我知道了路还很长很长,想把这次的经历写下来,也算是一种纪念。
笔试题一——富文本过滤
当我收到知乎的笔试题时,很激动,因为真心很想去知乎,用颤抖的手打开邮件,里面有两道题,第一道是这样的:
最开始才疏学浅,不知道富文本过滤要干些什么,去搜索了一番,大致知道了过滤是要对Html进行解析,去掉不合法的标签和字符。我最开始还想加上自动correct富文本的功能,比如如果标签不闭合,自动补全等等,但是记得那几天事情真心太多了,还有SQA的口试,没花太多的时间去完善代码。
知道了要干什么,就可以开始写了。我首先想到的肯定是要用到一个解析html库之类,跑一遍html,在解析html的过程中做一些处理。之前有用到过Python中的ElementTree解析过xml,首先去搜索了一番,找到了以下一些资料:
大致说Python里面有很多解析Html的库,内建的HtmlParser貌似是一种方法,但是它却经常在一些非常普通的html时会出现问题,如果你成功解决了这些问题,那么你很有可能重写了一个库——BeautifulSoup。靠谱的解析Html的方式大概有三种:
lxml.html,
BeautifulSoup,
html5lib。
但是考虑到可能面试官不会去安装这些库,我还是决定用python内建的HtmlParser去完成这道题。去搜了一下这个类的使用方法,发现原理跟Java使用SAX方式解析XML是一样的,都是提供了一系列的回调方法,使用时需要继承自相应的类,覆盖这些方法,添加上你自己的处理。比如遇到起始的tag有一个回调的方法,遇到文本有一个回调的方法,还需要一个变量来保存上一次遇到的tag,代码如下:
import HTMLParser, sys
class EditorParser(HTMLParser.HTMLParser):
def __init__(self, standard):
HTMLParser.HTMLParser.__init__(self)
self.standard = standard
self.clean_text = []
self.pre_tag = None
def handle_starttag(self, tag, attrs):
if tag in self.standard:
self.clean_text.append('<')
self.clean_text.append(tag)
for name, val in attrs:
if self.standard[tag] and name in self.standard[tag]:
exp = ' %s="%s"' % (name, val)
self.clean_text.append(exp)
self.clean_text.append('>')
self.pre_tag = tag
def handle_data(self, data):
if self.pre_tag in self.standard:
self.clean_text.append(data)
def handle_endtag(self, tag):
if tag in self.standard:
self.clean_text.append('</{0}>'.format(tag))
self.pre_tag = None
def get_clean_text(self):
return ''.join(self.clean_text)
def main():
if len(sys.argv) < 2:
print '\nUse like this:\n\t$python filter.py [html_file_to_handle]\nThe clean html will be output to a new html file.\n'
return
html = open(sys.argv[1], 'r')
legal_tag_attr = {'a' : ['href', 'title'], 'abbr' : ['title'], 'acronym' : ['title'], 'b' : None, 'blockquote' : ['cite'], 'cite' : None, \
'code' : None, 'del' : ['datetime'], 'em' : None, 'i' : None, 'q' :['cite'], 'strike' : None, 'strong' : None, 'pre' : None}
editorParser = EditorParser(legal_tag_attr)
editorParser.feed(html.read())
clean_text = editorParser.get_clean_text()
editorParser.close()
html.close()
# print clean_text
clean_html = open(sys.argv[1].split('.')[0] + '_clean.html', 'w')
clean_html.write(clean_text)
clean_html.close()
if __name__ == '__main__':
main()
样例输入与输出
样例的输入:
<abbr>This is legal abbr text.</abbr>
<a href="http://www.zhihu.com" id="bad_id">
<strong name="bad_name" id="bad_id" class="bad_class">This is a legal strong href</strong>
</a>
<head>This is a bad head</head>
<acronym title="acronym titel"></acronym>
</br>
</em>
<body>This is bad body.</body>
<title class="bad_class">This is bad title.</title>
经过过滤后的样例输出:
<abbr>This is legal abbr text.</abbr><a href="http://www.zhihu.com">
<strong>This is a legal strong href</strong></a><acronym title="acronym titel"></acronym></em>
HtmlParser提供的功能真的很少,只提供了最基本的功能,要对HTML做一些深入的操作还得用其他的lib。