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çãoPráticas recomendadasrazão
Vários vãos dentro da mesma linha têm as mesmas coordenadas yEmenda segura span.textPrincipalmente mudança de fonte ou cor
Existe uma lacuna horizontal óbvia entre os vãosVerifique o espaçamento das bboxes e insira espaços ou tabulações, se necessárioPode 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 fonteMantenha a estrutura original do vão sem mesclarPodem ser fórmulas embutidas ou subscritos
Spam de palavra única e bbox não estão ordenadosMarcar como de baixa qualidade, converter para manual ou OCRFalta de base confiável para classificação e agrupamento
Texto semanticamente contínuo entre blocosO 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 de block.
  • 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 line tiver 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 observadaMétodo de processamentoÉ adequado para fusão automática?
As coordenadas y dos vãos dentro da mesma linha são consistentesEmenda segurasim
Existe uma lacuna horizontal óbvia entre os vãosInsira espaços ou tabulações após verificar o espaçamentoSeja cauteloso e precise de regras
Fórmulas embutidas, sobrescritos e subscritos levam a grandes diferenças nas coordenadas yMantenha a estrutura original do vãonão
Spam de palavra única e bbox não estão ordenadosSinalizar baixa qualidade, converter para manual ou OCRnão
Texto semanticamente contínuo entre blocosJulgamento baseado no contextoNão, é necessária assistência de PNL

Critérios de aceitação e limites de revisão manual

Observe fenômenosPossíveis razõesdecisão de processamentoSe deve aplicar a mesclagem automática
Vários vãos dentro da mesma linha têm as mesmas coordenadas yTroca de fonte/corEmenda segura span.textsim
Há uma lacuna horizontal óbvia entre os vãos (> largura do espaço)Caracteres de tabulação e resíduos de colunaVerifique o espaçamento bbox, insira espaços ou tabulaçõesSeja cauteloso e precise de regras
Diferença nas coordenadas span y dentro da mesma linha> tamanho da fonte 10%Fórmulas embutidas, sobrescritos e subscritosMantenha a estrutura original do vão sem mesclarnão
Spam de palavra única e bbox não estão ordenadosPDF digitalizado ou danificadoMarcar como de baixa qualidade, converter para manual ou OCRnão
Continuidade semântica de texto entre blocosQuebra de páginaA fusão entre blocos requer julgamento contextualNã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 line e unir span.text com segurança quando as coordenadas y forem consistentes.

Se você encontrar fórmulas embutidas ou sobrescritos

  • Mantenha a estrutura span original 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

Atualizado em 2026-11-15