NGA(艾泽拉斯国家地理) 论坛使用一种自定义的名为 bbscode
的代码来排版帖子内容,类似HTML,它也是一种标记语言,对bbscode的详细介绍可见:[NGA常用BBS代码][奥运帖]Project N —— 《从入门到精通:排版的艺术 Ver.3》 。
这种论坛自定义标记语言可以和markdown、html进行相互转换。例子如下:
1 2 3 4 5 6 7 [h]标题[/h] [b]加粗文字[/b] [list] [*] 列表项 [*] 列表项 [/list] [quote]引用块[/quote]
在使用NGA论坛的时候遇到了将markdown文本转换为bbscode的需求,所以打算用python写一个简单的转换程序。由于不涉及复杂的GUI,本项目使用tkinter来编写界面。
项目地址:
效果
自定义包 自定义包 bbscode
结构非常简单,只含有 __init__.py
和一个python文件 converter.py
。
converter.py
中含有 md_to_bbscode
这一核心转换方法,参数为markdown文本字符串,返回bbscode字符串。
这个转换函数的原理非常简单,只用到了python的一个正则表达式替换方法 re.sub
,它的参数分别为:
代码如下:
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 import redef replace_quote (matched ): quote = matched.group(1 ) quote = re.sub(r"> (.*?)" ,"" ,quote) quote = "[quote]\n{}\n[/quote]" .format(quote) return quote def replace_list (matched ): l = matched.group(1 ) l = re.sub(r"[-*] " ,"[*]" ,l) l = "[list]\n{}\n[/list]" .format(l) return l def replace_italic (matched ): italic = matched.group(1 ) step = 50 italics = [italic[i:i+step] for i in range(0 ,len(italic),step)] italic = '' for item in italics: italic +="[i]{}[/i]" .format(item) return italic def md_to_bbscode (md_str:str ): ''' 将markdown字符串转换为bbscode字符串 ''' bbscode = md_str bbscode = re.sub(r"[^!]\[(.*?)\]\((.*?)\)" ,r"[url=\2]\1[/url]" ,bbscode) bbscode = re.sub(r"\!\[(.*?)\]\((.*?)\)" ,r"[img]\2[/img]" ,bbscode) bbscode = re.sub(r"^(#+)\s?(.*)" ,r"[h]\2[/h]" ,bbscode,flags=re.MULTILINE) bbscode = re.sub(r"\*\*(.*?)\*\*" ,r"[b]\1[/b]" ,bbscode) bbscode = re.sub(r"\*(.*?)\*" ,replace_italic,bbscode) bbscode = re.sub(r"<u>(.*?)</u>" ,r"[u]\1[/u]" ,bbscode) bbscode = re.sub(r"~~(.*?)~~" ,r"[del]\1[/del]" ,bbscode) bbscode = re.sub(r"((> (.*)\n?)+)" ,replace_quote,bbscode) bbscode = re.sub(r"(([-|*] (.*)\n?)+)" ,replace_list,bbscode) return bbscode
无序列表的替换 从代码可以看出,大部分markdown代码都可以直接转换为bbscode,但对于列表、引用块来说,它们对应的bbscode除了项目符号之外,还需要在两侧加上对应的标签,这就无法直接替换,需要编写自定义repl函数了。
以无序列表的转换为例,markdown的无序列表代码如下:
1 2 3 4 5 - 列表项1- 列表项2* 列表项a* 列表项b
以上两种方式都是无序列表。需要将它们转换为:
1 2 3 4 5 6 7 8 9 [list] [*] 列表项1 [*] 列表项2 [/list] [list] [*] 列表项a [*] 列表项b [/list]
首先需要用正则表达式匹配到每一个列表项,匹配单个列表项: [-|*] (.*)\n?
如果想要匹配多行列表项,就需要使用循环匹配符号 +
,至少匹配一项。即:([-|*] (.*)\n?)+
但是此时取匹配组1是取不到所有列表项的,在外面再套一层括号,这时的匹配组1就是我们要的整个无序列表了。
在替换函数 replace_list
中,参数为正则表达式的匹配对象,将项目符号替换并在前后添加 [list]
标签即可。
1 2 3 4 5 def replace_list (matched ): l = matched.group(1 ) l = re.sub(r"[-*] " ,"[*]" ,l) l = "[list]\n{}\n[/list]" .format(l) return l
多行引用转bbscode引用块的原理相同,不赘述。
界面 需要编写的界面只有一个多行输入框加上按钮,直接放代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import tkinter as tkfrom bbscode import converterroot = tk.Tk() root.title("bbscode转换器" ) inputText = tk.Text(root,height=20 ,width=100 ) inputText.pack() def md_to_bbscode (): md_str = inputText.get('1.0' ,tk.END) bbscode = converter.md_to_bbscode(md_str) inputText.delete('1.0' , tk.END) inputText.insert('1.0' ,bbscode) convertBtn = tk.Button(root,text="markdown转换为bbscode" ,command=md_to_bbscode) convertBtn.pack() root.mainloop()