使用 Lua 模式补丁匹配和替换换行符

Matching and replacing newline character using Lua pattern patch

这是我在 LaTeX community 中提出的关于如何在 itemize 环境中格式化项目的问题的后续。事实证明,我使用 lua 得到了对那个问题的答复,但现在我想扩展 lua 代码,所以我有一个更 lua 以编程为中心的问题。

答案建议使用 string.gsub 将字符串的模式匹配部分替换为其他内容。例如下面的代码:

s = string.gsub ( s , '\sitem%s+(.+)' , '\item\makefirstuc{%1},' )

\item hello world 替换为 \item\makefirstuc{hello world}

不过问题来了,有时我在项目后的字符串中有新行,例如:

\item hello
world

我想将其替换为:

\item\makefirstuc hello world

有人知道我该怎么做吗?

编辑

我刚刚尝试了 Wiktor 提出的解决方案,但它不适用于该案例:

\item hello
world
\end{itemize}

这里有一个完整的脚本来演示:

-- test.lua
s = "\sitem  Hello\n\end{itemize}"

print(s)

result = string.gsub ( s, '\item%s+(.+)' , function(x) return 
    '\item\makefirstuc{' .. string.gsub(x, '\n', ' ') .. '},' 
end )
print("\nAfter gsub")
print(result)

以上脚本输出

\sitem  Hello
\end{itemize}

After gsub
\sitem  Hello
\end{itemize}

但我希望它输出:

\sitem  Hello
\end{itemize}

After gsub
\item\makefirstuc {Hello},
\end{itemize}

您可以使用函数作为替换参数:

result = string.gsub ( s, '\sitem%s+(.-)(\n\)' , '\item\makefirstuc {%1},%2')

参见online demo

详情:

  • \sitem - \sitem固定字符串
  • %s+ - 一个或多个空格
  • (.-) - 第 1 组 (%1):尽可能少的任何零个或多个字符
  • (\n\) - 第 2 组 (%2):一个换行符和一个 \.

我们不希望 . 模式匹配是贪婪的,因此使用边界模式在下一个反斜杠或字符串末尾停止。这也意味着它可以匹配多个项目,因为匹配中不包含反斜杠。 (参见 Lua Manual § 6.4.1 - Patterns

%f[set], a frontier pattern; such item matches an empty string at any position such that the next character belongs to set and the previous character does not belong to set. The set set is interpreted as previously described. The beginning and the end of the subject are handled as if they were the character '[=15=]'.

s = s:gsub(
    "\sitem%s+(.-)\n?%f[\[=10=]]",
    function(it)
        return "\item\makefirstuc{" .. it:gsub("\n", " ") .. "},\n"
    end
)

输入:

\sitem Hello
World
\sitem Something else
\end{itemize}

输出:

\item\makefirstuc{Hello World},
\item\makefirstuc{Something else},
\end{itemize}

无需复杂的 lua 构造,您可以简单地使用 getitems 包:

\documentclass{article}

\usepackage{getitems}
\usepackage{mfirstuc}

% borrowed from biblatex
\makeatletter
\newcommand{\unspace}{%
  \ifbool{hmode}
    {\ifdimgreater\lastskip\z@
       {\unskip\unspace}
       {\ifnumgreater\lastpenalty\z@
          {\unpenalty\unspace}
          {}}}
    {}}  
\makeatother

\def\doitem#1{\item \makefirstuc{#1}\unspace\ifnum\thecurrentitemnumber=\thenumgathereditems.\else,\fi}%

\let\origitemize\itemize
\let\origenditemize\enditemize

\usepackage{environ}

\RenewEnviron{itemize}{%
  \expandafter\gatheritems\expandafter{\BODY}%
  \gathereditem{0}%
  \origitemize%
   \loopthroughitemswithcommand{\doitem}%
  \origenditemize%
}  

\begin{document}

\begin{itemize}
\item test
\item test
\item test
\end{itemize}

\end{document}