feat: refine excel export to apply bold formatting only to fully bolded cells

This commit is contained in:
fujie
2026-01-03 14:16:00 +08:00
parent c460337c43
commit 3e73fcb3f0
2 changed files with 50 additions and 156 deletions

View File

@@ -749,9 +749,16 @@ class Action:
} }
) )
# Bold and Italic font formats (for rich text) # Bold cell style (for full cell bolding)
bold_font_format = workbook.add_format({"bold": True}) text_bold_format = workbook.add_format(
italic_font_format = workbook.add_format({"italic": True}) {
"border": 1,
"align": "left",
"valign": "vcenter",
"text_wrap": True,
"bold": True,
}
)
for i, table in enumerate(tables): for i, table in enumerate(tables):
try: try:
@@ -824,8 +831,7 @@ class Action:
decimal_format, decimal_format,
date_format, date_format,
sequence_format, sequence_format,
bold_font_format, text_bold_format,
italic_font_format,
) )
except Exception as e: except Exception as e:
@@ -849,8 +855,7 @@ class Action:
decimal_format, decimal_format,
date_format, date_format,
sequence_format, sequence_format,
bold_font_format=None, text_bold_format=None,
italic_font_format=None,
): ):
""" """
Apply enhanced formatting Apply enhanced formatting
@@ -859,7 +864,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**) and italic (*text*) - Supports full cell Markdown bold (**text**)
""" """
try: try:
# 1. Write headers (Center aligned) # 1. Write headers (Center aligned)
@@ -921,23 +926,19 @@ class Action:
# Text - Left aligned # Text - Left aligned
current_format = text_format current_format = text_format
if ( if content_type == "text" and isinstance(value, str):
content_type == "text" # Check for full cell bold (**text**)
and isinstance(value, str) match = re.fullmatch(r"\*\*(.+)\*\*", value.strip())
and ("**" in value or "*" in value) if match:
): # Extract content and apply bold format
# Try to parse Markdown bold/italic clean_value = match.group(1)
self.write_rich_string_cell( worksheet.write(
worksheet, row_idx + 1, col_idx, clean_value, text_bold_format
row_idx + 1,
col_idx,
value,
current_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)
else:
worksheet.write(row_idx + 1, col_idx, value, current_format)
# 4. Auto-adjust column width # 4. Auto-adjust column width
for col_idx, column in enumerate(headers): for col_idx, column in enumerate(headers):
@@ -1028,59 +1029,5 @@ class Action:
except Exception as e: except Exception as e:
print(f"Error in basic formatting: {str(e)}") print(f"Error in basic formatting: {str(e)}")
def write_rich_string_cell(
self,
worksheet,
row,
col,
text,
cell_format,
bold_format,
italic_format,
):
"""
Parse Markdown bold (**) and italic (*) and write to rich string cell
Note: Does not support nested formatting or mixed overlapping tags for simplicity.
"""
try:
parts = []
current_text = text
has_formatting = False
# Regex to match **bold** OR *italic*
# Priority to bold (**) because it's longer
pattern = re.compile(r"(\*\*(.*?)\*\*)|(\*(.*?)\*)")
last_end = 0
for match in pattern.finditer(text):
has_formatting = True
start, end = match.span()
# Add preceding normal text
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(match.group(2))
elif match.group(3): # Italic match (*...*)
parts.append(italic_format)
parts.append(match.group(4))
last_end = end
# Add remaining text
if last_end < len(text):
parts.append(text[last_end:])
if has_formatting and len(parts) > 1:
# Must end with cell_format
parts.append(cell_format)
worksheet.write_rich_string(row, col, *parts)
else:
worksheet.write(row, col, text, cell_format)
except Exception as e: except Exception as e:
print(f"Error writing rich string: {e}") print(f"Error in basic formatting: {str(e)}")
worksheet.write(row, col, text, cell_format)

View File

@@ -754,9 +754,16 @@ class Action:
} }
) )
# 粗体和斜体字体格式 (用于富文本) # 粗体单元格样式 (用于全单元格加粗)
bold_font_format = workbook.add_format({"bold": True}) text_bold_format = workbook.add_format(
italic_font_format = workbook.add_format({"italic": True}) {
"border": 1,
"align": "left",
"valign": "vcenter",
"text_wrap": True,
"bold": True,
}
)
for i, table in enumerate(tables): for i, table in enumerate(tables):
try: try:
@@ -829,8 +836,7 @@ class Action:
decimal_format, decimal_format,
date_format, date_format,
sequence_format, sequence_format,
bold_font_format, text_bold_format,
italic_font_format,
) )
except Exception as e: except Exception as e:
@@ -854,8 +860,7 @@ class Action:
decimal_format, decimal_format,
date_format, date_format,
sequence_format, sequence_format,
bold_font_format=None, text_bold_format=None,
italic_font_format=None,
): ):
""" """
应用符合中国官方表格规范的格式化 应用符合中国官方表格规范的格式化
@@ -864,7 +869,7 @@ class Action:
- 文本: 左对齐 - 文本: 左对齐
- 日期: 居中对齐 - 日期: 居中对齐
- 序号: 居中对齐 - 序号: 居中对齐
- 支持 Markdown 粗体 (**text**) 和斜体 (*text*) - 支持全单元格 Markdown 粗体 (**text**)
""" """
try: try:
# 1. 写入表头(居中对齐) # 1. 写入表头(居中对齐)
@@ -926,23 +931,19 @@ class Action:
# 文本类型 - 左对齐 # 文本类型 - 左对齐
current_format = text_format current_format = text_format
if ( if content_type == "text" and isinstance(value, str):
content_type == "text" # 检查是否全单元格加粗 (**text**)
and isinstance(value, str) match = re.fullmatch(r"\*\*(.+)\*\*", value.strip())
and ("**" in value or "*" in value) if match:
): # 提取内容并应用粗体格式
# 尝试解析 Markdown 粗体/斜体 clean_value = match.group(1)
self.write_rich_string_cell( worksheet.write(
worksheet, row_idx + 1, col_idx, clean_value, text_bold_format
row_idx + 1,
col_idx,
value,
current_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)
else:
worksheet.write(row_idx + 1, col_idx, value, current_format)
# 4. 自动调整列宽 # 4. 自动调整列宽
for col_idx, column in enumerate(headers): for col_idx, column in enumerate(headers):
@@ -1043,59 +1044,5 @@ class Action:
except Exception as e: except Exception as e:
print(f"Warning: Even basic formatting failed: {str(e)}") print(f"Warning: Even basic formatting failed: {str(e)}")
def write_rich_string_cell(
self,
worksheet,
row,
col,
text,
cell_format,
bold_format,
italic_format,
):
"""
解析 Markdown 粗体 (**) 和斜体 (*) 并写入富文本单元格
注意: 为简化实现,不支持嵌套格式或混合重叠标签
"""
try:
parts = []
current_text = text
has_formatting = False
# 正则匹配 **bold** 或 *italic*
# 优先匹配粗体 (**),因为它更长
pattern = re.compile(r"(\*\*(.*?)\*\*)|(\*(.*?)\*)")
last_end = 0
for match in pattern.finditer(text):
has_formatting = True
start, end = match.span()
# 添加前面的普通文本
if start > last_end:
parts.append(text[last_end:start])
# 添加格式化文本
if match.group(1): # 粗体匹配 (**...**)
parts.append(bold_format)
parts.append(match.group(2))
elif match.group(3): # 斜体匹配 (*...*)
parts.append(italic_format)
parts.append(match.group(4))
last_end = end
# 添加剩余文本
if last_end < len(text):
parts.append(text[last_end:])
if has_formatting and len(parts) > 1:
# 必须以 cell_format 结尾
parts.append(cell_format)
worksheet.write_rich_string(row, col, *parts)
else:
worksheet.write(row, col, text, cell_format)
except Exception as e: except Exception as e:
print(f"Error writing rich string: {e}") print(f"Warning: Even basic formatting failed: {str(e)}")
worksheet.write(row, col, text, cell_format)