Доказательство концепции

Доказательство концепции

есть ли пакет, который может автоматически выделять непереносимые слова в выходном PDF? Т.е. слова, которых нет в списке слов для переноса. Например:

введите описание изображения здесь

Я использую пакет polyglossia. Спасибо большое!

решение1

Доказательство концепции

Мы проверили некоторые распространенные пакеты, такие какулем(Дональд Арсено) идуша(Мельхиор Франц), после этого мы переключили наше внимание напоказатьдефисы,lua-check-дефисиlua-визуальная-отладкапакеты, созданные Патриком Гундлахом. К сожалению, OP нуждается в противоположном от того, что предлагают эти пакеты.

Мы начали нашу работу с анализа и извлечения уроков изэтот код из TeX.SX(смотрите такжеhttp://wiki.luatex.org/index.php/Показать_точки_переноса) Патрика Гундлаха. Нас всегда поддерживаютсправочное руководство LuaTeX,где мы заметили определенные типы узлов (см. Главу 8 Узлы, первая страница; страница 169+ в руководстве). Мы можем прочитать об их полях на следующих страницах.

Нам особенно нужны были следующие типы:

  • hlist (0), горизонтальные списки,
  • vlist (1), вертикальные списки,
  • диск (7), место, где можно было бы перенести слово,
  • whasit (8), подходящий тип для создания нового узла,
  • клей (10), пробелы,
  • керн (11), кернинги, и,
  • глиф (37), ключевой тип узла для такого рода работ.

Наша задача состояла в том, чтобы пройти по всем узлам, собрать и сохранить их идентификаторы в таблице Lua, выполнить базовый анализ на уровне текста, а затем выполнить базовую подсветку результатов (в этом примере мы использовали подчеркивание каждого глифа).

Мы передаем минимальное количество букв, которые должны иметь это слово, чтобы быть выделенным. Одно слово состоит из букв, цифр, знаков препинания и т. д. Мы считаем, что этого должно быть достаточно для этого доказательства концепции.

Исходный код для отображения дефисов использует рекурсивный алгоритм для прохода по дереву узлов. Нам потребовалось два прохода, поэтому мы обернули эту функцию ( show_hyph) в другую ( towork). Анализ выполняется в showmeфункции. Мы используем headuserdata, мы могли бы распечатать поля с помощью getmetatableфункции. Она закомментирована в коде, как и распечатка дополнительной информации об узлах.

Анализ текста состоит из нескольких условий, в основном из:

  • ID 0 или ID 10, за которым следует ID 37 (плюс слово не может быть уже с дефисом), это начало слова. Это новая строка или пробел, за которым следует глиф.
  • Идентификатор 7 означает, что может быть диск, и это слово нас не интересует.
  • ID 11 (кернинг) или ID 37 (глиф) является частью слова, мы включаем эту часть для дальнейшего анализа.
  • ID 37, за которым следует ID 10, — это конец слова.

Мы храним всю информацию в таблице Lua. Нам нужны были две переменные о длине слова, для отображения слова мы использовали malsizetrue(глифы+узлы кернинга), для взаимодействия с пользователем мы использовали malsize(только глифы). Сначала было странно думать о словах в таких терминах, но это было необходимо.

Мы использовали head.width( spединицы) для правильного подчеркивания. В примере ниже каждая буква подчеркивается отдельно, можно было бы улучшить, рисуя одну линию на слово. Мы оставляем эту идею открытой для дальнейших экспериментов с кодом. Это потребовало бы сохранения ширины в первом запуске функции и использования ее во втором запуске на уровне Lua.

В следующем примере мы использовали некоторый базовый текст и установили минимальное количество букв в слове от 1 до 8. Мы прилагаем код и предварительный просмотр результата (8 страниц). В этом примере он работает так, как и ожидалось, но я предполагаю, что этот фрагмент требует большего тестирования.

Мы бегаем lualatex mal-hyph.tex.

% lualatex mal-hyph.tex
\documentclass[a4paper]{article}
\pagestyle{empty}
\usepackage{luacode} % the core package in LuaLaTeX, recommended is luatextra
\usepackage[english]{babel} % loading some hyphenation rules
\usepackage{kantlipsum} % loading some text
\usepackage{fontspec} % loading some font

\begin{luacode*}
-- This is the core function for callback...
function towork(head)

-- This inner function is recursive...
function show_hyph(head)
while head do

  -- If we want to see userdata of >head<...
  -- for i,j in pairs(getmetatable(head)) do
  --    print(i,j)
  -- end

  -- If we need to get nodes ID..., this is the way.
  --[=[  io.write(head.id.." ")
    if head.id ==10 then io.write(" ") end
    if head.id == 37 then 
       io.write(unicode.utf8.char(head.char).."; ")
       end    
    --]=] -- be silent

    if head.id == 0 or head.id == 1 then
       show_hyph(head.head) -- the core of recursion
    end -- if, head.id, 0 (hlist) or 1 (vlist)

    counter=counter+1 -- number of nodes
    malglyphs[counter]=head.id -- saving IDs for later analysis

if run then -- We can add nodes after analysis...
  if maldraw[counter]==1 then -- These letters belong to unhyphenateable words.
      local n = node.new("whatsit","pdf_literal") -- Underline them, please,
      n.mode = 0
      if head.width then dista=head.width/65535 else dista=0 end -- with proper  width,
      distb=0
      n.data = "q 1 w 0 0 1 RG "..-dista.." -2 m "..distb.." -2 l S Q" -- with some common line.
      n.next = head.next -- Add line to the node tree.
      n.prev = head
      head.next = n
      head = n
  end -- if we are done with lines.

    if head.id == 7 and run then -- a divis, this is an original example, addition of disc
      local n = node.new("whatsit","pdf_literal")
      n.mode = 0
      n.data = "q 0.9 w 1 .1 .1 RG 0 2 m 0 7 l S Q" -- an original setting was: q 0.3 w 0 2 m 0 7 l S Q
      n.next = head.next
      n.prev = head
      head.next = n
      head = n
    end -- if, head.id==7
end -- if, run

head = head.next -- go to the next node
end -- while, node three

end -- function, show_hyph


-- This function analyses ID of nodes.
function showme()
-- Initialize some variables.
malwrite=0 -- Can I store a unhyphenateable word?
maldraw={} -- Table with 1s for storing information.
malsize=0 -- A size of the last word (only letters, ID 37).
malsizetrue=0 -- A size of the last word (letters+kerning, IDs 11+37).
broken=0 -- Is a word already hyphenated?

for malcounter=1,#malglyphs do -- Let's analyse all nodes.

-- Print some letters from actual position backward.
-- print(malglyphs[malcounter-2], malglyphs[malcounter-1], malglyphs[malcounter]) 

-- Are we at the beginning of the word?
if  (malglyphs[malcounter-1]==0 or malglyphs[malcounter-1]==10) and malglyphs[malcounter]==37 and broken~=1 then malwrite=1; malsize=0; malsizetrue=0 end

-- Are we at the end of the word? Can we modify data in our Lua table?
if malglyphs[malcounter-1]==37 and (malglyphs[malcounter]==10 or malglyphs[malcounter]==12) then 
   if malwrite==1 and malsize>=malmax then -- used to be: malsize>0
   for malback=1,malsizetrue do -- set letters of unhyphenated word for underlining/highlighting, plus kerning
      maldraw[malcounter-malback]=1 -- mark them letter by letter
   end -- for, malback
   end -- if, malwrite
end -- if, malglyphs...

-- Are we in the middle of the hyphenated word?
if malglyphs[malcounter]==7 then broken=1 end -- Yes, we are!
if malglyphs[malcounter]==37 then broken=0 end -- No, at least not at the beginning of the line!

-- Is this a node with letter or kerning in some word?
if malglyphs[malcounter]==37 or malglyphs[malcounter]==11 then 
   malsizetrue=malsizetrue+1 -- letters+kernings
   if malglyphs[malcounter]==37 then malsize=malsize+1 end -- Only letters.
   else 
   malwrite=0 -- Stop analysing actual word, it has no meaning anymore.
   end -- stop searching

end -- for, malcounter

-- If we need some information from the Lua table...
--[[for allchars=1,#malglyphs do
   if maldraw then print(allchars, maldraw[allchars]) end
   end -- for, malheader
   ]]
end -- function, showme


-- This is the first run, we need data about nodes.
malglyphs={}; run=nil; counter=0
show_hyph(head)
showme()

-- This is the second run, we will highlight letters (and also kerning with an invisible pen :-) ).
malglyphs={}; run=1; counter=0
show_hyph(head)
showme()

return true -- Let's finish our work and send data back to a callback.
end -- major function, towork()
\end{luacode*}


% Some TeX commands for general use...
% A minimum of letters required in an unhyphenateable word to be highlighted.
\def\malactivateset#1{
   \luaexec{
   print("malmax "..#1)
   malmax=tonumber(#1) or 0
   }}

% This command activates a callback.
\def\malactivate{
   \directlua{luatexbase.add_to_callback("post_linebreak_filter",towork,"towork")}
   } % End of \activateme...

% This command deactivates a callback.
\def\maldeactivate{
   \directlua{luatexbase.remove_from_callback("post_linebreak_filter","towork")}
   } % End of \deactivateme...

% This text is an example for TeX.SX.
\def\maltext{\newpage
   Minimum of required letters: \the\malletters.\par
   Hello, the World!\par
   Here is some text without meaning.\par 
   \kant[1]\par
   } % End of \maltext...

% Small changes in paper mirror...
\rightskip=7cm
\parindent=0pt


\begin{document}
% A small example...
\malactivate % This command activates the algorithm...
\newcount\malletters 
\malletters=0 % Start with 0+1 letters, a common minimum.
\loop
   \advance\malletters by 1 % Try more letters.
   \malactivateset{\the\malletters} % Pass No. of letters to Lua.
   \maltext \relax % Text to be tested.
\ifnum\malletters<8 \repeat % Show us 8 pages.
\maldeactivate % This command deactivates the algorithm...
\end{document}

пример доказательства концепции

Связанный контент