2021-12-26 23:06:03 +08:00
|
|
|
|
# -------------------------------
|
|
|
|
|
# Difficult Rocket
|
2022-06-27 16:51:14 +08:00
|
|
|
|
# Copyright © 2021-2022 by shenjackyuanjie 3695888@qq.com
|
2021-12-26 23:06:03 +08:00
|
|
|
|
# All rights reserved
|
|
|
|
|
# -------------------------------
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
writen by shenjackyuanjie
|
|
|
|
|
mail: 3695888@qq.com
|
|
|
|
|
github: @shenjackyuanjie
|
|
|
|
|
gitee: @shenjackyuanjie
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
|
2022-04-26 22:05:58 +08:00
|
|
|
|
from utils import translate
|
2021-12-26 23:06:03 +08:00
|
|
|
|
|
|
|
|
|
default_style = {
|
|
|
|
|
'font_name': 'Times New Roman',
|
|
|
|
|
'font_size': 12,
|
2022-09-04 13:53:09 +08:00
|
|
|
|
'bold': False,
|
|
|
|
|
'italic': False
|
2021-12-26 23:06:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SingleTextStyle:
|
|
|
|
|
"""
|
|
|
|
|
单个字符的字体样式
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self,
|
|
|
|
|
font_name: str = '',
|
|
|
|
|
font_size: int = 12,
|
|
|
|
|
bold: bool = False,
|
|
|
|
|
italic: bool = False,
|
|
|
|
|
color: str = 'white',
|
|
|
|
|
text_tag: list = None,
|
|
|
|
|
show: bool = True,
|
|
|
|
|
prefix: str = '',
|
|
|
|
|
suffix: str = '',
|
|
|
|
|
text: str = ''):
|
|
|
|
|
self.font_name = font_name
|
|
|
|
|
self.font_size = font_size
|
|
|
|
|
self.bold = bold
|
|
|
|
|
self.italic = italic
|
|
|
|
|
self.color = color
|
|
|
|
|
self.prefix = prefix
|
|
|
|
|
self.suffix = suffix
|
|
|
|
|
|
|
|
|
|
if not text_tag:
|
|
|
|
|
self._tag = []
|
|
|
|
|
else:
|
|
|
|
|
self._tag = text_tag
|
|
|
|
|
self.show = show
|
|
|
|
|
self.text = text
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def tag(self) -> list:
|
|
|
|
|
return self._tag
|
|
|
|
|
|
|
|
|
|
@tag.setter
|
|
|
|
|
def tag(self, value: list):
|
|
|
|
|
assert type(value) == list, 'SingleTextStyle.tag must be list'
|
|
|
|
|
for tag in value:
|
|
|
|
|
if tag not in self._tag:
|
|
|
|
|
self._tag.append(tag)
|
|
|
|
|
self._tag.sort()
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
对运算操作的支持
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __add__(self, other: 'SingleTextStyle') -> 'SingleTextStyle':
|
|
|
|
|
"""
|
|
|
|
|
叠加两个字体样式 优先使用 other 的样式
|
|
|
|
|
:param other: 叠加的字体样式
|
|
|
|
|
:return: 叠加后的字体样式
|
|
|
|
|
"""
|
|
|
|
|
assert type(other) == SingleTextStyle, f'SingleTextStyle + other\n other must be the same type, not a {type(other)}'
|
|
|
|
|
return SingleTextStyle(
|
2022-06-21 20:15:36 +08:00
|
|
|
|
font_name=other.font_name or self.font_name,
|
|
|
|
|
font_size=other.font_size or self.font_size,
|
|
|
|
|
bold=other.bold or self.bold,
|
|
|
|
|
italic=other.italic or self.italic,
|
|
|
|
|
color=other.color or self.color,
|
|
|
|
|
text_tag=other.tag + self.tag,
|
|
|
|
|
show=other.show or self.show,
|
|
|
|
|
prefix=other.prefix + self.prefix,
|
|
|
|
|
suffix=other.suffix + self.suffix,
|
|
|
|
|
text=self.text
|
2021-12-26 23:06:03 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def __iadd__(self, other: 'SingleTextStyle') -> 'SingleTextStyle':
|
|
|
|
|
"""
|
|
|
|
|
叠加两个字体样式 优先使用 other 的样式
|
|
|
|
|
:param other: 叠加的字体样式
|
|
|
|
|
:return: 叠加后的字体样式
|
|
|
|
|
"""
|
|
|
|
|
assert type(other) == SingleTextStyle, f'SingleTextStyle += other\n other must be the same type, not a {type(other)}'
|
|
|
|
|
self.font_name = other.font_name or self.font_name
|
|
|
|
|
self.font_size = other.font_size or self.font_size
|
|
|
|
|
self.bold = other.bold or self.bold
|
|
|
|
|
self.italic = other.italic or self.italic
|
|
|
|
|
self.color = other.color or self.color
|
|
|
|
|
self.tag += other.tag
|
|
|
|
|
self.show = other.show or self.show
|
|
|
|
|
self.prefix += other.prefix
|
|
|
|
|
self.suffix += other.suffix
|
|
|
|
|
self.text = self.text
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
对各种判定的支持
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def have_tag(self, other: 'SingleTextStyle') -> bool:
|
|
|
|
|
"""
|
|
|
|
|
比较两个字体样式tag是否相同
|
|
|
|
|
:param other: 叠加的字体样式
|
|
|
|
|
:return: 是否相同
|
|
|
|
|
"""
|
|
|
|
|
assert type(other) == SingleTextStyle
|
|
|
|
|
return other.tag in self.tag
|
|
|
|
|
|
|
|
|
|
def same_font(self, other: 'SingleTextStyle') -> bool:
|
|
|
|
|
"""
|
|
|
|
|
比较两个字体样式的字体属性是否相同
|
|
|
|
|
:param other: 叠加的字体样式
|
|
|
|
|
:return: 是否相同
|
|
|
|
|
"""
|
|
|
|
|
assert type(other) == SingleTextStyle
|
|
|
|
|
return (self.font_name == other.font_name and
|
|
|
|
|
self.font_size == other.font_size and
|
|
|
|
|
self.color == other.color and
|
|
|
|
|
self.show == other.show)
|
|
|
|
|
|
|
|
|
|
def same_bold(self, other: 'SingleTextStyle') -> bool:
|
|
|
|
|
"""
|
|
|
|
|
比较两个字体样式的加粗属性是否相同
|
|
|
|
|
:param other: 叠加的字体样式
|
|
|
|
|
:return: 是否相同
|
|
|
|
|
"""
|
|
|
|
|
assert type(other) == SingleTextStyle
|
|
|
|
|
return self.bold == other.bold
|
|
|
|
|
|
|
|
|
|
def same_italic(self, other: 'SingleTextStyle') -> bool:
|
|
|
|
|
"""
|
|
|
|
|
比较两个字体样式的斜体属性是否相同
|
|
|
|
|
:param other: 叠加的字体样式
|
|
|
|
|
:return: 是否相同
|
|
|
|
|
"""
|
|
|
|
|
assert type(other) == SingleTextStyle
|
|
|
|
|
return self.italic == other.italic
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
自动输出一些属性的支持
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def HTML_font(self, suffix: bool = False) -> str:
|
|
|
|
|
"""
|
|
|
|
|
输出字体样式的HTML字符
|
|
|
|
|
:return: HTML 格式字符
|
|
|
|
|
"""
|
|
|
|
|
if suffix:
|
|
|
|
|
return font_HTML_end
|
|
|
|
|
text = f'<font face="{self.font_name}" color={self.color}'
|
|
|
|
|
if self.font_size != default_style['font_size']:
|
|
|
|
|
text += f' real_size={self.font_size}'
|
|
|
|
|
text += '>'
|
|
|
|
|
return text
|
|
|
|
|
|
|
|
|
|
def HTML_bold(self, suffix: bool = False) -> str:
|
|
|
|
|
"""
|
|
|
|
|
输出字体粗体的HTML字符
|
|
|
|
|
:return: HTML 格式字符
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
if self.bold:
|
|
|
|
|
if suffix:
|
|
|
|
|
return bold_HTML_end
|
|
|
|
|
return '<b>'
|
|
|
|
|
else:
|
|
|
|
|
return ''
|
|
|
|
|
|
|
|
|
|
def HTML_italic(self, suffix: bool = False) -> str:
|
|
|
|
|
"""
|
|
|
|
|
输出字体斜体的HTML字符
|
|
|
|
|
:return: HTML 格式字符
|
|
|
|
|
"""
|
|
|
|
|
if self.italic:
|
|
|
|
|
if suffix:
|
|
|
|
|
return italic_HTML_end
|
|
|
|
|
return '<i>'
|
|
|
|
|
else:
|
|
|
|
|
return ''
|
|
|
|
|
|
|
|
|
|
def HTML(self, suffix: bool = False) -> str:
|
|
|
|
|
"""
|
|
|
|
|
输出字体样式的HTML字符
|
|
|
|
|
:return: HTML 格式字符
|
|
|
|
|
"""
|
|
|
|
|
if not suffix:
|
|
|
|
|
return self.HTML_bold() + self.HTML_italic() + self.HTML_font()
|
|
|
|
|
else:
|
|
|
|
|
return font_HTML_end + (bold_HTML_end if self.bold else '') + (italic_HTML_end if self.italic else '')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# [\u4e00-\u9fa5] 中文字符
|
|
|
|
|
default_fonts_config = [
|
|
|
|
|
{
|
2022-08-29 00:26:14 +08:00
|
|
|
|
'match': re.compile(r''), # 匹配的字符 匹配选项是re.compile()
|
|
|
|
|
'shown': re.compile(r''), # 匹配到的字符中显示的部分 匹配选项是re.compile()
|
2021-12-26 23:06:03 +08:00
|
|
|
|
'style': SingleTextStyle(font_name=translate.鸿蒙简体, font_size=15, bold=False, italic=False, show=True, color='white'),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'match': re.compile(r'[a-zA-Z0-9]'),
|
|
|
|
|
'shown': re.compile(r'[a-zA-Z0-9]'),
|
|
|
|
|
'style': SingleTextStyle(font_name=translate.微软等宽, font_size=15)
|
|
|
|
|
},
|
|
|
|
|
# Markdown 语法规则匹配
|
|
|
|
|
{
|
|
|
|
|
# Markdown 粗体语法规则匹配
|
|
|
|
|
'match': re.compile(r'\*\*(.*?(?<!\s))\*\*'),
|
|
|
|
|
'shown': re.compile(r'(?<=\*\*)(.*?(?<!\s))(?=\*\*)'),
|
2022-09-04 13:53:09 +08:00
|
|
|
|
'tag': {
|
2021-12-26 23:06:03 +08:00
|
|
|
|
# 为 match 匹配到的字符添加标签
|
|
|
|
|
'match': re.compile(r'\*\*'),
|
|
|
|
|
'style': SingleTextStyle(text_tag=['bold'])
|
|
|
|
|
},
|
|
|
|
|
'style': SingleTextStyle(bold=True)
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
# Markdown 斜体语法规则匹配
|
2022-09-04 13:53:09 +08:00
|
|
|
|
'match': re.compile(r'\*(.*?(?<!\s))\*'),
|
|
|
|
|
'shown': re.compile(r'(?<=\*)(.*?(?<!\s))(?=\*)'),
|
2021-12-26 23:06:03 +08:00
|
|
|
|
'ignore': {
|
|
|
|
|
# 如果匹配到的字符含有 tag 就忽略本次解析
|
|
|
|
|
'match': re.compile(r'\*'),
|
2022-09-04 13:53:09 +08:00
|
|
|
|
'tag': SingleTextStyle(text_tag=['italic'])
|
2021-12-26 23:06:03 +08:00
|
|
|
|
},
|
2022-09-04 13:53:09 +08:00
|
|
|
|
'style': SingleTextStyle(italic=True)
|
2021-12-26 23:06:03 +08:00
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
# Markdown 链接规则匹配
|
|
|
|
|
# 注意:这里的匹配模式是非贪婪的,即匹配到的结果必须是完整的
|
|
|
|
|
# 即:链接名称不能是空格等空白字符开头,链接名称不能是空格等空白字符结尾
|
|
|
|
|
# 匹配的内容:[abc](def)
|
|
|
|
|
# 显示的内容:abc
|
|
|
|
|
'match': re.compile(r'\[(.*?(?<!\s))\]\((.*?(?<!\s))\)'),
|
|
|
|
|
'shown': re.compile(r'(?<=\[)(.*?(?<!\s))(?=\]\((.*?(?<!\s))\))'),
|
|
|
|
|
'style': SingleTextStyle(bold=True)
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
font_HTML_end = '</font>'
|
|
|
|
|
bold_HTML = '<b>'
|
|
|
|
|
bold_HTML_end = '</b>'
|
|
|
|
|
italic_HTML = '<i>'
|
|
|
|
|
italic_HTML_end = '</i>'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def decode_text2HTML(text: str,
|
2022-02-07 22:14:51 +08:00
|
|
|
|
configs=None,
|
|
|
|
|
show_style: bool = False) -> str:
|
2021-12-26 23:06:03 +08:00
|
|
|
|
if text == '':
|
|
|
|
|
return ''
|
|
|
|
|
if configs is None:
|
|
|
|
|
configs = default_fonts_config
|
|
|
|
|
style_list = [SingleTextStyle(text=text[x]) for x in range(0, len(text))]
|
|
|
|
|
|
|
|
|
|
# 根据输入的配置对每一个字符进行样式设定
|
|
|
|
|
for config in configs:
|
|
|
|
|
# 根据 配置"文件"
|
2022-02-07 22:14:51 +08:00
|
|
|
|
match_texts = config['match'].finditer(text) # 使用 config.match 匹配
|
2021-12-26 23:06:03 +08:00
|
|
|
|
for match_text in match_texts: # 每一个匹配到的匹配项
|
|
|
|
|
text_match = match_text.group() # 缓存一下匹配到的字符,用于匹配显示的字符
|
2022-02-07 22:14:51 +08:00
|
|
|
|
shown_texts = config['shown'].finditer(text_match) # 使用 config.shown 匹配
|
2021-12-26 23:06:03 +08:00
|
|
|
|
match_start, match_end = match_text.span()
|
|
|
|
|
if 'ignore' in config: # 如果样式选项包含忽略某些字符的tag
|
|
|
|
|
ignore_texts = config['ignore']['match'].finditer(text_match) # 根据选项匹配可能忽略的字符
|
|
|
|
|
ignore = False # 忽略先为False
|
|
|
|
|
for ignore_text in ignore_texts: # 每一个可能忽略的字符
|
|
|
|
|
if ignore: # 为了方便退出
|
|
|
|
|
break
|
|
|
|
|
for ignore_index in range(match_start + ignore_text.span()[0], match_start + ignore_text.span()[1]): # 对每一个可能的字符进行检测
|
|
|
|
|
if style_list[ignore_index].have_tag(config['ignore']['tag']): # 如果确实包含要忽略的
|
|
|
|
|
ignore = True # 忽略为True
|
|
|
|
|
break
|
|
|
|
|
if ignore:
|
|
|
|
|
continue # 跳过本次匹配
|
|
|
|
|
if 'tag' in config: # 如果样式选项包含对部分字符添加tag
|
|
|
|
|
tag_texts = config['tag']['match'].finditer(text_match) # 根据配置的正则表达式匹配要添加tag的字符
|
|
|
|
|
for tag_text in tag_texts: # 对每一个匹配到的~~~~~~
|
|
|
|
|
for tag_index in range(match_start + tag_text.span()[0], match_start + tag_text.span()[1]): # 用于遍历匹配到的字符
|
|
|
|
|
style_list[tag_index] += config['tag']['style']
|
|
|
|
|
# 为匹配到的字符添加样式
|
|
|
|
|
for match_index in range(match_start, match_end): # 用于遍历匹配到的字符
|
2022-02-07 22:14:51 +08:00
|
|
|
|
# 这里用 match index 来精确读写列表里的元素,毕竟 re.Match 返回的 span 是两个标点,得遍历
|
|
|
|
|
style_list[match_index] += config['style'] # 字体样式列表的 [match_index] += config['style'] 的样式
|
|
|
|
|
style_list[match_index].show = show_style # 设置显示属性变为 False
|
2021-12-26 23:06:03 +08:00
|
|
|
|
# 为每一个显示的字符设置显示属性
|
|
|
|
|
for shown_text in shown_texts: # 每一个显示的匹配项
|
|
|
|
|
for shown_index in range(match_start + shown_text.span()[0], match_start + shown_text.span()[1]):
|
|
|
|
|
style_list[shown_index].show = True
|
2022-02-07 22:14:51 +08:00
|
|
|
|
# 字体样式列表的 [shown_index] 设置显示属性变为 True
|
2021-12-26 23:06:03 +08:00
|
|
|
|
# 开始根据配置好的样式输出HTML文本
|
|
|
|
|
style_list[0].prefix += style_list[0].HTML() # 不管怎么说都要在最前面加一个字符标识
|
|
|
|
|
for style_index in range(1, len(style_list)):
|
|
|
|
|
if style_list[style_index].show: # 如果这个字符显示
|
|
|
|
|
if not style_list[style_index - 1].show: # 如果前面一个字符不显示(且这个字符显示)
|
|
|
|
|
style_list[style_index].prefix += style_list[style_index].HTML() # 那么就直接给这个字符的前缀添加
|
|
|
|
|
else: # 开始根据前面的情况处理每种单独的标签
|
|
|
|
|
if not style_list[style_index - 1].same_font(style_list[style_index]):
|
|
|
|
|
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML_font(suffix=True)
|
|
|
|
|
style_list[style_index].prefix += style_list[style_index].HTML_font()
|
|
|
|
|
if not style_list[style_index - 1].same_bold(style_list[style_index]):
|
|
|
|
|
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML_bold(suffix=True)
|
|
|
|
|
style_list[style_index].prefix += style_list[style_index].HTML_bold()
|
|
|
|
|
if not style_list[style_index - 1].same_italic(style_list[style_index]):
|
|
|
|
|
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML_italic(suffix=True)
|
|
|
|
|
style_list[style_index].prefix += style_list[style_index].HTML_italic()
|
|
|
|
|
else: # 如果这个字符不显示
|
|
|
|
|
if style_list[style_index - 1].show: # 如果前面一个字符显示(且这个字符不显示)
|
|
|
|
|
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML(suffix=True)
|
2022-02-07 22:14:51 +08:00
|
|
|
|
# 如果前面一个字符也不显示那就直接 pass
|
2021-12-26 23:06:03 +08:00
|
|
|
|
if style_list[-1].show:
|
|
|
|
|
style_list[-1].suffix += style_list[-1].HTML(suffix=True)
|
|
|
|
|
|
2022-02-07 22:14:51 +08:00
|
|
|
|
# 输出最终的 HTML 文本
|
2021-12-26 23:06:03 +08:00
|
|
|
|
formatted_HTML_text = '' # 初始化一下
|
|
|
|
|
for style in style_list: # 每一个样式
|
|
|
|
|
if style.show: # 如果这个字符显示
|
|
|
|
|
formatted_HTML_text += style.prefix + style.text + style.suffix # 文本的后面附加一下
|
2022-02-07 22:14:51 +08:00
|
|
|
|
del style_list # 主动删掉 style_list 释放内存
|
2021-12-26 23:06:03 +08:00
|
|
|
|
return formatted_HTML_text # 返回,DONE!
|