feat: support markdown italic formatting and refine bold parsing

This commit is contained in:
fujie
2026-01-03 14:12:53 +08:00
parent e775b23503
commit c460337c43
2 changed files with 80 additions and 50 deletions

View File

@@ -749,8 +749,9 @@ class Action:
} }
) )
# Bold font format (for rich text) # Bold and Italic font formats (for rich text)
bold_font_format = workbook.add_format({"bold": True}) bold_font_format = workbook.add_format({"bold": True})
italic_font_format = workbook.add_format({"italic": True})
for i, table in enumerate(tables): for i, table in enumerate(tables):
try: try:
@@ -824,6 +825,7 @@ class Action:
date_format, date_format,
sequence_format, sequence_format,
bold_font_format, bold_font_format,
italic_font_format,
) )
except Exception as e: except Exception as e:
@@ -848,6 +850,7 @@ class Action:
date_format, date_format,
sequence_format, sequence_format,
bold_font_format=None, bold_font_format=None,
italic_font_format=None,
): ):
""" """
Apply enhanced formatting Apply enhanced formatting
@@ -856,7 +859,7 @@ class Action:
- Text: Left aligned - Text: Left aligned
- Date: Center aligned - Date: Center aligned
- Sequence: Center aligned - Sequence: Center aligned
- Supports Markdown bold (**text**) - Supports Markdown bold (**text**) and italic (*text*)
""" """
try: try:
# 1. Write headers (Center aligned) # 1. Write headers (Center aligned)
@@ -921,9 +924,9 @@ class Action:
if ( if (
content_type == "text" content_type == "text"
and isinstance(value, str) and isinstance(value, str)
and "**" in value and ("**" in value or "*" in value)
): ):
# Try to parse Markdown bold # Try to parse Markdown bold/italic
self.write_rich_string_cell( self.write_rich_string_cell(
worksheet, worksheet,
row_idx + 1, row_idx + 1,
@@ -931,6 +934,7 @@ class Action:
value, value,
current_format, current_format,
bold_font_format, bold_font_format,
italic_font_format,
) )
else: else:
worksheet.write(row_idx + 1, col_idx, value, current_format) worksheet.write(row_idx + 1, col_idx, value, current_format)
@@ -1025,41 +1029,52 @@ class Action:
print(f"Error in basic formatting: {str(e)}") print(f"Error in basic formatting: {str(e)}")
def write_rich_string_cell( def write_rich_string_cell(
self, worksheet, row, col, text, cell_format, bold_format self,
worksheet,
row,
col,
text,
cell_format,
bold_format,
italic_format,
): ):
""" """
Parse Markdown bold and write to rich string cell Parse Markdown bold (**) and italic (*) and write to rich string cell
Note: Does not support nested formatting or mixed overlapping tags for simplicity.
""" """
try: try:
parts = [] parts = []
current_text = text current_text = text
has_bold = False has_formatting = False
# Simple parsing logic: split by ** # Regex to match **bold** OR *italic*
while "**" in current_text: # Priority to bold (**) because it's longer
start = current_text.find("**") pattern = re.compile(r"(\*\*(.*?)\*\*)|(\*(.*?)\*)")
end = current_text.find("**", start + 2)
if end != -1: last_end = 0
has_bold = True for match in pattern.finditer(text):
# Add preceding normal text has_formatting = True
if start > 0: start, end = match.span()
parts.append(current_text[:start])
# Add bold text # Add preceding normal text
bold_text = current_text[start + 2 : end] if start > last_end:
parts.append(text[last_end:start])
# Add formatted text
if match.group(1): # Bold match (**...**)
parts.append(bold_format) parts.append(bold_format)
parts.append(bold_text) parts.append(match.group(2))
elif match.group(3): # Italic match (*...*)
parts.append(italic_format)
parts.append(match.group(4))
current_text = current_text[end + 2 :] last_end = end
else:
break
# Add remaining text # Add remaining text
if current_text: if last_end < len(text):
parts.append(current_text) parts.append(text[last_end:])
if has_bold and len(parts) > 1: if has_formatting and len(parts) > 1:
# Must end with cell_format # Must end with cell_format
parts.append(cell_format) parts.append(cell_format)
worksheet.write_rich_string(row, col, *parts) worksheet.write_rich_string(row, col, *parts)

View File

@@ -754,8 +754,9 @@ class Action:
} }
) )
# 粗体字体格式 (用于富文本) # 粗体和斜体字体格式 (用于富文本)
bold_font_format = workbook.add_format({"bold": True}) bold_font_format = workbook.add_format({"bold": True})
italic_font_format = workbook.add_format({"italic": True})
for i, table in enumerate(tables): for i, table in enumerate(tables):
try: try:
@@ -829,6 +830,7 @@ class Action:
date_format, date_format,
sequence_format, sequence_format,
bold_font_format, bold_font_format,
italic_font_format,
) )
except Exception as e: except Exception as e:
@@ -853,6 +855,7 @@ class Action:
date_format, date_format,
sequence_format, sequence_format,
bold_font_format=None, bold_font_format=None,
italic_font_format=None,
): ):
""" """
应用符合中国官方表格规范的格式化 应用符合中国官方表格规范的格式化
@@ -861,7 +864,7 @@ class Action:
- 文本: 左对齐 - 文本: 左对齐
- 日期: 居中对齐 - 日期: 居中对齐
- 序号: 居中对齐 - 序号: 居中对齐
- 支持 Markdown 粗体 (**text**) - 支持 Markdown 粗体 (**text**) 和斜体 (*text*)
""" """
try: try:
# 1. 写入表头(居中对齐) # 1. 写入表头(居中对齐)
@@ -926,9 +929,9 @@ class Action:
if ( if (
content_type == "text" content_type == "text"
and isinstance(value, str) and isinstance(value, str)
and "**" in value and ("**" in value or "*" in value)
): ):
# 尝试解析 Markdown 粗体 # 尝试解析 Markdown 粗体/斜体
self.write_rich_string_cell( self.write_rich_string_cell(
worksheet, worksheet,
row_idx + 1, row_idx + 1,
@@ -936,6 +939,7 @@ class Action:
value, value,
current_format, current_format,
bold_font_format, bold_font_format,
italic_font_format,
) )
else: else:
worksheet.write(row_idx + 1, col_idx, value, current_format) worksheet.write(row_idx + 1, col_idx, value, current_format)
@@ -1040,41 +1044,52 @@ class Action:
print(f"Warning: Even basic formatting failed: {str(e)}") print(f"Warning: Even basic formatting failed: {str(e)}")
def write_rich_string_cell( def write_rich_string_cell(
self, worksheet, row, col, text, cell_format, bold_format self,
worksheet,
row,
col,
text,
cell_format,
bold_format,
italic_format,
): ):
""" """
解析 Markdown 粗体并写入富文本单元格 解析 Markdown 粗体 (**) 和斜体 (*) 并写入富文本单元格
注意: 为简化实现,不支持嵌套格式或混合重叠标签
""" """
try: try:
parts = [] parts = []
current_text = text current_text = text
has_bold = False has_formatting = False
# 简单的解析逻辑:分割 ** # 正则匹配 **bold** 或 *italic*
while "**" in current_text: # 优先匹配粗体 (**),因为它更长
start = current_text.find("**") pattern = re.compile(r"(\*\*(.*?)\*\*)|(\*(.*?)\*)")
end = current_text.find("**", start + 2)
if end != -1: last_end = 0
has_bold = True for match in pattern.finditer(text):
# 添加前面的普通文本 has_formatting = True
if start > 0: start, end = match.span()
parts.append(current_text[:start])
# 添加粗体文本 # 添加前面的普通文本
bold_text = current_text[start + 2 : end] if start > last_end:
parts.append(text[last_end:start])
# 添加格式化文本
if match.group(1): # 粗体匹配 (**...**)
parts.append(bold_format) parts.append(bold_format)
parts.append(bold_text) parts.append(match.group(2))
elif match.group(3): # 斜体匹配 (*...*)
parts.append(italic_format)
parts.append(match.group(4))
current_text = current_text[end + 2 :] last_end = end
else:
break
# 添加剩余文本 # 添加剩余文本
if current_text: if last_end < len(text):
parts.append(current_text) parts.append(text[last_end:])
if has_bold and len(parts) > 1: if has_formatting and len(parts) > 1:
# 必须以 cell_format 结尾 # 必须以 cell_format 结尾
parts.append(cell_format) parts.append(cell_format)
worksheet.write_rich_string(row, col, *parts) worksheet.write_rich_string(row, col, *parts)