A mesma linha de texto é dividida em mais de dez trechos pelo PyMuPDF? Isso determina se deve ser mesclado
PyMuPDF divide a mesma linha de palavras em mais de uma dúzia de trechos. Na maioria das vezes, a fonte, o tamanho da fonte ou o estilo mudaram, não necessariamente a segmentação. Este artigo explica como distinguir mudanças de estilo e limites de parágrafo e fornece exemplos de lógica de fusão e um formulário de aceitação para evitar o corte de uma frase durante a tradução.
Ao usar extractDICT() do PyMuPDF para extrair texto PDF, você pode descobrir que uma frase coerente é cortada em sete, oito ou mais span no resultado retornado. Geralmente, isso não é um erro de análise, mas um verdadeiro reflexo da estrutura subjacente do PDF: troca de fonte, alterações de cores ou ajustes de estilo local podem interromper o fluxo do texto durante a renderização.
Se esse "corte de estilo" for confundido com "segmentação de parágrafo", a limpeza, tradução ou recuperação subsequente causará facilmente erros de segmentação de frase. Este artigo explica como distinguir alterações de estilo de limites de parágrafo, fornece um exemplo mesclado de lógica de mesclagem e fornece um formulário de aceitação para ajudá-lo a evitar o corte de uma frase.
Uma linha de texto no PDF é dividida em vários trechos. Eles deveriam ser mesclados? Conclusão de uma frase
Quando há vários span no mesmo line e as coordenadas y são iguais, é principalmente fonte, tamanho da fonte ou mudança de cor, que pode ser emendada com segurança; o limite do parágrafo deve ser baseado na estrutura de block e line, não no número de span.
| sua situação | Práticas recomendadas | razão |
|---|---|---|
| Vários vãos dentro da mesma linha têm as mesmas coordenadas y | Emenda segura span.text | Principalmente mudança de fonte ou cor |
| Existe uma lacuna horizontal óbvia entre os vãos | Verifique o espaçamento das bboxes e insira espaços ou tabulações, se necessário | Pode ser caractere de tabulação ou resíduo de quebra de coluna, precisa de regras |
| A diferença nas coordenadas y dos vãos dentro da mesma linha excede 10% do tamanho da fonte | Mantenha a estrutura original do vão sem mesclar | Podem ser fórmulas embutidas ou subscritos |
| Spam de palavra única e bbox não estão ordenados | Marcar como de baixa qualidade, converter para manual ou OCR | Falta de base confiável para classificação e agrupamento |
| Texto semanticamente contínuo entre blocos | O julgamento contextual é necessário e a fusão automática não é realizada. | Pode ser um fragmento de paginação |
Primeiro esclareça a relação hierárquica entre Bloco, Linha e Span
Estrutura do dicionário do PyMuPDF
A saída do dicionário do PyMuPDF segue estritamente a estrutura do fluxo de conteúdo do PDF, e a hierarquia de fora para dentro é a seguinte:
block: uma área de composição tipográfica independente na página, como um parágrafo de texto, uma célula de tabela ou uma legenda.line: única linha visual de texto dentro deblock.span:lineé uma sequência interna de caracteres consecutivos com a mesma fonte, tamanho, cor e estilo.
Para obter mais descrições dos campos em cada camada, consulte Documentação oficial do PyMuPDF TextPage.
Por que a troca de estilo gera um novo intervalo?
Enquanto houver negrito, itálico, mudança de cor ou substituição de fonte no meio de uma linha de texto (por exemplo, caracteres chineses são misturados com inglês e números), um novo span será gerado. Esses spans pertencem ao mesmo line e compartilham a mesma linha de base e posição vertical.
O que observar nos limites dos parágrafos
O verdadeiro final de um parágrafo é marcado pelo final da lista line e pelo início de um novo block, não pelo número de span. Confundir os dois pode causar problemas práticos: por exemplo, "Dica importante" é erroneamente reconhecido como duas frases separadas, fazendo com que a memória de tradução não consiga corresponder ao termo completo.
Exemplo de síntese: saída correta e casos extremos
Saída correta
Para ilustrar o problema, construímos um cenário sintético. Suponha que haja uma linha de texto no PDF de entrada: "Observação: o sistema será reiniciado em 5 minutos." Entre eles, "Observação:" usa fonte em negrito, "o sistema será reiniciado em 5 minutos" retorna para a fonte Song.
A saída extractDICT() correta deve conter quatro span em um objeto line. Os bbox de cada span são altamente sobrepostos na direção vertical e as coordenadas y de origin são basicamente consistentes. Esses quatro fragmentos são unidos para formar uma unidade semântica completa.
Entrada de baixa qualidade
Uma situação de erro típica é que o PDF digitalizado não foi submetido ao OCR ou o gerador de PDF grava cada caractere chinês como um objeto de texto separado. Neste caso, extractDICT() pode retornar dezenas de spans de uma única palavra e pode haver pequenas lacunas ou sobreposições irregulares entre seus bboxs.
Esta situação não pode ser corrigida simplesmente pela concatenação de strings porque não existe uma base confiável para classificação e agrupamento. É mais seguro marcar a página como"dados estruturados de baixa qualidade"e enviá-la para revisão manual ou para um processo de OCR dedicado, em vez de forçar uma mesclagem.
Lógica de mesclagem de extensão baseada em recursos geométricos
Exemplo de código
O exemplo Python a seguir demonstra como emular a estrutura de saída deextractDICT() na memória e implementar uma função segura de mesclagem de intervalo de pares. Nota: Este exemplo constrói dados sintéticos puramente a partir da memória e não lê nenhum arquivo PDF real. É usado apenas para verificar a lógica do algoritmo de fusão.
Para uso real, confirme se a versão PyMuPDF suporta o método extractDICT (recomendado 1.23.x e superior) e execute-o em seu próprio ambiente de dependência bloqueada.
# 合成示例:演示同行span合并逻辑,非真实PDF解析结果
# 依赖: PyMuPDF (pymupdf) >= 1.23.0,仅用于类型参考,本例纯内存构造
def merge_spans_in_line(line_dict, y_tolerance=2.0):
"""合并同一line内y坐标相近的span,保留原始顺序"""
if not line_dict.get("spans"):
return ""
spans = sorted(line_dict["spans"], key=lambda s: s["bbox"][0]) # 按x排序
merged_text = []
current_y = spans[0]["origin"][1]
buffer = [spans[0]["text"]]
for span in spans[1:]:
y = span["origin"][1]
if abs(y - current_y) <= y_tolerance:
buffer.append(span["text"])
else:
merged_text.append("".join(buffer))
buffer = [span["text"]]
current_y = y
merged_text.append("".join(buffer))
return "\n".join(merged_text)
# 构造合成line数据,模拟四种字体混排(正常情况)
synthetic_line = {
"spans": [
{"text": "请注意:", "bbox": (100, 200, 160, 220), "origin": (100, 215)},
{"text": "系统将在", "bbox": (160, 200, 220, 220), "origin": (160, 215)},
{"text": "5", "bbox": (220, 200, 230, 220), "origin": (220, 215)},
{"text": "分钟后重启。", "bbox": (230, 200, 310, 220), "origin": (230, 215)}
]
}
result = merge_spans_in_line(synthetic_line)
assert result == "请注意:系统将在5分钟后重启。", f"合并失败: {result}"
# 边界测试:y坐标差异超过容差,应视为不同行片段(即使在同一line dict中也应分隔)
bad_line = {
"spans": [
{"text": "上行", "bbox": (100, 200, 140, 220), "origin": (100, 215)},
{"text": "下行", "bbox": (100, 230, 140, 250), "origin": (100, 245)}
]
}
bad_result = merge_spans_in_line(bad_line, y_tolerance=2.0)
# y差值30 > 2.0,应被分隔为两行
assert bad_result == "上行\n下行", f"异常行未正确分隔: {repr(bad_result)}"
Precauções antes de usar
- Um valor de 2,0 para
y_toleranceé apenas um exemplo sintético e não é um padrão do setor. - Em projetos reais, este valor pode ser calculado dinamicamente com base no tamanho médio da fonte do documento; se o próprio
linetiver sido dividido corretamente, geralmente não há necessidade de verificação adicional da coordenada y. - Os exemplos neste artigo representam apenas demonstrações em nível de código e não representam uma garantia de todos os arquivos reais ou efeitos do produto.
📊 Comparação principal
A tabela a seguir compara vários métodos de processamento e se eles são adequados para mesclagem automática com base na situação observada, com base nas regras de aceitação acima.
| Situação observada | Método de processamento | É adequado para fusão automática? |
|---|---|---|
| As coordenadas y dos vãos dentro da mesma linha são consistentes | Emenda segura | sim |
| Existe uma lacuna horizontal óbvia entre os vãos | Insira espaços ou tabulações após verificar o espaçamento | Seja cauteloso e precise de regras |
| Fórmulas embutidas, sobrescritos e subscritos levam a grandes diferenças nas coordenadas y | Mantenha a estrutura original do vão | não |
| Spam de palavra única e bbox não estão ordenados | Sinalizar baixa qualidade, converter para manual ou OCR | não |
| Texto semanticamente contínuo entre blocos | Julgamento baseado no contexto | Não, é necessária assistência de PNL |
Critérios de aceitação e limites de revisão manual
| Observe fenômenos | Possíveis razões | decisão de processamento | Se deve aplicar a mesclagem automática |
|---|---|---|---|
| Vários vãos dentro da mesma linha têm as mesmas coordenadas y | Troca de fonte/cor | Emenda segura span.text | sim |
| Há uma lacuna horizontal óbvia entre os vãos (> largura do espaço) | Caracteres de tabulação e resíduos de coluna | Verifique o espaçamento bbox, insira espaços ou tabulações | Seja cauteloso e precise de regras |
| Diferença nas coordenadas span y dentro da mesma linha> tamanho da fonte 10% | Fórmulas embutidas, sobrescritos e subscritos | Mantenha a estrutura original do vão sem mesclar | não |
| Spam de palavra única e bbox não estão ordenados | PDF digitalizado ou danificado | Marcar como de baixa qualidade, converter para manual ou OCR | não |
| Continuidade semântica de texto entre blocos | Quebra de página | A fusão entre blocos requer julgamento contextual | Não, é necessária assistência de PNL |
Esta tabela cobre apenas a verificação estrutural no nível de demonstração do código, e o efeito ponta a ponta precisa ser combinado com modelos de linguagem ou amostragem manual. A mesclagem automática não deve ser usada para documentos sensíveis ao formato, como contratos legais, registros médicos, etc., a menos que seja verificada por um especialista no domínio.
Antes de usar, prepare você mesmo o PDF do teste de dessensibilização, execute page.get_text("dict", sort=True) para exportar JSON e verifique cada item.
Usado para verificação antes da tradução do documento
Primeiro verifique a ordem das páginas, a localização da fonte e a integridade do texto e, em seguida, envie a mesma amostra dessensibilizada para o processo de tradução. Após a tradução, você ainda precisa verificar se o título, o texto e as ilustrações correspondem corretamente, e não apenas se o texto está suave.
OmniDoc (portal de produtos) fornece um portal de tradução de documentos multiformato e o site oficial apresenta funções de OCR, glossário e comparação bilíngue. Para equipes que desejam trabalhar diretamente a partir dos arquivos, vale a pena avaliar esse caminho com exemplos da vida real. Use arquivos dessensibilizados que você tem permissão para carregar e use os itens de verificação neste artigo para revisar os resultados. Não há nenhuma afirmação aqui de que o OmniDoc use as bibliotecas de código aberto ou algoritmos internos neste artigo, nem o exemplo substitui o teste de desempenho do produto.
🎯 Qual método é adequado para você?
Se você deseja apenas organizar o texto na mesma linha
- Agrupar por
linee unirspan.textcom segurança quando as coordenadas y forem consistentes.
Se você encontrar fórmulas embutidas ou sobrescritos
- Mantenha a estrutura
spanoriginal sem mesclar.
Se você estiver lidando com digitalizações ou PDFs com muitos espaços de palavras únicas
- Marque primeiro como de baixa qualidade e depois transfira para revisão manual ou processo de OCR dedicado.
Se você quiser fazer tradução entre blocos ou páginas cruzadas
- Com base no julgamento contextual, não é apropriado mesclar diretamente e automaticamente.
❓ Perguntas frequentes (FAQ)
1. Uma linha de texto é dividida em vários trechos. Tem que ser segmentação?
Não necessariamente, é causado principalmente por alterações na fonte, tamanho da fonte ou cor. span dentro do mesmo line compartilham a mesma linha de base e posição vertical.
2. O que devo ler no final do parágrafo?
Veja se a lista line termina e começa um novo block, e não o número de span.
3. A concatenação de strings pode ser usada para corrigir o problema de extensão de palavra única?
Não recomendado. Tais casos carecem de uma base confiável para classificação e agrupamento, e é mais prudente marcá-los como de baixa qualidade e encaminhá-los para um manual ou processo de OCR.
4. Quanto y_tolerance deve ser definido durante a fusão?
O 2.0 no exemplo é apenas um exemplo sintético e não é um padrão do setor. Os itens reais podem ser calculados dinamicamente com base no tamanho médio da fonte ou confiar diretamente no agrupamento de line.
5. A fusão automática pode ser utilizada em contratos jurídicos?
Não é adequado, a menos que seja verificado por especialistas do domínio.
📝 Resumo
A chave para julgar se span pode ser mesclado é primeiro observar a estrutura de line e block e, em seguida, observar a posição geométrica. Ao encontrar fórmulas, documentos digitalizados ou semântica de blocos cruzados, é melhor mantê-los como estão ou convertê-los manualmente, em vez de uni-los à força.
Experimente agora: carregue o documento para iniciar a tradução, mantendo o layout original


