feat: refine excel export to apply bold formatting only to fully bolded cells
This commit is contained in:
@@ -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,21 +926,17 @@ 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,
|
else:
|
||||||
value,
|
worksheet.write(row_idx + 1, col_idx, value, current_format)
|
||||||
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)
|
||||||
|
|
||||||
@@ -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)
|
|
||||||
|
|||||||
@@ -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,21 +931,17 @@ 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,
|
else:
|
||||||
value,
|
worksheet.write(row_idx + 1, col_idx, value, current_format)
|
||||||
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)
|
||||||
|
|
||||||
@@ -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)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user