You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySide6读取XML填QTableWidget导出python-docxtpl阿拉伯字符显示异常

问题原因

该排版异常由双向文本(BiDi)渲染逻辑差异导致:

  • Qt的QTableWidget会自动检测文本主导方向,为阿拉伯语这类从右到左(RTL)的文本自动添加隐式方向控制,句号、连字符这类中性字符的位置会按照RTL规则正确渲染
  • python-docxtpl底层依赖的python-docx默认不会为文本附加方向控制信息,docx渲染时会误判混合文本中中性字符的所属方向,导致句号等标点出现在文本开头。此前使用python-bidi、arabic-reshaper不生效是因为没有配合docx的渲染规则添加对应的控制标记。

解决方案

给所有包含阿拉伯字符的文本包裹Unicode双向控制字符即可解决错位问题:

  • 文本开头加右向嵌入标记 \u202B(RLE)
  • 文本结尾加弹出方向格式化标记 \u202C(PDF)
    若模板中对应段落还有对齐偏移问题,可以直接在docx模板里把占位符所在段落设置为右对齐。

代码修改

仅需修改export_single方法中读取文本的逻辑即可,修改后代码如下:

# 辅助方法:判断文本是否包含阿拉伯字符
def has_arabic(text):
    for char in text:
        if '\u0600' <= char <= '\u06FF' or '\u0750' <= char <= '\u077F' or '\u08A0' <= char <= '\u08FF':
            return True
    return False

# 修改后的导出方法
def export_single(self):
    teacher = self.teachers_dialog.list_widget.currentItem().text()
    tpl = DocxTemplate('./resources/template.docx')
    context = {
        'teacher': '',
        'days': [],
        'tbl_contents': [],
        'hours': 0,
    }
    # 处理教师名称的双向控制
    context['teacher'] = f"\u202B{teacher}\u202C" if has_arabic(teacher) else teacher
    m_row_headers = [self.teachers_dialog.morning_table.verticalHeaderItem(
        i).text() for i in range(self.teachers_dialog.morning_table.rowCount())]
    m_col_headers = [self.teachers_dialog.morning_table.horizontalHeaderItem(i).text(
    ).split(' ')[0] for i in range(self.teachers_dialog.morning_table.columnCount())]
    for i in range(len(m_row_headers)):
        context['tbl_contents'].append({'hour': '', 'sets': []})
        # 处理行头文本的双向控制
        processed_hour = f"\u202B{m_row_headers[i]}\u202C" if has_arabic(m_row_headers[i]) else m_row_headers[i]
        context['tbl_contents'][i]['hour'] = processed_hour
        for j in range(len(m_col_headers)):
            item = self.teachers_dialog.morning_table.item(i, j)
            if item:
                context['hours'] += 1
                # 核心修改:为单元格文本添加双向控制标记
                cell_text = item.text()
                processed_text = f"\u202B{cell_text}\u202C" if has_arabic(cell_text) else cell_text
                context['tbl_contents'][i]['sets'].append(processed_text)
            else:
                context['tbl_contents'][i]['sets'].append('')
    tpl.render(context)
    tpl.save('result.docx')

补充说明

如果调整后仍有连字符显示异常,可结合arabic-reshaper和python-bidi做预处理,替换上述文本处理逻辑即可:

from arabic_reshaper import reshape
from bidi.algorithm import get_display

processed_text = get_display(reshape(cell_text))

使用该预处理方式时需提前将docx模板中对应段落设置为RTL方向,避免出现二次错位。

内容的提问来源于stack exchange,提问作者Crizalid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 11:45:03