LuaLatex:如何从段落获取 ascii 文本,更改它并再次渲染

LuaLatex:如何从段落获取 ascii 文本,更改它并再次渲染

是否可以渲染段落LuaTeX-> 获取ascii带连字符的文本 -> 放回文本并再次渲染?

  1. 我有简单的文字:“Lorem ipsum dolor sit amet, conse... laborum。”

我需要让此文本以 12 pt 特定字体以 5 cm 宽度呈现。

  1. 渲染文本并获取数组(包含一些数据)数组

    temptext[0]="Lorem ipsum dolor sit a-"
    
    temptext[1]="met, consectetur adipisicing e-"
    
    temptext[2]="lit, sed do eiusmod tempor in-"
    
    ...
    
    temptext[n]="lit anim id est laborum."
    
  2. 我改变了一些参数或字母,例如新的宽度不是5.1cm5.0cm改变一些字母,改变字体等。

  3. 而我的文本有不同的行,例如n=21我改变一些参数并转到 2。


该算法可以用于多个文件。例如,我的段落是\includefile.tex,3. 要点是运行 perl 脚本、ruby、exe 或 bash 脚本并再次运行。我只需要行数、数组表(行中第一个字母是什么等)以及连字符的位置。

波兰语 [Mogę napisać po polsku。我使用 TeX 的简单语法来简化问题,并通过简单的语法规则来验证参数的正确性(np. 5 简化了文本),但 np. 5 仍然有效。 wielkosc fontu,glify,sam font itp。

请注意,除非另有说明,否则不要将文字用于prostokąta。箱子过满(箱子太满),箱子太满,箱子就不会满end space size。她们的眼泪代表了同样的悲伤。 np.我们 wzorach 莫格使用 kilku fontów,które 可能在 siebie,白色 ligaturation 莫格使用 swoje byle wszystko pasowało 到 prostokatu akapitu。您还可以获取适用于手机的其他免费应用。 Tak by napisac program poprawiający tekst na tyle by błąd dopasowania był jak najmniejszy]

其中一些不是波兰语歌词,但它们是英语歌词。喚库延。 ]

答案1

概念证明:

\documentclass{article}
\usepackage{luacode}
\usepackage{libertine}
\begin{document}
\begin{luacode*}
function count_lines (head)
  local linecount = 0
  while head do
    if head.id == 0 then linecount = linecount + 1 end
    head = head.next
  end
  return linecount
end

function mknodes( text )
  local current_font = font.current()
  local font_parameters = font.getfont(current_font).parameters
  local n, head, last
  -- we should insert the paragraph indentation at the beginning
  head = node.new("glue")
  head.spec = node.new("glue_spec")
  head.spec.width = 20 * 2^16
  last = head

  for s in string.utfvalues( text ) do
    local char = unicode.utf8.char(s)
    if unicode.utf8.match(char,"%s") then
      -- its a space
      n = node.new("glue")
      n.spec = node.new("glue_spec")
      n.spec.width   = font_parameters.space
      n.spec.shrink  = font_parameters.space_shrink
      n.spec.stretch = font_parameters.space_stretch
    else -- a glyph
      n = node.new("glyph")
      n.font = current_font
      n.subtype = 1
      n.char = s
      n.lang = tex.language
      n.uchyph = 1
      n.left = tex.lefthyphenmin
      n.right = tex.righthyphenmin
    end

    last.next = n
    last = n
  end

  -- now add the final parts: a penalty and the parfillskip glue
  local penalty = node.new("penalty")
  penalty.penalty = 10000

  local parfillskip = node.new("glue")
  parfillskip.spec = node.new("glue_spec")
  parfillskip.spec.stretch = 2^16
  parfillskip.spec.stretch_order = 2

  last.next = penalty
  penalty.next = parfillskip

  -- just to create the prev pointers for tex.linebreak
  node.slide(head)
  return head
end

local txt = "A wonderful serenity has taken possession of my entire soul, like these sweet mornings of spring which I enjoy with my whole heart. I am alone, and feel the charm of existence in this spot, which was created for the bliss of souls like mine."

tex.baselineskip = node.new("glue_spec")
tex.baselineskip.width = 14 * 2^16

local head = mknodes(txt)
lang.hyphenate(head)
head = node.kerning(head)
head = node.ligaturing(head)

local vbox
local size = 90
lines = 0
lines_goal = 6

while lines < lines_goal do
  texio.write_nl(string.format("Formatting text to %d mm",size))
  local copy_of_head = node.copy_list(head)
  vbox = tex.linebreak(copy_of_head,{ hsize = tex.sp(string.format("%dmm",size))})
  size = size - 10
  lines = count_lines(vbox)
  texio.write_nl(string.format("lines=%d",lines))
end

node.write(vbox)

\end{luacode*}
\end{document}

这会在 Lua 端创建一个段落,并重新排版直到它有 6 行(或更长)。每次迭代时,它都会将 hsize 从 90mm 减少 10mm。

答案2

这是一个小型上下文模块,它将字符和空格写入文本文件。首先,Lua 代码位于一个单独的文件中charsperline.lua。它包含一个简单的回调(或上下文术语中的“节点终结器”),用于浏览构成段落的 hlist 以查找字符和单词间粘合。

thirddata                  = thirddata or { }
thirddata.chars_per_line   = thirddata.chars_per_line or { }

local stringformat         = string.format
local tableconcat          = table.concat
local utfchar              = utf.char

local traverse_nodetype    = node.traverse_id
local traverse_nodelist    = node.traverse

local nodecodes            = nodes.nodecodes
local listcodes            = nodes.listcodes
local skipcodes            = nodes.skipcodes

local hlist_t              = nodecodes.hlist
local vlist_t              = nodecodes.vlist
local glue_t               = nodecodes.glue
local glyph_t              = nodecodes.glyph
local line_t               = listcodes.line
local userskip_t           = skipcodes.userskip

local tasks                = nodes.tasks
local enableaction         = tasks.enableaction
local disableaction        = tasks.disableaction

local linedata             = { }

local resolve_ligatures
resolve_ligatures = function (lst, hd)
  for n in traverse_nodetype (glyph_t, hd) do
    local components = n.components
    if components then
      lst = resolve_ligatures (lst, components)
    else
      lst[#lst+1] = utfchar (n.char)
    end
  end
  return lst
end

local collect = function (hd, groupcode)
  if groupcode == "vbox" then
    return hd
  end

  for current in traverse_nodetype (hlist_t, hd) do

    if current.subtype == line_t then
      local chars, has_glyphs = { }, false

      for n in traverse_nodelist (current.list) do

        local ntype, nsubtype = n.id, n.subtype

        -- we care only for glyphs’n’glue
        if ntype == glyph_t then
          has_glyphs = true
          if n.components then
            chars = resolve_ligatures (chars, n.components)
          else
            chars[#chars+1] = utfchar (n.char)
          end
        elseif ntype == glue_t and nsubtype == userskip_t then
          chars[#chars+1] = " "
        end

      end

      if has_glyphs then
        linedata[#linedata+1] = chars
      end
    end
  end

  return hd
end

thirddata.chars_per_line.collect = collect

tasks.appendaction ("finalizers", "before",
                    "thirddata.chars_per_line.collect")
tasks.disableaction("finalizers",
                    "thirddata.chars_per_line.count_words")

local write_stats = function (...) texiowrite_nl(stringformat(...)) end

local datafile = "./linedata.txt"

write_linedata = function (filename)
  filename = filename or datafile

  local result = { }
  for i = 1, #linedata do local line = linedata[i]
    result[#result+1] = stringformat ("%q,%d",
                                      tableconcat (line),
                                      #line)
  end

  io.savedata (filename, result, "\n")
end

local active --- callback state

commands.start_chars_per_line = function ()
  if not active then
    enableaction("finalizers",
                 "thirddata.chars_per_line.count_words")
    active = true
  end
end

commands.stop_chars_per_line = function ()
  if active then
    disableaction("finalizers",
                  "thirddata.chars_per_line.count_words")
    active = false
  end
end

commands.write_linedata = write_linedata

用户界面在模块中定义t-charsperline.mkvi。除了通常的\start.../环境之外,它还在 TeX 运行结束时\stop...设置对的调用。write_linedata()

\startmodule [charsperline]

\unprotect

\ctxloadluafile{charsperline}

\def\startdumplines{\ctxcommand{start_chars_per_line ()}}

\def\stopdumplines{\endgraf\ctxcommand{stop_chars_per_line ()}}

\prependtoks \charsperline_dump \to \everystoptext

\def\charsperline_dump{\ctxcommand{write_linedata ()}}

\protect

\stopmodule \endinput

现在您可以通过加载模块在常规文档中使用宏\startdumplines/ :\stopdumplines

\usemodule[charsperline]
\setuplayout[width=5cm]

\starttext
  \startdumplines
    \input knuth
  \stopdumplines
\stoptext

输出将写入linedata.txt当前目录中的文件。每行的架构为 CSV 格式"<line content>",<character count>::

"Thus, I came to the conclu-",27
"sion that the designer of a",27
"new system must not only",24
"be the implementer and first",28
"large  scale user; the designer",31
"should also write the first user",32
"manual.",7
"The separation of any of these",30
"four components would have",26

链接到要点。

顺便说一句,您是否获得 ASCII 输出取决于文档包含的字形;如果您想要一个严格的解决方案来删除所有不在 ASCII 范围内的代码点,请告诉我。

相关内容