ทำไมข้อความ 'fi` ถูกตัดเมื่อฉันคัดลอกจาก PDF หรือพิมพ์เอกสาร?


15

เมื่อฉันคัดลอกจากไฟล์ Adobe Reader PDF ที่มี

Define an operation

ฉันอยากเห็น

Dene an operation

เมื่อฉันวางข้อความเหตุใดจึงเป็นเช่นนี้

ฉันจะแก้ไขปัญหาที่น่ารำคาญนี้ได้อย่างไร

ฉันเคยเห็นสิ่งนี้เกิดขึ้นในอดีตเมื่อฉันพิมพ์ไฟล์ Microsoft Office Word ไปยังเครื่องพิมพ์ของฉัน

คำตอบ:


13

ดูเหมือนว่าปัญหาตัวอักษร รูปแบบไฟล์ PDF อาจจะใช้ OpenType fi มัดในคำdefineและตัวอักษรในปัจจุบันของการประยุกต์ใช้ปลายทางจะหายไปที่สัญลักษณ์

ฉันไม่รู้ว่ามีวิธีง่าย ๆ ที่จะให้ Acrobat สลายการมัดบนสำเนาหรือไม่

ปัญหาเกี่ยวกับการพิมพ์ของคุณอาจเกี่ยวข้องกับตัวอักษร มีบางอย่างที่อาจทำให้เครื่องพิมพ์สามารถแทนที่แบบอักษรของเอกสารด้วยแบบอักษรในตัวและรุ่นแบบอักษรของเครื่องพิมพ์ก็หายไปด้วย glyph นั้น คุณต้องบอกให้ Windows ดาวน์โหลดแบบอักษรไปยังเครื่องพิมพ์เพื่อแก้ไขปัญหานี้เสมอ

ความเป็นไปได้อีกอย่างเมื่อพิมพ์: UniScribe อาจไม่สามารถเปิดใช้งานได้ MS KB 2642020พูดถึงเรื่องนี้และวิธีแก้ไขปัญหาที่เป็นไปได้บางประการ (กล่าวคือใช้การพิมพ์แบบ RAW แทนการพิมพ์แบบ EMF) แม้ว่าบริบทจะแตกต่างจากปัญหาเฉพาะของคุณเล็กน้อยสาเหตุอาจเหมือนกันและอาจใช้วิธีแก้ไขปัญหาเดียวกัน


1
น่าสนใจเกี่ยวกับหนังสติ๊กฉันสงสัยว่ามันสามารถกำหนดค่าให้ทำงานได้อย่างเหมาะสมหรือไม่ บางทีฉันอาจดูว่าโปรแกรมอ่าน PDF อื่น ๆ ทำงานอย่างไร ฉันจะกำหนดค่าที่แน่นอนเพื่อให้แบบอักษรถูกส่งไปยังเครื่องพิมพ์ได้อย่างไร
Tamara Wijsman

1
จากกล่องโต้ตอบการพิมพ์ของแอป: คลิกProperties(หรือ ( Preferencesขึ้นอยู่กับรุ่นกล่องโต้ตอบ) สำหรับเครื่องพิมพ์ตรวจสอบให้แน่ใจว่าคุณอยู่บนแท็บLayoutหรือQualityคลิกAdvancedปุ่ม ในGraphicกลุ่มเปลี่ยนตัวเลือกในการTrueType Font Download as Softfontสิ่งนี้ครอบคลุมเครื่องพิมพ์ PostScript และเครื่องพิมพ์ส่วนใหญ่ที่ใช้กล่องโต้ตอบในตัว Windows (ฉันคิดว่า) แต่ไดรเวอร์อื่น ๆ อาจมีสิ่งต่าง ๆ ที่เคลื่อนไหวหรือขาดหายไป
afrazier

คุณอาจพบว่า MS KB 2642020 มีประโยชน์บ้าง ฉันได้แก้ไขคำตอบด้วยข้อมูลนั้น
afrazier

ขอบคุณที่อธิบายปัญหา ฉันยังไม่ได้พยายามแก้ปัญหานี้ แต่จะลองอีกครั้งเมื่อพบปัญหาการพิมพ์อีกครั้ง ฉันเดาว่าหนึ่งในวิธีแก้ปัญหาทั้งสองจะช่วยแก้ปัญหานี้โดยเฉพาะ ... :)
Tamara Wijsman

@afrazier วิธีแก้ปัญหาที่คุณเขียนไว้ในความคิดเห็นของคุณเริ่มต้น "จากกล่องโต้ตอบการพิมพ์ของแอพ:" เหมาะสำหรับฉัน ฉันแนะนำให้ใส่ข้อความนั้นลงในคำตอบของคุณ (ฉันสามารถแก้ไขได้ แต่ฉันคิดว่าการตัดสินใจควรขึ้นอยู่กับคุณ)
อลัน

9

คุณสามารถแทนที่คำ "เสีย" เหล่านี้ส่วนใหญ่ด้วยต้นฉบับได้ คุณสามารถแทนที่คำได้อย่างปลอดภัยหาก:

  • ชอบdeneหรือreyไม่ใช่คำจริง
  • เหมือนdefineหรือfireflyมีหนึ่งวิธีที่จะ sequeneces ใหม่เพิ่มมัด ( ff, fi, fl, ffiหรือffl) และให้คำจริง

ปัญหาการมัดส่วนใหญ่จะเข้ากับเกณฑ์เหล่านี้ อย่างไรก็ตามคุณไม่สามารถแทนที่:

  • us เพราะมันเป็นคำที่แท้จริงแม้ว่ามันอาจจะเป็นในตอนแรก fluffs
    • ยังaffirm, butterfly, fielders, fortifies, flimflam, misfits...
  • cusเพราะมันอาจจะกลายเป็นอย่างใดอย่างหนึ่งcuffsหรือficus
    • ยังstiffed/ stifled, rifle/ riffle, flung/ fluffing...

ในนี้ 496 พันคำภาษาอังกฤษพจนานุกรมมี16055คำที่มีอย่างน้อยหนึ่งff, fi, fl, ffiหรือfflซึ่งกลายเป็น15,879คำเมื่อหนังสติ๊กของพวกเขาจะถูกลบออก 173คำที่หายไปเหล่านั้นเช่นชนcuffsและficusและที่ผ่านมา3เพราะพจนานุกรมที่มีคำff, และfifl

790ของเหล่านี้ "มัดเอาออก" คำนี้เป็นคำจริงเหมือนusแต่15089เป็นคำเสีย คำที่แตกหัก14960สามารถแทนที่ได้อย่างปลอดภัยด้วยคำเดิมซึ่งหมายถึง99.1%ของคำที่แตกหักนั้นสามารถแก้ไขได้และ93.2%ของคำเดิมที่มีการมัดรวมกันนั้นสามารถกู้คืนได้หลังจากคัดลอกไฟล์ PDF 6.8%ของคำที่มีลำดับการผูกจะหายไปจากการชน ( cus) และคำย่อย ( us) เว้นแต่คุณเลือกวิธี (บริบท / คำศัพท์เอกสาร?) เพื่อเลือกการแทนที่ที่ดีที่สุดสำหรับแต่ละคำที่ไม่มีการรับประกัน การแทนที่

ด้านล่างเป็นสคริปต์ Python ของฉันที่สร้างสถิติด้านบน คาดว่าไฟล์ข้อความพจนานุกรมที่มีหนึ่งคำต่อบรรทัด ในตอนท้ายมันเขียนไฟล์ CSV ที่จับคู่คำที่ไม่สามารถแก้ไขได้กับคำเดิม

นี่คือลิงค์สำหรับดาวน์โหลด CSV: http://www.filedropper.com/brokenligaturewordfixes รวมการแมปนี้เข้ากับสคริปต์การแทนที่ regex เพื่อแทนที่คำที่เสียหาย

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])

ลิงก์ไปที่.csvเสียหาย มันจะดีถ้าคุณสามารถอัปโหลดอีกครั้ง! ในกรณีใด ๆ ขอขอบคุณสำหรับรหัส
MagTun

@Enora ฉันอัปโหลด CSV อีกครั้งที่ลิงก์เดียวกัน - หวังว่าจะช่วยได้! ฉันยังสังเกตเห็นปัญหาสองสามข้อในรหัส / ผลลัพธ์ (ใช้เครื่องหมายจุดเป็นตัวยึดตำแหน่งในขณะที่พจนานุกรมใหม่มีคำในจุดและไม่ลดขนาดคำก่อนเปรียบเทียบพวกเขา) ฉันเชื่อว่าการทดแทนทั้งหมดนั้นถูกต้อง แต่เอาเกลือเม็ดหนึ่งไปใช้และรู้ว่าจะสามารถทดแทนที่ดีกว่าได้ ฉันขอแนะนำให้ทำการเปลี่ยนอัตโนมัติด้วย regex แต่จากนั้นยืนยันว่าการเปลี่ยนแต่ละอย่างนั้นดีด้วยตาของคุณเอง
Jan Van Bruggen

7

ปัญหาที่นี่คือเช่นเดียวกับบันทึกคำตอบอื่น ๆ ที่มีหนังสติ๊ก อย่างไรก็ตามมันไม่มีอะไรเกี่ยวข้องกับ OpenType ปัญหาพื้นฐานคือ PDF นั้นเป็นรูปแบบการพิมพ์ล่วงหน้าที่เกี่ยวข้องกับเนื้อหาและความหมายเพียงเล็กน้อยเท่านั้น

ข้อความนั้นไม่ได้จัดวางเป็นข้อความ แต่เป็นรูปแบบของสัญลักษณ์ในแบบอักษรที่ตำแหน่งที่แน่นอน ดังนั้นคุณจะได้อะไรเช่น»วางเลขที่ 72 สัญลักษณ์ที่นั่นเลขที่ 101 สัญลักษณ์ที่นั่นเลขที่สัญลักษณ์ 108 ที่นั่น ... « ในระดับที่มีพื้นฐานความคิดของข้อความใด ๆที่ทุกคน มันเป็นเพียงคำอธิบายว่ามันมีลักษณะอย่างไร มีปัญหาสองข้อที่ดึงความหมายออกจากพวงของร่ายมนตร์:

  1. เค้าโครงเชิงพื้นที่ เนื่องจาก PDF มีข้อมูลเฉพาะที่จะวางสัญลักษณ์แต่ละอันแล้วจึงไม่มีข้อความจริงอ้างอิงตามปกติ ผลข้างเคียงก็คือไม่มีที่ว่าง แน่นอนว่าถ้าคุณดูข้อความที่นั่น แต่ไม่ใช่ใน PDF ทำไมปล่อยสัญลักษณ์ว่างเปล่าเมื่อคุณสามารถปล่อยไม่มีเลย? ผลลัพธ์จะเหมือนกันหลังจากทั้งหมด ดังนั้นผู้อ่าน PDF ต้องทำการรวมข้อความอย่างระมัดระวังอีกครั้งโดยแทรกช่องว่างเมื่อใดก็ตามที่พวกเขาพบช่องว่างขนาดใหญ่ระหว่างร่ายมนตร์

  2. PDF แสดงผลร่ายมนตร์ไม่ใช่ข้อความ เวลาส่วนใหญ่ glyph IDs สอดคล้องกับจุดโค้ด Unicode หรือรหัส ASCII อย่างน้อยในแบบอักษรฝังตัวซึ่งหมายความว่าคุณมักจะได้รับข้อความ ASCII หรือละติน 1 กลับมาได้ดีขึ้นอยู่กับว่าใครเป็นผู้สร้าง PDF ในตอนแรก garble ทุกอย่างในกระบวนการ) แต่บ่อยครั้งที่แม้แต่ไฟล์ PDF ที่ช่วยให้คุณสามารถใช้ข้อความ ASCII ได้อย่างดีก็จะทำให้ทุกอย่างที่ไม่ได้เป็นASCII หยุดชะงัก น่ากลัวโดยเฉพาะอย่างยิ่งกับสคริปต์ที่ซับซ้อนเช่นภาษาอาหรับซึ่งมีเพียงเส้นเอ็นและร่ายมนตร์สำรองหลังจากขั้นตอนการจัดวางซึ่งหมายความว่าไฟล์ PDF ภาษาอาหรับแทบจะไม่เคยมีข้อความจริง

ปัญหาที่สองเป็นเหมือนปัญหาที่คุณเผชิญ ผู้ร้ายที่พบบ่อยที่นี่คือ LaTeX ซึ่งใช้จำนวนแบบอักษรที่แตกต่างกันประมาณ 238982375 (แต่ละอันถูก จำกัด ไว้ที่ 256 ร่ายมนตร์) เพื่อให้ได้ผลลัพธ์ แบบอักษรที่แตกต่างกันสำหรับข้อความปกติคณิตศาสตร์ (ใช้มากกว่าหนึ่ง) ฯลฯ ทำให้สิ่งที่ยากมากโดยเฉพาะอย่างยิ่งเมื่อ Metafont ถือกำเนิด Unicode มาเกือบสองทศวรรษและดังนั้นจึงไม่เคยมีการทำแผนที่ Unicode Umlauts ยังแสดงโดย diaeresis ทับลงบนตัวอักษรเช่นคุณได้รับ»¨a«แทน»ä«เมื่อคัดลอกจาก PDF (และแน่นอนไม่สามารถค้นหาได้)

แอปพลิเคชันที่สร้าง PDF สามารถเลือกที่จะรวมข้อความจริงเป็นเมทาดาทา หากไม่เป็นเช่นนั้นคุณจะเหลือความเมตตาว่าจะจัดการแบบอักษรที่ฝังอยู่อย่างไรและผู้อ่าน PDF สามารถแยกส่วนข้อความต้นฉบับอีกครั้งได้หรือไม่ แต่» fi «การคัดลอกเป็นว่างเปล่าหรือไม่เลยมักเป็นสัญญาณของ LaTeX PDF คุณควรทาสีอักขระ Unicode บนก้อนหินและโยนให้ผู้ผลิตหวังว่าพวกเขาจะเปลี่ยนเป็น XeLaTeX และในที่สุดก็มาถึงในปี 1990 ของการเข้ารหัสตัวอักษรและมาตรฐานตัวอักษร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.