14

Когда я копирую из Adobe Reader файл PDF, который содержит

Define an operation

Я скорее вижу

Dene an operation

когда я вставляю текст, почему это?

Как я могу исправить эту досадную проблему?

Я также видел это в прошлом, когда я печатал файл Microsoft Office Word на своем принтере.

3 ответа3

13

Это звучит как проблема со шрифтом. PDF, вероятно , используя fi OpenType лигатуры в слове define и текущий шрифт приложения назначения отсутствует , что глиф.

Я не знаю, есть ли простой способ заставить Acrobat разложить лигатуру на копии.

Ваши проблемы с печатью, вероятно, также связаны со шрифтами. Возможно, что-то позволяет принтеру заменять шрифт документа собственными встроенными шрифтами, и в версии шрифта принтера также отсутствует этот конкретный глиф. Чтобы обойти эту проблему, вы должны указать Windows всегда загружать шрифты на принтер.

Другая возможность при печати: UniScribe может быть не включен. MS KB 2642020 рассказывает об этом и о некоторых возможных обходных путях (а именно, использовать печать типа RAW, а не печать EMF). Хотя контекст немного отличается от вашей конкретной проблемы, причина может быть той же, и могут применяться те же обходные пути.

9

Вы можете заменить большинство этих "сломанных" слов оригиналами. Вы можете смело заменить слово, если:

  • как dene или rey , это не настоящее слово
  • например, define или firefly , есть один способ повторно добавить лигатурные последовательности (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 , которые превращаются в 15879 слов, когда их лигатуры удалены. 173 из этих пропущенных слов сошлись, как cuffs и ficus , а последние 3 - потому что в этом словаре есть слова ff , fi и fl .

790 из этих «удаленных лигатур» слов - настоящие слова, как и us , но 15089 - сломанные слова. 14960 сломанных слов можно безопасно заменить исходным словом, что означает, что 99,1% сломанных слов можно исправить, а 93,2% исходных слов, содержащих лигатуру, можно восстановить после вставки копии в PDF. 6,8% слов, содержащих лигатурные последовательности, теряются для столкновений (cus) и подслов (us), если вы не выберете какой-либо путь (контекст слова / документа?) выбрать лучшую замену для каждого слова, которое не имеет гарантированной замены.

Ниже приведен мой скрипт на Python, который генерирует приведенную выше статистику. Он ожидает текстовый файл словаря с одним словом в строке. В конце он записывает CSV-файл, который сопоставляет исправляемые неработающие слова с их исходными словами.

Вот ссылка для загрузки CSV:http://www.filedropper.com/brokenligaturewordfixes. Объедините это сопоставление с чем-то вроде сценария замены регулярных выражений, чтобы заменить большинство пропущенных слов.

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

Проблема здесь, как отмечает другой ответ , с лигатурами. Однако это не имеет ничего общего с OpenType. Основная проблема заключается в том, что PDF-файлы представляют собой формат перед печатью, который мало заботится о содержании и семантике, но вместо этого ориентирован на точное представление страницы в том виде, в каком она будет напечатана.

Текст выкладывается не как текст, а как наборы глифов из шрифта в определенных позициях. Таким образом, вы получите что-то вроде «Поместите глиф № 72 там, глиф № 101 там, глиф № 108 там, ...«. На этом уровне не существует принципиально никакого понятия текста вообще. Это просто описание того, как это выглядит. Есть две проблемы извлечения значения из набора символов:

  1. Пространственная планировка. Поскольку PDF уже содержит конкретную информацию о том, где разместить каждый глиф, фактического текста, лежащего в его основе, нет, как обычно. Еще одним побочным эффектом является отсутствие пробелов. Конечно, если вы посмотрите на текст, есть, но не в PDF. Зачем испускать пустой глиф, если вы можете просто ничего не испускать? Результат такой же, в конце концов. Таким образом, читатели PDF должны аккуратно собрать воедино текст, вставляя пробел всякий раз, когда они сталкиваются с большим разрывом между глифами.

  2. PDF отображает глифы, а не текст. Большую часть времени идентификаторы глифов соответствуют кодовым точкам Unicode или, по крайней мере, кодам ASCII во встроенных шрифтах, что означает, что вы часто можете достаточно хорошо вернуть текст ASCII или Latin 1, в зависимости от того, кто создал PDF в первую очередь (некоторые искажать все в процессе). Но часто даже PDF-файлы, которые позволяют вам получать текст ASCII просто, будут искажать все, что не является ASCII. Особенно ужасно со сложными скриптами, такими как арабский, которые содержат только лигатуры и альтернативные глифы после стадии макета, что означает, что арабские PDF-файлы почти никогда не содержат фактического текста

Вторая проблема, как та, с которой вы сталкиваетесь. Распространенным виновником здесь является LaTeX, который использует приблизительное число 238982375 различных шрифтов (каждый из которых ограничен 256 глифами) для достижения своего результата. Различные шрифты для обычного текста, математики (использует более одного) и т.д. Усложняют ситуацию, особенно потому, что Metafont предшествовал Unicode почти на два десятилетия и, следовательно, никогда не было сопоставления Unicode. Умлауты также отображаются диарезом, наложенным на букву, например, вы получаете »«a« вместо »ä« при копировании из PDF-файла (и, конечно, также не можете его искать).

Приложения, создающие PDF-файлы, могут включать фактический текст в качестве метаданных. Если этого не произойдет, вы останетесь в зависимости от того, как обрабатываются встроенные шрифты, и сможет ли программа чтения PDF снова собрать воедино исходный текст. Но »fi« копирование как пустое или не копирование обычно является признаком LaTeX PDF. Вы должны рисовать символы Unicode на камнях и бросать их производителю, надеясь, что они переключатся на XeLaTeX и, таким образом, наконец, появятся в 1990-х годах в кодировках символов и стандартах шрифтов.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .