¿PyMuPDF divide la misma línea de texto en más de diez tramos? Esto determina si se debe fusionar.

PyMuPDF divide la misma línea de palabras en más de una docena de tramos. La mayoría de las veces, la fuente, el tamaño de fuente o el estilo han cambiado, no necesariamente la segmentación. Este artículo explica cómo distinguir los cambios de estilo y los límites de los párrafos, y brinda ejemplos de lógica de fusión y una forma de aceptación para evitar dividir una oración durante la traducción.

Cuando utiliza extractDICT() de PyMuPDF para extraer texto PDF, puede encontrar que una oración coherente se corta en siete, ocho o más span en el resultado devuelto. Por lo general, esto no es un error de análisis, sino un fiel reflejo de la estructura subyacente del PDF: el cambio de fuente, los cambios de color o los ajustes de estilo locales pueden interrumpir el flujo del texto al renderizar.

Si esta "división de estilo" se confunde con "segmentación de párrafos", la limpieza, traducción o recuperación posteriores fácilmente causarán errores de segmentación de oraciones. Este artículo explica cómo distinguir los cambios de estilo de los límites de los párrafos, ofrece un ejemplo combinado de lógica de combinación y proporciona un formulario de aceptación para ayudarle a evitar dividir una oración.

Una línea de texto en el PDF se divide en muchos tramos. ¿Deberían fusionarse? Conclusión de una frase

Cuando hay varios span en el mismo line y las coordenadas y son las mismas, la fuente, el tamaño de fuente o el cambio de color se pueden unir de forma segura; el límite del párrafo debe basarse en la estructura de block y line, no en el número de span.

tu situaciónPrácticas recomendadasrazón
Varios tramos dentro de la misma línea tienen las mismas coordenadas ySpan.text de empalme seguroPrincipalmente cambio de fuente o color
Hay una brecha horizontal obvia entre los tramos.Verifique el espaciado de bbox e inserte espacios o tabulaciones si es necesarioPuede ser un carácter de tabulación o un residuo de salto de columna; necesita reglas
La diferencia en las coordenadas y de los tramos dentro de la misma línea supera el 10% del tamaño de fuenteMantener la estructura del tramo original sin fusionarPueden ser fórmulas en línea o subíndices.
El intervalo de una sola palabra y el bbox están desordenadosMarcar como baja calidad, convertir a manual u OCRFalta de una base confiable para clasificar y agrupar
Texto semánticamente continuo entre bloques.Se requiere juicio contextual y no se realiza la fusión automática.Puede ser un fragmento de paginación.

Primero aclare la relación jerárquica entre Bloque, Línea y Tramo

Estructura del diccionario de PyMuPDF

La salida del diccionario de PyMuPDF sigue estrictamente la estructura de flujo de contenido PDF, con la jerarquía de exterior a interior de la siguiente manera:

  • block: Un área de formato separada en la página, como una sección del texto principal, una celda de la tabla o un pie de foto.
  • line: Texto visual de una sola línea dentro de block.
  • span: line contiene una secuencia de caracteres consecutivos con la misma fuente, tamaño, color y estilo.

Para más explicaciones sobre los campos en cada capa, consulte Documentación oficial de PyMuPDF Textpage.

¿Por qué el cambio de estilo genera un nuevo tramo?

Mientras una línea de texto aparezca en negrita, cursiva, cambiando de color o con reversión de fuente (por ejemplo, chino mezclado con inglés y números), se generará un nuevo span. Estos span pertenecen al mismo line, compartiendo la misma línea base y posición vertical.

Qué mirar Límites de párrafos

El signo final del párrafo real es el final de la lista line y el inicio de la nueva block, no el número de span. Confundir ambos conduce a problemas prácticos: por ejemplo, identificar erróneamente "indicaciones importantes" como dos oraciones separadas hace que las memorias de traducción no coincidan con la terminología completa.

Ejemplo de síntesis: Salida correcta y situación de frontera

Salida correcta

Para ilustrar el punto, construimos un escenario compuesto. Supongamos que introduces una línea en el PDF: "Por favor, tenga en cuenta: El sistema se reiniciará en 5 minutos." "Nota: Usa Heiti", el sistema se reiniciará tras "Usar SimSun", "5" usa fuente numérica monoespaciada y "5" se reiniciará tras un minuto. "Volviendo al estilo Song.

Una salida correcta de extractDICT() debe contener cuatro span bajo un objeto line. La bbox de cada span está muy solapada verticalmente, y las coordenadas y de la origin son básicamente consistentes. Solo después de unir estos cuatro segmentos se forma la unidad semántica completa.

Entrada de baja calidad

Un error típico es que el PDF escaneado no tiene OCR, o que el generador de PDF escriba cada carácter chino como un objeto de texto separado. En este punto, extractDICT() puede devolver decenas de span que contengan solo palabras individuales, y puede haber pequeños huecos o solapamientos irregulares entre sus bbox.

Esta situación no puede corregirse simplemente mediante concatenación de cadenas, ya que falta una base fiable de ordenación y agrupación. Un enfoque más seguro es etiquetar la página como "datos estructurados de baja calidad" y pasarla a corrección manual o procesos de OCR dedicados en lugar de fusionarla forzosamente.

Lógica de fusión de span basada en características geométricas

Código de ejemplo

El siguiente ejemplo en Python demuestra cómo simular la estructura de salida de extractDICT() en memoria e implementar una función segura de fusión de peer span. Nota: Este ejemplo construye datos sintéticos únicamente en memoria y no lee archivos PDF reales; solo se utiliza para verificar la lógica del algoritmo de fusión.

Cuando lo uses en la práctica, asegúrate de que la versión de PyMuPDF soporte el método extractDICT (recomendado 1.23.x o superior) y ejecutarlo en tu propio entorno de dependencias bloqueadas.

# 合成示例:演示同行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)}"

Precauciones antes de usarlo

  • El valor 2.0 para y_tolerance se establece solo para ejemplos de síntesis y no es un estándar industrial.
  • En proyectos reales, este valor puede calcularse dinámicamente en función del tamaño medio del documento; Si line está correctamente dividido, normalmente no se requiere verificación adicional de coordenadas y.
  • Los ejemplos de este artículo solo representan demostraciones a nivel de código y no garantizan el rendimiento real de ningún archivo o producto.

📊 Comparación de núcleos

La siguiente tabla compara varios métodos de manejo y si la fusión automática es adecuada, basándose en las reglas de aceptación mencionadas anteriormente.

Situación observadaMétodos de manipulaciónSi las fusiones automáticas son adecuadas
Dentro de la misma línea, las coordenadas y del vano son consistentesEmpalme seguroSí
Hay un espacio horizontal claro entre los tramosDespués de comprobar el espaciado, inserta un tope de espacio o de pestañaTen cuidado, y necesitas reglas
Las fórmulas y los subíndices en línea causan diferencias significativas en las coordenadas yConserva la estructura original del vanoNo
Espacio de palabra única y bbox no ordenadosMarca baja calidad, cambia a manual o OCRNo
Texto semántico continuo a través de bloquesJuzgar según el contextoNo, se requiere asistencia con PLN

Criterios de aceptación y límites de revisión manual

Observa el fenómenoPosibles razonesDecisión de gestionar el asuntoSi la fusión automática es aplicable
Múltiples vanos y coordenadas y dentro de la misma línea son consistentesCambio de fuente/colorSpan.text de empalme seguroSí
Hay un espacio horizontal notable entre los tramos (> anchos de espacio)Marcas restantes de tabla y columnaRevisa el espaciado de los bbox e inserta espacios o registros de pestañaTen cuidado, y necesitas reglas
Diferencia en las coordenadas span y dentro de la misma línea: > Tamaño de fuente: 10%Fórmulas dentro de la línea y subíndicesConservar la estructura original del vano sin fusionarseNo
Espacio de palabra única y bbox no ordenadosPDF escaneado o dañadoMarcado como de baja calidad, cambio a manual o OCRNo
Semántica textual entre bloquesPaginación y segmentaciónLa fusión entre bloques requiere juicio contextualNo, se requiere asistencia con PLN

Esta tabla solo cubre la validación estructural a nivel de demostración del código; los efectos de extremo a extremo requieren integración con modelos de lenguaje o comprobaciones manuales puntuales. La fusión automática no debe aplicarse a documentos sensibles al formato, como contratos legales o historiales médicos, a menos que sea validada por expertos del dominio.

Antes de usarlas, por favor prepara tú mismo el PDF de la prueba de desensibilización, ejecuta page.get_text("dict", sort=True) para exportar JSON y luego verifica cada elemento uno por uno.

Usado para comprobaciones de pre-traducción en documentos

Primero, revisa a fondo el orden de las páginas, la ubicación de la fuente y la integridad del texto, y luego entrega la misma muestra anonimizada al proceso de traducción. Tras la traducción, sigue siendo necesario comprobar si el título, el texto principal y los pies de foto corresponden correctamente; no basta con juzgar solo por si el texto es fluido.

OmniDoc (Entrada de producto) ofrece portales de traducción de documentos multiformato, y su página web oficial introduce OCR, glosarios y funciones de referencia bilingües. Para los equipos que quieren empezar directamente desde los archivos, este es un camino que merece la pena evaluar con muestras reales. Por favor, utiliza el archivo anonimizado que has autorizado para subir y verifica los resultados con la lista de comprobación de este artículo. Esto no pretende que OmniDoc utilice la biblioteca de código abierto ni los algoritmos internos de este artículo, ni sustituye las pruebas de rendimiento del producto por ejemplos.

🎯 ¿Qué método te conviene?

Si solo quieres organizar el texto en la misma línea

  • Agrupar por line; cuando las coordenadas y coincidan, concatenar span.text de forma segura.

Si te encuentras con fórmulas o subíndices en línea

  • Conservar la estructura original span y no fusionar.

Si trabajas con escaneos o PDFs con muchos tramos simples,

  • Inicialmente marcado como de baja calidad, luego trasladado a calibración manual o procesos OCR dedicados.

Si quieres traducir entre bloques o páginas

  • Según el juicio contextual, no es recomendable fusionar directamente automáticamente.

❓ Preguntas frecuentes (FAQ)

1. Si una línea de texto se divide en muchos espacios, ¿tiene que estar segmentada?

No necesariamente; la mayoría de las veces se debe a cambios en la fuente, tamaño de fuente o color. Dentro del mismo line, span comparte la misma línea base y posición vertical.

2. ¿Qué deberías buscar al final de un párrafo?

Mira si termina la lista de line y si comienza un nuevo block, en lugar del número de span.

3. ¿Puedes solucionar el problema del espacio de un solo carácter con la concatenación de cadenas?

No lo recomiendo. Estas situaciones carecen de criterios fiables de secuenciación y agrupación; un enfoque más seguro es marcarlas como de baja calidad y trasladarlas a procesos manuales o OCR.

4. ¿Cuánto debería estar configurado y_tolerance durante la fusión?

La versión 2.0 del ejemplo está configurada solo para fines de síntesis y no es un estándar industrial. En proyectos reales, puedes calcular dinámicamente basándote en el tamaño medio de la fuente o confiar directamente en el agrupamiento line.

5. ¿Se pueden utilizar fusiones automáticas en contratos legales?

No es adecuado a menos que lo verifiquen expertos en el sector.

📝 Resumen

Para determinar si span puede fusionarse, la clave es primero observar la estructura de line y block, y luego observar sus posiciones geométricas. Al encontrarse con fórmulas, escaneos o semánticas de bloques cruzados, es mejor mantener la forma original o cambiar a semántica manual en lugar de forzarlas a unirlas.

Experiencia ahora: Sube tu documento para empezar a traducir, conservando el formato original

Actualizado 2026-11-15