Ein Proof of Concept

Ein Proof of Concept

Gibt es ein Paket, das Wörter, die nicht getrennt werden können, im Ausgabe-PDF automatisch hervorheben kann? Also Wörter, die nicht in der Liste der Wörter zur Trennung stehen. Beispiel:

Bildbeschreibung hier eingeben

Ich verwende das Polyglossia-Paket. Vielen Dank!

Antwort1

Ein Proof of Concept

Wir haben einige gängige Pakete überprüft, wie zum Beispielulem(Donald Arseneau) undSeele(Melchior Franz), danach haben wir unsere Aufmerksamkeit auf dieBindestriche anzeigen,Lua-Check-BindestrichUndLua-visuelles DebuggenPakete, die von Patrick Gundlach erstellt wurden. Leider benötigt der OP das Gegenteil von dem, was diese Pakete bieten.

Wir begannen unsere Arbeit mit der Analyse und dem Lernen ausdieser Code von TeX.SX(siehe auchhttp://wiki.luatex.org/index.php/Zeige_die_Bindestriche) von Patrick Gundlach. Wir werden stets unterstützt vonReferenzhandbuch von LuaTeX,wo wir definierte Knotentypen bemerkt haben (siehe Kapitel 8 Knoten, erste Seite; Seite 169+ im Handbuch). Auf den folgenden Seiten können wir mehr über ihre Felder lesen.

Diese Typen haben wir besonders gebraucht:

  • hlist (0), horizontale Listen,
  • vlist (1), vertikale Listen,
  • disc (7), eine Stelle, an der ein Wort getrennt werden konnte,
  • whasit (8), geeigneter Typ für die Erstellung eines neuen Knotens,
  • Kleber (10), Leerzeichen,
  • Kern (11), Unterschneidungen und
  • Glyphe (37), der wichtigste Knotentyp für diese Art von Arbeit.

Unsere Aufgabe bestand darin, alle Knoten durchzugehen, ihre IDs zu erfassen und in einer Lua-Tabelle zu speichern, einige grundlegende Analysen auf Textebene durchzuführen und anschließend die Ergebnisse grundlegend hervorzuheben (in diesem Beispiel haben wir jedes Glyph unterstrichen).

Wir geben eine Mindestanzahl von Buchstaben an, die das Wort enthalten muss, damit es hervorgehoben wird. Ein einzelnes Wort besteht aus Buchstaben, Ziffern, Satzzeichen usw. Wir glauben, dass dies für diesen Proof of Concept ausreichend sein sollte.

Der ursprüngliche Code zum Anzeigen von Bindestrichen verwendet einen rekursiven Algorithmus, um den Knotenbaum zu durchlaufen. Wir brauchten zwei Durchläufe, deshalb haben wir diese Funktion ( show_hyph) in eine andere ( towork) gepackt. Die Analyse wird in der showmeFunktion durchgeführt. Wir verwenden headBenutzerdaten, wir könnten die Felder mit der getmetatableFunktion ausdrucken. Sie ist im Code auskommentiert und druckt zusätzliche Informationen über die Knoten aus.

Die Textanalyse besteht aus mehreren Bedingungen, hauptsächlich aus:

  • ID 0 oder ID 10 gefolgt von ID 37 (und das Wort darf nicht bereits mit Bindestrich geschrieben sein), das ist der Anfang eines Wortes. Es ist eine neue Zeile oder ein Leerzeichen, gefolgt von einem Glyph.
  • ID 7 bedeutet, dass eine Disc vorhanden sein kann und dieses Wort für uns uninteressant ist.
  • ID 11 (Kerning) oder ID 37 (Glyphe) ist ein Teil eines Wortes, wir schließen diesen Teil für die weitere Analyse ein.
  • ID 37 gefolgt von ID 10 ist das Ende eines Wortes.

Wir speichern alle Informationen in einer Lua-Tabelle. Wir brauchten zwei Variablen über die Länge des Wortes, für die Anzeige eines Wortes verwendeten wir malsizetrue(Glyphen+Kerning-Knoten) und für die Interaktion mit einem Benutzer verwendeten wir malsize(nur Glyphen). Es war zunächst seltsam, in diesen Begriffen über Wörter nachzudenken, aber es war notwendig.

Wir haben head.width( spEinheiten) verwendet, um eine korrekte Unterstreichung zu erhalten. Im folgenden Beispiel wird jeder Buchstabe einzeln unterstrichen. Es könnte verbessert werden, eine einzelne Linie pro Wort zu zeichnen. Wir lassen diese Idee für weitere Experimente mit dem Code offen. Dies würde erfordern, Breiten im ersten Durchlauf der Funktion zu speichern und sie im zweiten Durchlauf auf Lua-Ebene zu verwenden.

Im folgenden Beispiel haben wir einen einfachen Text verwendet und eine Mindestanzahl von Buchstaben pro Wort von 1 bis 8 festgelegt. Wir fügen den Code und eine Vorschau des Ergebnisses (8 Seiten) bei. In diesem Beispiel funktioniert es wie erwartet, aber ich vermute, dass dieser Codeausschnitt noch mehr Tests erfordert.

Wir rennen 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}

ein Beispiel für den Proof of Concept

verwandte Informationen