如何创建一个查找和替换文本模式的新环境?

如何创建一个查找和替换文本模式的新环境?

我正在尝试创建一个环境,它可以查找并替换其主体中的某些模式,并且不会与可能包含它的其他环境发生冲突。一种可能的使用场景可能如下所示:

\documentclass{article}
\usepackage{amsmath}
\begin{document}
\begin{gather}
\begin{foo}
a -> b \\ c -> \LaTeX
\end{foo}
\end{gather}
\end{document}

在这里,我的foo环境应该用 替换->\to在我的实际情况下,我有更多模式)。另一种可能的用法,这次没有gather

\documentclass{article}
\begin{document}
\begin{foo}
a -> \textbf{\TeX}
\end{foo}
\end{document}

你会怎么做?(我更喜欢使用\regex_replace_allfrom expl3,但这不是必需的。)

答案1

请参阅答案末尾的多个替换的一般情况

您是否正在寻找类似的东西?在这里,我使用一种listofitems将要替换的文本用作输入的列表分隔符的方法。

\documentclass{article}
\usepackage{listofitems,amsmath}
\setsepchar{->}
\def\reptext{$\to$}
\newcommand\replace[1]{\readlist\pathlist{#1}%
  \foreachitem\z\in\pathlist[]{\ifnum\zcnt=1\else\reptext\fi\z}}
\begin{document}
\replace{a -> b \\ c -> \LaTeX}
\end{document}

在此处输入图片描述

当然,要替换和替换的文本可以作为宏调用的一部分:

\documentclass{article}
\usepackage{listofitems,amsmath}
\newcommand\replace[3]{\setsepchar{#1}%
  \readlist\pathlist{#3}%
  \foreachitem\z\in\pathlist[]{\ifnum\zcnt=1\else#2\fi\z}}
\begin{document}
\replace{->}{$\to$}{a -> b \\ c -> \LaTeX}
\end{document}

...或者环境调用:

\documentclass{article}
\usepackage{listofitems,amsmath,environ}
\NewEnviron{replace}[2]{\setsepchar{#1}%
  \readlist\pathlist{\BODY}%
  \foreachitem\z\in\pathlist[]{\ifnum\zcnt=1\else#2\fi\z}}
\begin{document}
\begin{replace}{->}{$\to$}
  a -> b \\ c -> \LaTeX
\end{replace}
\end{document}

具有多个替换的一般情况

\documentclass{article}
\usepackage{listofitems,amsmath,environ}
\newcommand\defxx[2]{\expandafter\expandafter\expandafter\def
  \expandafter\expandafter\expandafter#1%
  \expandafter\expandafter\expandafter{#2}}
\newtoks\septoks
\NewEnviron{replace}[2]{%
  \setsepchar{,}%
  \readlist*\pretext{#1}%
  \readlist*\posttext{#2}%
  \septoks{}%
  \foreachitem\z\in\pretext[]{%
    \ifnum\zcnt=1\else\global\septoks\expandafter{\the\septoks||}\fi%
    \global\septoks\expandafter\expandafter\expandafter{%
      \expandafter\the\expandafter\septoks\z}%
  }%
  \expandafter\setsepchar\expandafter{\the\septoks}%
  \readlist\pathlist{\BODY}%
  \foreachitem\z\in\pathlist[]{\ifnum\zcnt=1\else
    \foreachitem\zz\in\pretext[]{%
      \defxx\zzz{\pretext[\zzcnt]}%
      \defxx\zzzz{\pathlistsep[\zcnt-1]}%
      \ifx\zzz\zzzz\posttext[\zzcnt]\fi
    }\fi\z%
  }%
}
\begin{document}
\begin{replace}{          <-,   ->,               Z}
               {$\leftarrow$,$\to$,\textbf{Hi Mom!}}
  a -> b \\ c <- \LaTeX{} -> Z
\end{replace}
\end{document}

在此处输入图片描述

答案2

尽管 OP 在评论中表示基于 LuaLaTeX 的解决方案对于他们的用例来说“不是一个选择”,但其他人可能仍然会发现了解这样的解决方案是有益的。

解决方案包括(a)一个名为的 Lua 函数,foosub它执行所需的字符串替换 - 请注意,完全可以设置多个字符串替换 - 和(b)一个名为的 LaTeX 环境,foo它执行以下指令:

  • 输入后,将foosub函数分配给 LuaTeX 的process_input_buffer回调,使其像输入流上的预处理器一样运行。这样,例如,<->被替换为\leftrightarrow TeX 开始执行其通常的处理步骤。

  • 退出时,foosubprocess_input_buffer回调中删除。

我所知道的关于此代码适用性的唯一限制(除了在 LuaLaTeX 下编译文档的能力之外)是环境foo必须包含gather环境,而不是相反。

在此处输入图片描述

\documentclass{article}
\usepackage{amsmath,amssymb}
\usepackage{unicode-math} % <-- Important, to avoid interactions 
                          %     with code in 'umsa.fd' file.

\usepackage{luacode} % for "luacode" environment

%% Lua-side code: Lua function to perform the string substitutions
\begin{luacode}
   function foosub ( s )
      s = s:gsub ( "<%->" , "\\leftrightarrow " )
      s = s:gsub ( "%->"  , "\\rightarrow " )
      s = s:gsub ( "<%-"  , "\\leftarrow " )
      return ( s )
   end
\end{luacode}

%% LaTeX-side code: LaTeX environment called "foo"
\newenvironment{foo}%
  {\directlua{luatexbase.add_to_callback ( 
     "process_input_buffer", foosub , "foosub" )}}%
  {\directlua{luatexbase.remove_from_callback ( 
     "process_input_buffer", "foosub" )}}
    
\begin{document}

\begin{foo}
\begin{gather}
  a ->  b \\ 
  c <-  d \\
  e <-> \text{\LaTeX}
\end{gather}
\end{foo}

\end{document}

相关内容