Mengapa teks `fi` terpotong saat saya menyalin dari PDF atau mencetak dokumen?

15

Ketika saya menyalin dari file PDF Adobe Reader yang berisi

Define an operation

Saya lebih suka melihat

Dene an operation

ketika saya menempelkan teks, mengapa ini?

Bagaimana saya bisa mengatasi masalah yang mengganggu ini?

Saya juga melihat ini terjadi di masa lalu ketika saya sudah mencetak file Microsoft Office Word ke printer saya.

Tamara Wijsman
sumber

Jawaban:

13

Ini terdengar seperti masalah font. PDF mungkin menggunakan fi ligatur OpenType dalam kata define, dan font saat ini dari aplikasi tujuan hilang mesin terbang itu.

Saya tidak tahu apakah ada cara mudah untuk membuat Acrobat menguraikan ligatur pada salinan.

Masalah Anda dengan pencetakan mungkin juga terkait font. Sesuatu yang memungkinkan printer untuk mengganti font dokumen dengan font bawaannya sendiri dan font versi printer juga tidak memiliki mesin terbang tertentu. Anda harus memberi tahu Windows untuk selalu mengunduh font ke printer untuk mengatasi masalah ini.

Kemungkinan lain saat mencetak: UniScribe mungkin tidak diaktifkan. MS KB 2642020 berbicara tentang ini dan beberapa kemungkinan penyelesaian (yaitu, untuk menggunakan pencetakan tipe RAW daripada pencetakan tipe EMF). Meskipun konteksnya sedikit berbeda dari masalah spesifik Anda, penyebabnya mungkin sama dan solusi yang sama mungkin berlaku.

afrazier
sumber
1
Menarik tentang ligatur, saya bertanya-tanya apakah itu dapat dikonfigurasi untuk berperilaku dengan benar. Mungkin saya bisa melihat bagaimana perilaku pembaca PDF lainnya. Di mana tepatnya cara mengkonfigurasinya agar font dikirim ke printer?
Tamara Wijsman
1
Dari dialog cetak aplikasi: Klik Properties(atau Preferences, tergantung pada versi dialog) untuk printer, pastikan Anda berada di tab Layoutatau Quality, klik Advancedtombol. Di Graphicgrup, ubah TrueType Fontopsi menjadi Download as Softfont. Ini mencakup sebagian besar printer dan printer PostScript menggunakan dialog built-in Windows (saya pikir), tetapi driver lain mungkin memiliki hal-hal yang bergerak, atau hilang hilang.
Afrazier
Anda mungkin menemukan MS KB 2642020 dari beberapa penggunaan. Saya telah mengedit jawaban saya dengan informasi itu.
Afrazier
Terima kasih telah menjelaskan masalahnya. Saya belum mencoba menyelesaikan ini tetapi pasti akan mencoba ketika saya menemukan masalah pencetakan lagi. Saya kira salah satu dari kedua solusi ini pasti akan menyelesaikan masalah yang sangat spesifik ini ... :)
Tamara Wijsman
@afrazier, solusi yang Anda tulis di komentar Anda mulai "Dari dialog cetak aplikasi:" bekerja untuk saya. Saya sarankan memasukkan teks itu ke dalam jawaban Anda. (Saya bisa mengeditnya, tapi saya pikir keputusannya harus Anda lakukan.)
Alan
9

Anda dapat mengganti sebagian besar kata-kata "rusak" ini dengan aslinya. Anda dapat dengan aman mengganti kata jika:

  • suka deneatau rey, itu bukan kata yang nyata
  • seperti defineatau firefly, ada satu cara untuk sequeneces re-add ligatur ( ff, fi, fl, ffi, atau ffl) dan membuat kata nyata

Sebagian besar masalah ligatur memenuhi kriteria ini. Namun, Anda tidak dapat mengganti:

  • us karena itu adalah kata yang nyata, meskipun mungkin awalnya fluffs
    • juga affirm, butterfly, fielders, fortifies, flimflam, misfits...
  • cuskarena bisa menjadi salah satu cuffsatauficus
    • juga stiffed/ stifled, rifle/ riffle, flung/ fluffing...

Dalam 496-ribu-kata kamus bahasa Inggris ini , ada 16.055 kata-kata yang mengandung setidaknya satu ff, fi, fl, ffi, atau ffl, yang berubah menjadi 15.879 kata-kata ketika ligatures mereka dihapus. 173 kata-kata yang hilang bertabrakan seperti cuffsdan ficus, dan terakhir 3 adalah karena kamus yang berisi kata-kata ff, fidan fl.

790 dari kata-kata "ligatur-disingkirkan" ini adalah kata-kata nyata, seperti us, tetapi 15089 adalah kata-kata rusak. 14960 dari kata-kata yang rusak dapat diganti dengan aman dengan kata aslinya, yang berarti 99,1% dari kata-kata yang rusak dapat diperbaiki dan 93,2% dari kata-kata asli yang berisi ligatur dapat dipulihkan setelah menyalin-menempelkan PDF. 6,8% dari kata-kata yang mengandung sekuens ligatur hilang dari tabrakan ( cus) dan sub-kata ( us), kecuali Anda memilih cara (konteks kata / dokumen?) Untuk memilih pengganti terbaik untuk setiap kata yang tidak memiliki jaminan penggantian.

Di bawah ini adalah skrip Python saya yang menghasilkan statistik di atas. Itu mengharapkan file teks kamus dengan satu kata per baris. Pada akhirnya ia menulis file CSV yang memetakan kata-kata rusak yang dapat diperbaiki menjadi kata-kata aslinya.

Berikut tautan untuk mengunduh CSV: http://www.filedropper.com/brokenligaturewordfixes Gabungkan pemetaan ini dengan sesuatu seperti skrip pengganti regex untuk mengganti sebagian besar kata-kata yang rusak.

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])
Jan Van Bruggen
sumber
Tautan ke .csvrusak. Itu akan bagus jika Anda bisa mengunggahnya lagi! Bagaimanapun, terima kasih untuk kodenya.
MagTun
@Enora Saya mengunggah ulang CSV di tautan yang sama - semoga membantu! Saya juga memperhatikan beberapa masalah dalam kode / hasil (menggunakan periode sebagai placeholder sementara kamus baru memiliki periode dalam kata-katanya, dan tidak menurunkan kata-kata sebelum membandingkannya). Saya percaya semua penggantian itu benar, tetapi bawa mereka dengan sebutir garam dan tahu bahwa penggantian yang lebih baik adalah mungkin. Saya sarankan mengotomatiskan penggantian dengan regex tetapi kemudian mengonfirmasi setiap penggantian baik dengan mata Anda sendiri.
Jan Van Bruggen
7

Masalahnya di sini adalah, sebagaimana dicatat oleh jawaban lainnya , dengan ligatur. Namun, tidak ada hubungannya sama sekali dengan OpenType. Masalah mendasarnya adalah bahwa PDF adalah format pra-cetak yang hanya menyangkut sedikit isi dan semantik tetapi sebaliknya diarahkan untuk mewakili halaman yang akan dicetak.

Teks diletakkan bukan sebagai teks tetapi sebagai aliran mesin terbang dari font pada posisi tertentu. Jadi Anda mendapatkan sesuatu seperti »Tempatkan mesin terbang nomor 72 di sana, mesin terbang nomor 101 di sana, mesin terbang nomor 108 di sana, ...«. Pada tingkat itu secara fundamental tidak ada gagasan tentang teks sama sekali . Itu hanya deskripsi bagaimana tampilannya . Ada dua masalah dalam mengekstraksi makna dari sekelompok mesin terbang:

  1. Tata ruang. Karena PDF sudah berisi informasi spesifik di mana menempatkan setiap mesin terbang tidak ada teks aktual yang mendasari itu seperti biasa. Efek samping lain adalah tidak ada ruang. Tentu, jika Anda melihat teks yang ada, tetapi tidak dalam PDF. Mengapa memancarkan mesin terbang kosong ketika Anda hanya bisa memancarkannya? Hasilnya sama saja. Jadi pembaca PDF harus hati-hati menyatukan teks lagi, menyisipkan spasi setiap kali mereka menemukan celah yang lebih besar antara mesin terbang.

  2. PDF membuat mesin terbang, bukan teks. Sebagian besar waktu ID Mesin terbang berkorespondensi dengan titik kode Unicode atau setidaknya kode ASCII dalam font yang disematkan, yang berarti bahwa Anda sering mendapatkan teks ASCII atau Latin 1 dengan cukup baik, tergantung pada siapa yang membuat PDF di tempat pertama (beberapa memutarbalikkan segala sesuatu dalam proses). Tetapi seringkali bahkan PDF yang memungkinkan Anda untuk keluar teks ASCII saja akan memotong-motong segala sesuatu yang bukan ASCII. Terutama mengerikan dengan skrip kompleks seperti Arab yang hanya berisi ligatur dan mesin terbang alternatif setelah tahap tata letak yang berarti bahwa PDF berbahasa Arab hampir tidak pernah mengandung teks yang sebenarnya

Masalah kedua adalah seperti yang Anda hadapi. Penyebab umum di sini adalah LaTeX yang menggunakan perkiraan jumlah font yang berbeda 238982375 (masing-masing dibatasi hingga 256 glyphs) untuk mencapai outputnya. Font yang berbeda untuk teks normal, matematika (menggunakan lebih dari satu), dll. Membuat segalanya sangat sulit, terutama karena Metafont mendahului Unicode selama hampir dua dekade dan dengan demikian tidak pernah ada pemetaan Unicode. Umlaut juga diberikan oleh diaeresis yang ditumpangkan pada surat, misalnya Anda mendapatkan »¨a« bukan »ä« saat menyalin dari PDF (dan tentu saja tidak dapat mencarinya juga).

Aplikasi yang menghasilkan PDF dapat memilih untuk memasukkan teks aktual sebagai metadata. Jika tidak, Anda harus bergantung pada bagaimana font yang disematkan ditangani dan apakah pembaca PDF dapat menyatukan kembali teks aslinya. Tapi »fi« disalin sebagai kosong atau tidak sama sekali biasanya merupakan tanda LaTeX PDF. Anda harus melukis karakter Unicode pada batu dan melemparkannya ke produser, berharap mereka akan beralih ke XeLaTeX dan akhirnya tiba pada 1990-an pengkodean karakter dan standar font.

Joey
sumber