записать содержимое hbox во вспомогательный файл

записать содержимое hbox во вспомогательный файл

Я знаю, что TeX не может записать содержимое hbox во вспомогательный файл (Повторный анализ содержимого регистра ящика).

Это значит, что

\newwrite\foo
\immediate\openout\foo=\jobname.txt
\setbox0=\hbox{bar}
\immediate\write\foo{\box0}

не могу писать Однако, может ли LuaTeX сделать это? Я нашел

\directlua{
 n = tex.getbox(0)
}

Но я не понимаю, что nэто такое и могу ли я использовать это для записи содержимого коробки в файл.

решение1

Редактировать: вот новый код, который работает для лигатур:

\documentclass{article}
\usepackage{fontspec}
\begin{document}
\setbox0=\hbox{Příliš žluťoučký \textit{kůň} úpěl \hbox{ďábelské} ódy, diffierence, difference}
\directlua{
    % local fontstyles = require "l4fontstyles"
  local char = unicode.utf8.char
  local glyph_id = node.id("glyph")
  local glue_id  = node.id("glue")
  local hlist_id = node.id("hlist")
  local vlist_id = node.id("vlist")
  local disc_id  = node.id("disc")
  local minglue  = tex.sp("0.2em")
  local usedcharacters = {}
  local identifiers = fonts.hashes.identifiers
  local function get_unicode(xchar,font_id)
    local current = {}
    local uchar = identifiers[font_id].characters[xchar].tounicode
    for i= 1, string.len(uchar), 4 do
      local cchar = string.sub(uchar, i, i + 3)
      print(xchar,uchar,cchar, font_id, i)
      table.insert(current,char(tonumber(cchar,16)))
    end
    return current
  end
  local function nodeText(n)
    local t =  {}
    for x in node.traverse(n) do
      % glyph node
      if x.id == glyph_id then
        % local currentchar = fonts.hashes.identifiers[x.font].characters[x.char].tounicode
        local chars = get_unicode(x.char,x.font)
        for _, current_char in ipairs(chars) do
          table.insert(t,current_char)
        end
      % glue node
      elseif x.id == glue_id and  node.getglue(x) > minglue then
        table.insert(t," ")
      % discretionaries
      elseif x.id == disc_id then
        table.insert(t, nodeText(x.replace))
      % recursivelly process hlist and vlist nodes
      elseif x.id == hlist_id or x.id == vlist_id then
        table.insert(t,nodeText(x.head))
      end
    end
    return table.concat(t)
  end
  local n = tex.getbox(0)
  print(nodeText(n.head))
  local f = io.open("hello.txt","w")
  f:write(nodeText(n.head))
  f:close()
}

\box0
\end{document}

Результат в hello.txt:

Příliš žluťoučký kůň úpěl ďábelské ódy, diffierence, difference

Оригинальный ответ:

Переменная nв вашем примере — это список узлов. Существуют различные типы узлов, например, glyphsдля символов, glueдля интервалов или hlistкакой тип вы получаете для своего \hbox. hlistсодержит дочерние узлы, которые доступны в n.headатрибуте. Затем вы можете зациклить этот дочерний список для глифов и клеев.

Каждый тип узла различим по значению n.idатрибута. Конкретные типы узлов и возможные атрибуты описаны в главе "8 Узлов". В этом конкретном примере нам нужно обработать только узлы glyphи glue, но вы должны помнить, что списки узлов являются рекурсивными и различные узлы могут содержать дочерние списки, например hlist, vlist, и т. д. Вы можете поддержать их с помощью рекурсивного вызова атрибута nodeTextтекущего узла head.

Что касается узлов глифов, charатрибут содержит значение Unicode только в том случае, если вы используете шрифты OpenType или TrueType. Если вы используете старые 8-битные шрифты, он содержит только 8-битное значение, фактическая кодировка которого зависит от кодировки используемого шрифта, и преобразовать его в Unicode непросто.

\documentclass{article}
\usepackage{fontspec}
\begin{document}
\setbox0=\hbox{Příliš žluťoučký \textit{kůň} úpěl \hbox{ďábelské} ódy}
\directlua{
    local fontstyles = require "l4fontstyles"
  local char = unicode.utf8.char
  local glyph_id = node.id("glyph")
  local glue_id  = node.id("glue")
  local hlist_id = node.id("hlist")
  local vlist_id = node.id("vlist")
  local minglue = tex.sp("0.2em")
  local usedcharacters = {}
  local identifiers = fonts.hashes.identifiers
  local function get_unicode(xchar,font_id)
     return char(tonumber(identifiers[font_id].characters[xchar].tounicode,16))
  end
  local function nodeText(n)
    local t =  {}
    for x in node.traverse(n) do
      % glyph node
      if x.id == glyph_id then
        % local currentchar = fonts.hashes.identifiers[x.font].characters[x.char].tounicode
        table.insert(t,get_unicode(x.char,x.font))
                local y = fontstyles.get_fontinfo(x.font)
                print(x.char,y.name,y.weight,y.style) 
      % glue node
      elseif x.id == glue_id and  node.getglue(x) > minglue then

        table.insert(t," ")
            elseif x.id == hlist_id or x.id == vlist_id then
                table.insert(t,nodeText(x.head))
      end
    end
    return table.concat(t)
  end
  local n = tex.getbox(0)
  print(nodeText(n.head))
  local f = io.open("hello.txt","w")
  f:write(nodeText(n.head))
  f:close()
}

\box0
\end{document}

nodeTextФункция возвращает текст, содержащийся в списке узлов. Она используется для печати \hboxсодержимого на терминале и для записи в файл hello.txtв этом примере.

Для получения базовой информации о стиле шрифта вы можете попробовать использоватьl4fontstylesмодуль, например такой:

local fontstyles = require "l4fontstyles"
...
if x.id == glyph_id then                                                        
        table.insert(t,char(x.char))
        local y = fontstyles.get_fontinfo(x.font)
        print(y.name,y.weight,y.style)

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