Ta sama linia tekstu jest podzielona przez PyMuPDF na więcej niż dziesięć części? Od tego zależy, czy należy je połączyć
PyMuPDF dzieli tę samą linię słów na kilkanaście części. W większości przypadków zmienia się czcionka, jej rozmiar lub styl, niekoniecznie dotyczy to segmentacji. W tym artykule wyjaśniono, jak rozróżnić zmiany stylu i granice akapitów oraz podano przykłady łączenia logiki i formularza akceptacji, aby uniknąć dzielenia zdania podczas tłumaczenia.
Kiedy używasz extractDICT() PyMuPDF do wyodrębniania tekstu PDF, może się okazać, że w zwróconym wyniku spójne zdanie zostanie podzielone na siedem, osiem lub więcej span. Zwykle nie jest to błąd analizy, ale prawdziwe odzwierciedlenie podstawowej struktury pliku PDF: przełączanie czcionek, zmiany kolorów lub lokalne dostosowania stylu mogą zakłócać przepływ tekstu podczas renderowania.
Jeśli to „cięcie stylu"zostanie pomylone z „segmentacją akapitów", późniejsze czyszczenie, tłumaczenie lub pobieranie z łatwością spowoduje błędy w segmentacji zdań. W tym artykule wyjaśniono, jak odróżnić zmiany stylu od granic akapitów, przedstawiono połączony przykład logiki łączenia i udostępniono formularz akceptacji, który pomoże uniknąć dzielenia zdania.
Linia tekstu w pliku PDF jest podzielona na wiele części. Czy należy je połączyć? Wniosek w jednym zdaniu
Gdy w tym samymline znajduje się wiele span, a współrzędne y są takie same, to głównie zmiana czcionki, rozmiaru czcionki lub koloru może być bezpiecznie łączona; granica akapitu powinna opierać się na strukturze block i line, a nie liczbie span.
| twoja sytuacja | Zalecane praktyki | powód |
|---|---|---|
| Wiele przęseł w obrębie tej samej linii ma te same współrzędne y | Bezpieczne łączenie.tekst | Głównie przełączanie czcionek lub kolorów |
| Pomiędzy przęsłami widoczna jest wyraźna szczelina pozioma | Sprawdź odstępy bbox i w razie potrzeby wstaw spacje lub tabulatory | Może to być znak tabulacji lub pozostałość po podziale kolumny, potrzebne są reguły |
| Różnica współrzędnych y przęseł w obrębie tej samej linii przekracza 10% wielkości czcionki | Zachowaj oryginalną strukturę przęsła bez łączenia | Mogą to być formuły wbudowane lub indeksy dolne |
| Rozpiętość pojedynczych słów i bbox są nieuporządkowane | Oznacz jako niską jakość, skonwertuj na tryb ręczny lub OCR | Brak wiarygodnych podstaw do sortowania i grupowania |
| Semantycznie ciągły tekst w blokach | Wymagana jest ocena kontekstowa i nie jest wykonywane automatyczne łączenie. | Może to być fragment stronicowania |
Najpierw wyjaśnij hierarchiczną relację pomiędzy blokiem, linią i rozpiętością
Struktura słownika PyMuPDF
Dane wyjściowe słownika PyMuPDF są ściśle zgodne ze strukturą przepływu treści w formacie PDF, a hierarchia od zewnątrz do wewnątrz jest następująca:
block: Niezależny obszar składu na stronie, taki jak akapit tekstu, komórka tabeli lub legenda.line: Wizualna pojedyncza linia tekstu wewnątrzblock.span:lineto wewnętrzna sekwencja kolejnych znaków o tej samej czcionce, rozmiarze, kolorze i stylu.
Więcej opisów pól na każdej warstwie można znaleźć w Oficjalna dokumentacja dla PyMuPDF TextPage.
Dlaczego przełączanie stylów generuje nowy zakres?
Jeśli w środku wiersza tekstu występuje pogrubienie, kursywa, zmiana koloru lub czcionka zastępcza (na przykład chińskie znaki są zmieszane z angielskim i cyframi), zostanie wygenerowany nowy span. Te span należą do tego samego line i mają tę samą linię bazową i pozycję pionową.
Na co zwrócić uwagę przy granicach akapitów
Prawdziwy koniec akapitu jest oznaczony końcem listy line i początkiem nowego block, a nie numerem span. Pomieszanie tych dwóch pojęć może powodować problemy praktyczne: na przykład „Ważna wskazówka"jest błędnie rozpoznawana jako dwa osobne zdania, przez co pamięć tłumaczeniowa nie jest w stanie dopasować całego terminu.
Przykład syntezy: poprawne przypadki wyjściowe i brzegowe
Prawidłowe wyjście
Aby zilustrować problem, konstruujemy syntetyczny scenariusz. Załóżmy, że wejściowy plik PDF zawiera wiersz tekstu: „Uwaga: system uruchomi się ponownie za 5 minut". Wśród nich „Uwaga:"używa pogrubionej czcionki, „system uruchomi się ponownie za 5 minut"powraca do czcionki Song.
Prawidłowe wyjścieextractDICT() powinno zawierać cztery span pod jednym obiektem line. bbox każdego span w dużym stopniu nakładają się na siebie w kierunku pionowym, a współrzędne y origin są w zasadzie spójne. Te cztery fragmenty są łączone ze sobą, tworząc kompletną jednostkę semantyczną.
Dane wejściowe niskiej jakości
Typową sytuacją powodującą błąd jest to, że zeskanowany plik PDF nie został poddany OCR lub generator PDF zapisuje każdy chiński znak jako oddzielny obiekt tekstowy. W tym przypadku extractDICT() może zwrócić dziesiątki jednowyrazowych span, a pomiędzy ich bbox mogą występować małe przerwy lub nieregularne nakładanie się.
Sytuacji tej nie można naprawić po prostu poprzez łączenie ciągów znaków, ponieważ nie ma wiarygodnych podstaw do sortowania i grupowania. Bezpieczniej jest oznaczyć stronę jako „uporządkowane dane niskiej jakości"i wysłać ją do ręcznej korekty lub dedykowanego procesu OCR, niż wymuszać scalanie.
Logika scalania zakresu oparta na cechach geometrycznych
Przykładowy kod
Poniższy przykład w języku Python demonstruje, jak emulować strukturę wyjściowąextractDICT() w pamięci i implementować bezpieczną funkcję scalania zakresu elementów równorzędnych. Uwaga: ten przykład konstruuje dane syntetyczne wyłącznie z pamięci i nie odczytuje żadnych prawdziwych plików PDF. Służy jedynie do sprawdzenia logiki algorytmu łączenia.
Podczas praktycznego stosowania upewnij się, że wersja PyMuPDF obsługuje metodę extractDICT (zalecaną 1.23.x lub nowszą) i uruchom ją w swoim własnym środowisku zależności.
# 合成示例:演示同行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)}"
Środki ostrożności przed użyciem
- Wartość 2.0 dla
y_tolerancejest ustalana tylko dla przykładów syntezy i nie jest standardem branżowym. - W rzeczywistych projektach wartość tę można dynamicznie obliczać na podstawie średniego rozmiaru dokumentu; Jeśli
linejest poprawnie podzielone, zwykle nie jest wymagana dodatkowa weryfikacja współrzędnych y. - Przykłady w tym artykule stanowią jedynie demonstracje na poziomie kodu i nie gwarantują rzeczywistej wydajności żadnych plików ani produktów.
📊 Porównanie rdzeni
Poniższa tabela porównuje kilka metod obsługi oraz to, czy automatyczne łączenie jest odpowiednie, na podstawie wymienionych powyżej zasad akceptacji.
| Zaobserwowana sytuacja | Metody obsługi | Czy automatyczne fuzje są odpowiednie |
|---|---|---|
| W obrębie tej samej linii współrzędne y rozpiętości są spójne | Bezpieczne łączenie | Tak |
| Między przęsłami występuje wyraźna pozioma szczelina | Po sprawdzeniu odstępów wstaw spację lub zatrzymanie tabulatora | Bądź ostrożny, a potrzebujesz zasad |
| Wzory i indeksy wpisowe powodują istotne różnice w współrzędnych y | Zachowuje oryginalną konstrukcję przęsła | Nie |
| Rozciąg pojedynczych słów i bbox nieuporządkowany | Oznacz niską jakość, przełącz na ręczną lub OCR | Nie |
| Tekst semantyczny ciągły przez bloki | Osądz na podstawie kontekstu | Nie, potrzebna jest pomoc NLP |
Kryteria akceptacji i granice ręcznej oceny
| Obserwuj to zjawisko | Możliwe przyczyny | Decyzja o zajęciu się tą sprawą | Czy automatyczne połączenie ma zastosowanie |
|---|---|---|---|
| Wiele przęsień i współrzędnych y w obrębie tej samej linii jest spójnych | Zamiana czcionki i koloru | Bezpieczne łączenie.tekst | Tak |
| Między przęsłami (> przestrzeni jest zauważalna pozioma szczelina) | Pozostałe oznaczenia tablicowe i kolumnowe | Sprawdź odstępy między bboxami oraz wstawki lub tabulatory | Bądź ostrożny, a potrzebujesz zasad |
| Różnica współrzędnych y w obrębie tej samej linii: > Rozmiar czcionki: 10% | Formuły w linii i indeksach dolnych | Zachowaj oryginalną konstrukcję przęsła bez łączenia | Nie |
| Rozciąg pojedynczych słów i bbox nieuporządkowany | Zeskanowany lub uszkodzony PDF | Oznaczone jako niskiej jakości, przejście na ręczne lub OCR | Nie |
| Semantyka tekstu między blokami | Paginacja i segmentacja | Łączenie bloków krzyżowych wymaga oceny kontekstowej | Nie, potrzebna jest pomoc NLP |
Ta tabela obejmuje walidację strukturalną tylko na poziomie demonstracji kodu; efekty end-to-end wymagają integracji z modelami językowymi lub ręcznych kontrol punktowych. Automatyczne łączenie nie powinno być stosowane do dokumentów wrażliwych na format, takich jak umowy prawne czy dokumentacja medyczna, chyba że zostanie zweryfikowane przez ekspertów dziedzinowych.
Przed użyciem prosimy samodzielnie przygotować PDF testu dessensytyzacji, uruchomić page.get_text("dict", sort=True) do eksportu JSON, a następnie zweryfikować każdy element pojedynczo.
Używany do kontroli przed tłumaczeniem dokumentów
Najpierw dokładnie sprawdź kolejność stron, lokalizację źródła i integralność tekstu, a następnie przekaż tę samą zanonimizowaną próbkę procesowi tłumaczeniowemu. Po tłumaczeniu nadal konieczne jest sprawdzenie, czy tytuł, główny tekst i podpisy prawidłowo się zgadzają; nie wystarczy oceniać tylko na podstawie płynności tekstu.
OmniDoc (wpis produktu) oferuje wieloformatowe portale tłumaczeń dokumentów, a jego oficjalna strona internetowa wprowadza OCR, słowniki oraz funkcje dwujęzyczne referencyjne. Dla zespołów, które chcą zacząć bezpośrednio od plików, jest to ścieżka warta oceny na podstawie rzeczywistych próbek. Prosimy o użycie zanonimizowanego pliku, który uznałeś, aby przesłać i zweryfikować wyniki za pomocą listy kontrolnej opisanej w tym artykule. Nie twierdzi to, że OmniDoc korzysta z biblioteki open-source ani wewnętrznych algorytmów z tego artykułu, ani nie zastępuje testów wydajności produktu przykładami.
🎯 Która metoda ci odpowiada?
Jeśli chcesz tylko uporządkować tekst na tej samej linii
- Grupuj według
line; gdy współrzędne y się zgadzają, bezpiecznie łączspan.text.
Jeśli napotkasz formuły lub indeksy w linii
- Zachowuj oryginalną strukturę
spani nie łącz się.
Jeśli pracujesz ze skanami lub PDF-ami z wieloma pojedynczymi rozmachami,
- Początkowo oznaczane jako niskiej jakości, następnie przeniesione do ręcznej kalibracji lub dedykowanych procesów OCR.
Jeśli chcesz tłumaczyć przez bloki lub strony
- Na podstawie oceny kontekstowej nie zaleca się automatycznego łączenia bezpośredniego.
❓ Najczęściej zadawane pytania (FAQ)
1. Jeśli linia tekstu jest podzielona na wiele części, czy musi być podzielona na segmenty?
Niekoniecznie; najczęściej jest spowodowany zmianami czcionki, rozmiaru czcionki lub koloru. W obrębie tego samego line span ma tę samą linię bazową i pozycję pionową.
2. Na co zwracać uwagę na końcu akapitu?
Sprawdź, czy lista line się kończy i czy zaczyna się nowa block, zamiast liczyć liczbę span.
3. Czy można rozwiązać problem rozpięcia pojedynczych znaków przy konkatenacji ciągów znaków?
Nie polecam. Takie sytuacje nie mają wiarygodnych kryteriów sekwencjonowania i grupowania; bezpieczniejszym podejściem jest oznaczenie ich jako niskiej jakości i przeniesienie do procesów ręcznych lub OCR.
4. Ile y_tolerance powinno być ustawione podczas scalania?
2.0 w tym przykładzie jest ustawione wyłącznie do syntezy i nie jest standardem branżowym. W rzeczywistych projektach możesz dynamicznie obliczać na podstawie średniego rozmiaru czcionki lub bezpośrednio zaufać grupowaniu line.
5. Czy automatyczne fuzje mogą być stosowane w umowach prawnych?
Nie nadaje się, chyba że zweryfikowają ją eksperci od dziedziny.
📝 Podsumowanie
Aby ustalić, czy span może się łączyć, kluczowe jest najpierw przyjrzenie się strukturze line i block, a następnie przyjrzeniu się ich pozycjom geometrycznym. W przypadku wzorów, skanów czy semantyki krzyżowych bloków lepiej zachować oryginalną formę lub przejść na semantykę manualną niż ich wymuszać łączeniem.
Doświadczenie teraz: Prześlij dokument, aby zacząć tłumaczyć, zachowując oryginalne formatowanie


