¿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ón | Prácticas recomendadas | razón |
|---|---|---|
| Varios tramos dentro de la misma línea tienen las mismas coordenadas y | Span.text de empalme seguro | Principalmente 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 necesario | Puede 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 fuente | Mantener la estructura del tramo original sin fusionar | Pueden ser fórmulas en línea o subíndices. |
| El intervalo de una sola palabra y el bbox están desordenados | Marcar como baja calidad, convertir a manual u OCR | Falta 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 deblock.span:linecontiene 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_tolerancese 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
lineestá 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 observada | Métodos de manipulación | Si las fusiones automáticas son adecuadas |
|---|---|---|
| Dentro de la misma línea, las coordenadas y del vano son consistentes | Empalme seguro | Sí |
| Hay un espacio horizontal claro entre los tramos | Después de comprobar el espaciado, inserta un tope de espacio o de pestaña | Ten cuidado, y necesitas reglas |
| Las fórmulas y los subíndices en línea causan diferencias significativas en las coordenadas y | Conserva la estructura original del vano | No |
| Espacio de palabra única y bbox no ordenados | Marca baja calidad, cambia a manual o OCR | No |
| Texto semántico continuo a través de bloques | Juzgar según el contexto | No, se requiere asistencia con PLN |
Criterios de aceptación y límites de revisión manual
| Observa el fenómeno | Posibles razones | Decisión de gestionar el asunto | Si la fusión automática es aplicable |
|---|---|---|---|
| Múltiples vanos y coordenadas y dentro de la misma línea son consistentes | Cambio de fuente/color | Span.text de empalme seguro | Sí |
| Hay un espacio horizontal notable entre los tramos (> anchos de espacio) | Marcas restantes de tabla y columna | Revisa el espaciado de los bbox e inserta espacios o registros de pestaña | Ten 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índices | Conservar la estructura original del vano sin fusionarse | No |
| Espacio de palabra única y bbox no ordenados | PDF escaneado o dañado | Marcado como de baja calidad, cambio a manual o OCR | No |
| Semántica textual entre bloques | Paginación y segmentación | La fusión entre bloques requiere juicio contextual | No, 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, concatenarspan.textde forma segura.
Si te encuentras con fórmulas o subíndices en línea
- Conservar la estructura original
spany 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


