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 sytuacjaZalecane praktykipowód
Wiele przęseł w obrębie tej samej linii ma te same współrzędne yBezpieczne łączenie.tekstGłównie przełączanie czcionek lub kolorów
Pomiędzy przęsłami widoczna jest wyraźna szczelina poziomaSprawdź odstępy bbox i w razie potrzeby wstaw spacje lub tabulatoryMoż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 czcionkiZachowaj oryginalną strukturę przęsła bez łączeniaMogą to być formuły wbudowane lub indeksy dolne
Rozpiętość pojedynczych słów i bbox są nieuporządkowaneOznacz jako niską jakość, skonwertuj na tryb ręczny lub OCRBrak wiarygodnych podstaw do sortowania i grupowania
Semantycznie ciągły tekst w blokachWymagana 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ątrz block.
  • span: line to 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_tolerance jest 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 line jest 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 sytuacjaMetody obsługiCzy automatyczne fuzje są odpowiednie
W obrębie tej samej linii współrzędne y rozpiętości są spójneBezpieczne łączenieTak
Między przęsłami występuje wyraźna pozioma szczelinaPo sprawdzeniu odstępów wstaw spację lub zatrzymanie tabulatoraBądź ostrożny, a potrzebujesz zasad
Wzory i indeksy wpisowe powodują istotne różnice w współrzędnych yZachowuje oryginalną konstrukcję przęsłaNie
Rozciąg pojedynczych słów i bbox nieuporządkowanyOznacz niską jakość, przełącz na ręczną lub OCRNie
Tekst semantyczny ciągły przez blokiOsądz na podstawie kontekstuNie, potrzebna jest pomoc NLP

Kryteria akceptacji i granice ręcznej oceny

Obserwuj to zjawiskoMożliwe przyczynyDecyzja 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ójnychZamiana czcionki i koloruBezpieczne łączenie.tekstTak
Między przęsłami (> przestrzeni jest zauważalna pozioma szczelina)Pozostałe oznaczenia tablicowe i kolumnoweSprawdź odstępy między bboxami oraz wstawki lub tabulatoryBą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 dolnychZachowaj oryginalną konstrukcję przęsła bez łączeniaNie
Rozciąg pojedynczych słów i bbox nieuporządkowanyZeskanowany lub uszkodzony PDFOznaczone jako niskiej jakości, przejście na ręczne lub OCRNie
Semantyka tekstu między blokamiPaginacja i segmentacjaŁączenie bloków krzyżowych wymaga oceny kontekstowejNie, 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 łącz span.text.

Jeśli napotkasz formuły lub indeksy w linii

  • Zachowuj oryginalną strukturę span i 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

Zaktualizowano 2026-11-15