Warum wird der Text "fi" abgeschnitten, wenn ich aus einem PDF kopiere oder ein Dokument drucke?


15

Wenn ich aus einer Adobe Reader PDF-Datei kopiere, die Folgendes enthält

Define an operation

Ich sehe eher

Dene an operation

Wenn ich den Text einfüge, warum ist das so?

Wie kann ich dieses ärgerliche Problem beheben?

Ich habe dies auch in der Vergangenheit gesehen, als ich eine Microsoft Office Word-Datei auf meinem Drucker gedruckt habe.

Antworten:


13

Dies klingt nach einem Schriftartenproblem. In der PDF-Datei wird wahrscheinlich die OpenType- fi Ligatur im Wort verwendet define, und in der aktuellen Schriftart der Zielanwendung fehlt diese Glyphe.

Ich weiß nicht, ob es eine einfache Möglichkeit gibt, Acrobat dazu zu bringen, die Ligatur beim Kopieren zu zerlegen.

Ihre Probleme beim Drucken hängen wahrscheinlich auch mit den Schriftarten zusammen. Es ist wahrscheinlich möglich, dass der Drucker die Schriftart des Dokuments durch seine eigenen integrierten Schriftarten ersetzt, und der Druckerversion der Schriftart fehlt auch diese bestimmte Glyphe. Sie müssen Windows anweisen, immer Schriftarten auf den Drucker herunterzuladen, um dieses Problem zu umgehen.

Eine weitere Möglichkeit beim Drucken: UniScribe ist möglicherweise nicht aktiviert. In MS KB 2642020 werden dies und einige mögliche Problemumgehungen erläutert (z. B. RAW-Druck anstelle von EMF-Druck). Obwohl der Kontext geringfügig von Ihrem spezifischen Problem abweicht, ist die Ursache möglicherweise dieselbe und es gelten möglicherweise dieselben Problemumgehungen.


1
Interessant an den Ligaturen, ich frage mich, ob es irgendwie so konfiguriert werden kann, dass es sich richtig verhält. Vielleicht könnte ich schauen, wie sich andere PDF-Reader verhalten. Wo genau konfiguriere ich es, damit die Schriftarten an den Drucker gesendet werden?
Tamara Wijsman

1
Im Druckdialog einer App: Klicken Sie auf Properties(oder Preferences, abhängig von der Dialogversion) für den Drucker, stellen Sie sicher, dass Sie sich auf den Registerkarten Layoutoder befinden Quality, und klicken Sie auf die AdvancedSchaltfläche. GraphicÄndern Sie in der Gruppe die TrueType FontOption in Download as Softfont. Dies gilt für die meisten PostScript-Drucker und -Drucker, die integrierte Windows-Dialogfelder verwenden (glaube ich), aber bei anderen Treibern sind möglicherweise Probleme aufgetreten oder sie fehlen.
afrazier

Möglicherweise finden Sie MS KB 2642020 von einiger Verwendung. Ich habe meine Antwort mit diesen Informationen bearbeitet.
afrazier

Vielen Dank für die Beschreibung des Problems. Ich habe noch nicht versucht, das Problem zu lösen, werde es aber versuchen, wenn ich erneut auf ein Druckproblem stoße. Ich denke, eine der beiden Lösungen würde dieses sehr spezifische Problem sicher lösen ... :)
Tamara Wijsman

@afrazier, die Lösung, die Sie in Ihrem Kommentar geschrieben haben, der mit "Aus dem Druckdialog einer App:" beginnt, hat bei mir funktioniert. Ich schlage vor, diesen Text in Ihre Antwort aufzunehmen. (Ich könnte es bearbeiten, aber ich denke, die Entscheidung sollte bei Ihnen liegen.)
Alan

9

Sie können die meisten dieser "kaputten" Wörter durch die Originale ersetzen. Sie können ein Wort sicher ersetzen, wenn:

  • wie deneoder rey, es ist kein richtiges Wort
  • wie defineoder fireflygibt es eine Möglichkeit , zu re-add Ligatur sequeneces ( ff, fi, fl, ffi, oder ffl) und ein echtes Wort machen

Die meisten Ligaturprobleme erfüllen diese Kriterien. Sie können jedoch nicht ersetzen:

  • us denn es ist ein echtes Wort, obwohl es ursprünglich gewesen sein könnte fluffs
    • auch affirm, butterfly, fielders, fortifies, flimflam, misfits...
  • cusweil es entweder cuffsoder werden könnteficus
    • auch stiffed/ stifled, rifle/ riffle, flung/ fluffing...

In diesem 496-tausend-Wort Englisch - Wörterbuch gibt es 16.055 Worte , die mindestens eine enthalten ff, fi, fl, ffi, oder ffl, die in drehen 15.879 Worte , wenn ihre Ligaturen entfernt werden. 173 dieser fehlenden Wörter kollidierte wie cuffsund ficus, und die letzten drei sind , weil das Wörterbuch enthält die Wörter ff, fiund fl.

790 dieser "Ligatur-entfernten" Wörter sind echte Wörter us, aber 15089 sind gebrochene Wörter. 14960 der fehlerhaften Wörter können sicher durch das ursprüngliche Wort ersetzt werden. Dies bedeutet, dass 99,1% der fehlerhaften Wörter reparierbar sind und 93,2% der ursprünglichen Wörter, die eine Ligatur enthalten, nach dem Einfügen einer PDF-Datei wiederhergestellt werden können. 6,8% der Wörter, die Ligatursequenzen enthalten, gehen an die Kollisionen ( cus) und Unterwörter ( us) verloren, es sei denn, Sie wählen einen Weg (Wort- / Dokumentkontext?), Um den besten Ersatz für jedes der Wörter zu wählen, für die keine Garantie besteht Ersatz.

Unten ist mein Python-Skript, das die obigen Statistiken generiert hat. Es erwartet eine Wörterbuch-Textdatei mit einem Wort pro Zeile. Am Ende wird eine CSV-Datei geschrieben, die feststellbare, fehlerhafte Wörter ihren ursprünglichen Wörtern zuordnet.

Hier ist ein Link zum Herunterladen der CSV: http://www.filedropper.com/brokenligaturewordfixes Kombinieren Sie diese Zuordnung mit einem Regex-Ersetzungsskript, um die meisten fehlerhaften Wörter zu ersetzen.

import csv
import itertools
import operator
import re


dictionary_file_path = 'dictionary.txt'
broken_word_fixes_file_path = 'broken_word_fixes.csv'
ligatures = 'ffi', 'ffl', 'ff', 'fi', 'fl'


with open(dictionary_file_path, 'r') as dictionary_file:
    dictionary_words = list(set(line.strip()
                                for line in dictionary_file.readlines()))


broken_word_fixes = {}
ligature_words = set()
ligature_removed_words = set()
broken_words = set()
multi_ligature_words = set()


# Find broken word fixes for words with one ligature sequence
# Example: "dene" --> "define"
words_and_ligatures = list(itertools.product(dictionary_words, ligatures))
for i, (word, ligature) in enumerate(words_and_ligatures):
    if i % 50000 == 0:
        print('1-ligature words {percent:.3g}% complete'
              .format(percent=100 * i / len(words_and_ligatures)))
    for ligature_match in re.finditer(ligature, word):
        if word in ligature_words:
            multi_ligature_words.add(word)
        ligature_words.add(word)
        if word == ligature:
            break
        # Skip words that contain a larger ligature
        if (('ffi' in word and ligature != 'ffi') or
                ('ffl' in word and ligature != 'ffl')):
            break
        # Replace ligatures with dots to avoid creating new ligatures
        # Example: "offline" --> "of.ine" to avoid creating "fi"
        ligature_removed_word = (word[:ligature_match.start()] +
                                 '.' +
                                 word[ligature_match.end():])
        # Skip words that contain another ligature
        if any(ligature in ligature_removed_word for ligature in ligatures):
            continue
        ligature_removed_word = ligature_removed_word.replace('.', '')
        ligature_removed_words.add(ligature_removed_word)
        if ligature_removed_word not in dictionary_words:
            broken_word = ligature_removed_word
            broken_words.add(broken_word)
            if broken_word not in broken_word_fixes:
                broken_word_fixes[broken_word] = word
            else:
                # Ignore broken words with multiple possible fixes
                # Example: "cus" --> "cuffs" or "ficus"
                broken_word_fixes[broken_word] = None


# Find broken word fixes for word with multiple ligature sequences
# Example: "rey" --> "firefly"
multi_ligature_words = sorted(multi_ligature_words)
numbers_of_ligatures_in_word = 2, 3
for number_of_ligatures_in_word in numbers_of_ligatures_in_word:
    ligature_lists = itertools.combinations_with_replacement(
        ligatures, r=number_of_ligatures_in_word
    )
    words_and_ligature_lists = list(itertools.product(
        multi_ligature_words, ligature_lists
    ))
    for i, (word, ligature_list) in enumerate(words_and_ligature_lists):
        if i % 1000 == 0:
            print('{n}-ligature words {percent:.3g}% complete'
                  .format(n=number_of_ligatures_in_word,
                          percent=100 * i / len(words_and_ligature_lists)))
        # Skip words that contain a larger ligature
        if (('ffi' in word and 'ffi' not in ligature_list) or
                ('ffl' in word and 'ffl' not in ligature_list)):
            continue
        ligature_removed_word = word
        for ligature in ligature_list:
            ligature_matches = list(re.finditer(ligature, ligature_removed_word))
            if not ligature_matches:
                break
            ligature_match = ligature_matches[0]
            # Replace ligatures with dots to avoid creating new ligatures
            # Example: "offline" --> "of.ine" to avoid creating "fi"
            ligature_removed_word = (
                ligature_removed_word[:ligature_match.start()] +
                '.' +
                ligature_removed_word[ligature_match.end():]
            )
        else:
            # Skip words that contain another ligature
            if any(ligature in ligature_removed_word for ligature in ligatures):
                continue
            ligature_removed_word = ligature_removed_word.replace('.', '')
            ligature_removed_words.add(ligature_removed_word)
            if ligature_removed_word not in dictionary_words:
                broken_word = ligature_removed_word
                broken_words.add(broken_word)
                if broken_word not in broken_word_fixes:
                    broken_word_fixes[broken_word] = word
                else:
                    # Ignore broken words with multiple possible fixes
                    # Example: "ung" --> "flung" or "fluffing"
                    broken_word_fixes[broken_word] = None


# Remove broken words with multiple possible fixes
for broken_word, fixed_word in broken_word_fixes.copy().items():
    if not fixed_word:
        broken_word_fixes.pop(broken_word)


number_of_ligature_words = len(ligature_words)
number_of_ligature_removed_words = len(ligature_removed_words)
number_of_broken_words = len(broken_words)
number_of_fixable_broken_words = len(
    [word for word in set(broken_word_fixes.keys())
     if word and broken_word_fixes[word]]
)
number_of_recoverable_ligature_words = len(
    [word for word in set(broken_word_fixes.values())
     if word]
)
print(number_of_ligature_words, 'ligature words')
print(number_of_ligature_removed_words, 'ligature-removed words')
print(number_of_broken_words, 'broken words')
print(number_of_fixable_broken_words,
      'fixable broken words ({percent:.3g}% fixable)'
      .format(percent=(
      100 * number_of_fixable_broken_words / number_of_broken_words
  )))
print(number_of_recoverable_ligature_words,
      'recoverable ligature words ({percent:.3g}% recoverable)'
      '(for at least one broken word)'
      .format(percent=(
          100 * number_of_recoverable_ligature_words / number_of_ligature_words
      )))


with open(broken_word_fixes_file_path, 'w+', newline='') as broken_word_fixes_file:
    csv_writer = csv.writer(broken_word_fixes_file)
    sorted_broken_word_fixes = sorted(broken_word_fixes.items(),
                                      key=operator.itemgetter(0))
    for broken_word, fixed_word in sorted_broken_word_fixes:
        csv_writer.writerow([broken_word, fixed_word])

Die Verbindung zum .csvist unterbrochen. Das wäre toll, wenn Sie es erneut hochladen könnten! Auf jeden Fall danke für den Code.
MagTun

@Enora Ich habe die CSV unter demselben Link erneut hochgeladen - hoffe, es hilft! Ich bemerkte auch einige Probleme im Code / in den Ergebnissen (Verwenden von Punkten als Platzhalter, während das neue Wörterbuch Punkte in den Wörtern enthält, und Verringern von Wörtern vor dem Vergleichen). Ich glaube, dass alle Ersetzungen korrekt sind, aber nehmen Sie sie mit einem Körnchen Salz und wissen Sie, dass mehr gute Ersetzungen möglich sind. Ich empfehle, die Ersetzungen mit Regex zu automatisieren, aber dann zu bestätigen, dass jede Ersetzung mit eigenen Augen gut ist.
Jan Van Bruggen

6

Hier geht es, wie die anderen Antwortnotizen zeigen , um Ligaturen. Es hat jedoch überhaupt nichts mit OpenType zu tun. Das grundlegende Problem besteht darin, dass PDFs ein Vordruckformat sind, das sich nur wenig mit Inhalten und Semantik befasst, sondern darauf ausgerichtet ist, eine Seite genau so darzustellen, wie sie gedruckt werden würde.

Text wird nicht als Text, sondern als Zeichenfolge aus einer Schriftart an bestimmten Positionen angelegt. Sie erhalten also so etwas wie »Platziere Glyphe Nummer 72 dort, Glyphe Nummer 101 dort, Glyphe Nummer 108 dort, ...«. Auf dieser Ebene gibt es im Grunde keine Ahnung von Text überhaupt . Es ist nur eine Beschreibung, wie es aussieht . Es gibt zwei Probleme beim Extrahieren der Bedeutung aus einer Reihe von Glyphen:

  1. Die räumliche Anordnung. Da PDF bereits spezifische Informationen enthält, wo die einzelnen Glyphen platziert werden sollen, liegt kein eigentlicher Text darunter, wie es normal wäre. Ein weiterer Nebeneffekt ist, dass keine Leerzeichen vorhanden sind. Klar, wenn du dir den Text dort ansiehst, dann nicht im PDF. Warum eine leere Glyphe ausgeben, wenn Sie gerade keine ausgeben konnten? Das Ergebnis ist schließlich dasselbe. Daher müssen PDF-Leser den Text sorgfältig wieder zusammenfügen und ein Leerzeichen einfügen, wenn sie auf eine größere Lücke zwischen Glyphen stoßen.

  2. PDF rendert Glyphen, nicht Text. In den meisten Fällen entsprechen die Glyphen - IDs Unicode - Codepunkten oder zumindest ASCII - Codes in den eingebetteten Schriftarten. Dies bedeutet, dass Sie häufig ausreichend ASCII - oder Latin 1 - Text zurückerhalten können, je nachdem, wer die PDF - Datei zuerst erstellt hat (einige davon) alles in dem Prozess verfälschen ). Aber oft werden auch PDFs, mit denen Sie ASCII-Text ganz gut rausholen können, alles kaputt machen, was nicht ASCII ist. Besonders schrecklich bei komplexen Skripten wie Arabisch, die nach dem Layout nur Ligaturen und alternative Glyphen enthalten, was bedeutet, dass arabische PDFs fast nie tatsächlichen Text enthalten

Das zweite Problem ist wie das, dem Sie gegenüberstehen. Ein häufiger Schuldiger ist LaTeX, das schätzungsweise 238982375 verschiedene Schriftarten verwendet (von denen jede auf 256 Zeichen beschränkt ist), um die Ausgabe zu erzielen. Unterschiedliche Schriftarten für normalen Text, Mathematik (verwendet mehr als eine) usw. erschweren die Dinge sehr, zumal Metafont fast zwei Jahrzehnte vor Unicode liegt und es daher nie eine Unicode-Zuordnung gab. Umlaute werden auch durch eine einem Buchstaben überlagerte Diärese wiedergegeben, z. B. erhalten Sie beim Kopieren aus einem PDF »¨a« anstelle von »ä« (und können natürlich auch nicht danach suchen).

Anwendungen, die PDFs erstellen, können den eigentlichen Text als Metadaten einfügen. Andernfalls sind Sie dem Umgang mit den eingebetteten Schriftarten und der Frage, ob der PDF-Reader den Originaltext wieder zusammenfügen kann, überlassen. Das Kopieren von »fi« als Leerzeichen oder gar nicht ist in der Regel ein Zeichen für ein LaTeX-PDF. Sie sollten Unicode-Zeichen auf Steine ​​malen und sie auf den Produzenten werfen, in der Hoffnung, dass sie zu XeLaTeX wechseln und damit in den 1990er Jahren endlich Zeichencodierungen und Schriftstandards erhalten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.