![控制序列方法](https://linux22.com/image/317534/%E6%8E%A7%E5%88%B6%E5%BA%8F%E5%88%97%E6%96%B9%E6%B3%95.png)
是否可以创建一个宏,使得在编译文件时,由字符“whitespace”、“{”、“L”组成的字符串和由“L”、“}”、“whitespace”组成的字符串之间的所有内容都不会显示?即该行" {L HelloL} World"
应该编译为"World"
。
我故意没有指定任何关于如何编程此宏的限制。对我来说,理想的方式是在我的 LaTeX 文件中有一个变量,我们称之为\switch
,这样当 时\switch=1
,上述字符串之间的所有内容都不会显示,并且\switch=0
它会像往常一样编译 - 但我也会喜欢不那么完美的方式,比如为我的*.tex
文本文件创建一个宏,手动删除这些字符串之间的所有内容。
我的目标是,文本中有几部分位于这些字符串之间,我通常喜欢在文本中包含这些部分。但有时我暂时不想让它们出现在那里。使用自动方式显示或不显示它们将为我节省大量时间:我不必总是手动搜索它们。
请注意,除了 LaTeX 之外,我的编程技能相当有限。
答案1
控制序列方法
至于您询问的宏,这里有一个使用分隔参数(类似于@jfbu 的解决方案)的解决方案,其中包含通过转义字符引入的规范宏\
,它结合了您的语法设计:
\documentclass{article}
\newcount\switch
\switch=0
\def\maybehide#1{\maybehidei#1}
\def\maybehidei L #1 L{\ifnum\switch>0\unskip\else#1\fi}
\begin{document}
\maybehide{L Hello L} World
\end{document}
积极角色方法
现在,您的实际问题变成了关于 (La)TeX 中不使用转义字符的字符串。因此,您可以执行以下操作:首先,您需要将{
和的类别代码更改}
为活动。然后,您可以使用它们(再次)定义带有分隔参数的宏,您需要将新字符分配给类别代码 1 和 2,因为旧字符现在已丢失。一个普通的 TeX 示例可能看起来像
\newcount\switch
\switch=0
\catcode`\(=1
\catcode`\)=2
\catcode`\{\active
\catcode`\}\active
\def{L #1 L}(\ifnum\switch>0\unskip\else#1\fi)
{L Hello L} World
\bye
但,这样做会破坏很多东西。为了避免大多数这些问题,你必须说类似的话
\def\mymacro#1{\bgroup\bf World: #1\egroup}% test macro
\newcount\switch
\switch=1
\catcode`\(=1
\catcode`\)=2
\catcode`\{\active
\catcode`\}\active
\def\:(\let\sptoken= ) \:
\def{(\bgroup\futurelet\next\braceaux)
\def\braceaux(\ifx L\next\expandafter\maybehide\fi)
\def\maybehide L(\afterassignment\maybehideaux\let\spacechecker= )
\def\maybehideaux(%
\if\noexpand\spacechecker\sptoken
\expandafter\maybehideprocess\else L\spacechecker\fi)
\def\maybehideprocess #1L}(\ifnum\switch>0\unskip\else#1\fi\unskip)
\def}(\egroup)
\catcode`\(=12
\catcode`\)=12
{L Hello L} World
{L
\mymacro{Hello}
L}
{\it Testing a simple group}
Empty group after \TeX{}
{LLLLLLLL}
\bye
由于您对 OP 的评论之一指出您尚未被大括号所束缚,并且由于最后一个 hack 相当肮脏,这里有一个使用 的版本~
。 (仍然肮脏,但虽然稍微干净一些。) 它所做的几乎与最后一个例子相同。
\documentclass{article}
\newcount\switch
\switch=0
\catcode`\~\active
\catcode`\@=11
\def~#1{\let\@tempa=#1\afterassignment\tilde@\let\next= }
\def\tilde@{%
\ifx L\@tempa
\expandafter\tilde@@
\else
\tilde@aux
\fi
}
\def\tilde@@{%
\if\noexpand\next\@sptoken
\expandafter\tilde@hide@or@show
\else
\tilde@aux
\fi
}
\def\tilde@aux{\nobreakspace\@tempa\next}
\def\tilde@hide@or@show#1 L~{\ifnum\switch>0\unskip\else#1\fi}
\catcode`\@=12
\begin{document}
~L Hello L~ World~League
\end{document}
它将\switch=0
编译为
以及\switch=1
评论字符方法
如果您愿意允许使用不同的语法,最简单的方法是定义另一个注释字符,即%
。假设正斜杠是我们的候选者:
\documentclass{article}
\def\hideon{\catcode`\/=14}
\def\hideoff{\catcode`\/=9}
\hideon
\begin{document}
/ Hello
World
\end{document}
这里\hideon
和\hideoff
相当于上个例子中的\switch=1
和。\switch=0
但是,您可以模仿最后一种技术,并获得一个更接近您计划的语法设计的版本,方法是使用经过修改的波浪号版本\tilde@hide@or@show
(参见主动字符方法),该版本只需要初始的“~L”并从扫描到行尾:
\def\tilde@hide@or@show{\begingroup\catcode`\^^M=12 \tilde@hide@or@show@}
\bgroup\catcode`\^^M=12 %
\gdef\tilde@hide@or@show@#1^^M{%
\ifnum\switch>0\unskip\else#1 \fi\endgroup}%
\egroup
~L
然后将被用作
~L Hello
World
完整示例:
\documentclass{article}
\newcount\switch
\switch=1
\catcode`\~\active
\catcode`\@=11
\def~#1{\let\@tempa=#1\afterassignment\tilde@\let\next= }
\def\tilde@{%
\ifx L\@tempa
\expandafter\tilde@@
\else
\tilde@aux
\fi
}
\def\tilde@@{%
\if\noexpand\next\@sptoken
\expandafter\tilde@hide@or@show
\else
\tilde@aux
\fi
}
\def\tilde@aux{\nobreakspace\@tempa\next}
\def\tilde@hide@or@show{\begingroup\catcode`\^^M=12 \tilde@hide@or@show@}
\bgroup\catcode`\^^M=12 %
\gdef\tilde@hide@or@show@#1^^M{%
\ifnum\switch>0\unskip\else#1 \fi\endgroup}%
\egroup
\catcode`\@=12
\begin{document}
~L Hello
World,~Hello
\end{document}
答案2
最简单的方法是使用分隔宏的概念:这在 LaTeX 手册中没有广泛记录,但 LaTeX 是基于允许此功能的 TeX 宏语言构建的。
但是,完全按照您的意愿去做会有问题(我们不想改变括号的 catcode),因此,如果您接受以以下样式来界定可选部分:blah blah blah \YY optional\ZZ blah
然后在序言中输入:
\newcommand\YY{}
\newcommand\ZZ{}
\long\def\YY #1\ZZ {}
然后可选文本将不会出现。如果您希望它显示,只需注释掉该\long\def ...
行。这将打印blah blah blah optionalblah
,如果您想要一个空格,您应该在文件中有\YY optional \ZZ
,或者,您可以不\newcommand\ZZ{}
定义\newcommand\ZZ{ }
。完整 mwe:
\documentclass{article}
\newcommand\YY{}
\newcommand\ZZ{}
% comment next line out to deactivate \YY and \ZZ
\long\def\YY #1\ZZ {}
\begin{document}
blah blah blah \YY optional\ZZ blah
\end{document}
这是一种针对短文本的方法:对于较长的文本,您可能会遇到嵌套问题,\YY ... \YY .. \ZZ ... \ZZ
而无法得到预期的结果。
答案3
这是一个基于 LuaLaTeX 的解决方案。它定义了一个名为 的 Lua 函数,hidedelims
该函数提取分隔符" {L"
和所包围的材料"L} "
,并设置了两个 LaTeX 宏,分别称为\switchon
和\switchoff
,用于启用和禁用 Lua 函数的操作。术语“空白”应按其一般意义理解,即不仅包括空格,还包括“制表符”。(在 Lua 中,%s
表示通用空白字符。)
评论:您的要求写得有点混乱。首先,您似乎表示应该隐藏分隔符对之间的所有内容。后来,您似乎表示应该显示分隔符之间的内容(但不是分隔符本身)。在我的回答中,我已经实现了第二个要求。如果您确实想隐藏分隔符之间的所有内容(以及大概是分隔符本身),只需将行
return ( string.gsub ( line , '%s{L(.-)L}%s', '%1' ) )
到
return ( string.gsub ( line , '%s{L.*L}%s', '' ) )
在以下屏幕截图中,所有字符串“ {LHelloL} ”和“ {LGoodbyeL} ”实例左侧的垂直线和右侧的点用于在隐藏分隔符打开或关闭时直观地分隔输出。宏\verb+ ... +
用于显示{
和}
字符(如果没有被删除hidedelims
)。
% !TEX TS-program = lualatex
\documentclass{article}
%% Lua-side code: A function called "hidedelims"
\usepackage{luacode}
\begin{luacode}
function hidedelims ( line )
return ( string.gsub ( line , '%s{L(.-)L}%s', '%1' ) )
end
\end{luacode}
%% TeX-side code: Macros to enable/disable the Lua function
\usepackage{luatexbase}
\newcommand\switchon{\directlua{%
luatexbase.add_to_callback ( "process_input_buffer",
hidedelims, "hidedelims" )}}
\newcommand\switchoff{\directlua{%
luatexbase.remove_from_callback( "process_input_buffer",
"hidedelims" )}}
%% Just for this example...
\usepackage{showframe}
\setlength\parindent{0pt}
\begin{document}
\verb+ {LHelloL} +.
\switchon
\verb+ {LHelloL} +.
\switchoff
\verb+ {LHelloL} +.
\medskip
\verb+ {LGoodbyeL} +.
\switchon
\verb+ {LGoodbyeL} +.
\switchoff
\verb+ {LGoodbyeL} +.
\end{document}
以下是代码的一个版本,它始终隐藏分隔符,并显示或隐藏分隔符内的内容,具体取决于 或 是否\HideOff
有效\HideOn
。以下屏幕截图显示了两次传递的结果——首先使用\HideOff
,然后使用—— 包含由和\HideOn
分隔的内容的段落。{L
L}
% !TEX TS-program = lualatex
\documentclass{article}
%% Lua-side code:
%% - Boolean variable "check_hide_stuff"
%5 - Function "hide_stuff", assigned to "process_input_buffer" callback
\usepackage{luacode,luatexbase}
\begin{luacode}
check_hide_stuff = false
function hide_stuff ( line )
if check_hide_stuff then
return ( string.gsub ( line , '%s{L.-L}%s', '' ) )
else
return ( string.gsub ( line , '%s{L(.-)L}%s', '%1' ) )
end
end
luatexbase.add_to_callback ( "process_input_buffer",
hide_stuff, "hidestuff" )
\end{luacode}
%% TeX-side code: Macros to modify value of "check_hide_stuff"
\newcommand\HideOn{\directlua{check_hide_stuff = true}}
\newcommand\HideOff{\directlua{check_hide_stuff = false}}
\begin{document}
\HideOff %% show material inside delimiters
\noindent
A long time ago {L in a galaxy far, far awayL} , a {L beautifulL} princess lived in a {LmajesticL} castle close to a {Lmysterious andL} dark forest {LL} .
\HideOn %% hide material inside delimiters
\bigskip\noindent
A long time ago {L in a galaxy far, far awayL} , a {L beautifulL} princess lived in a {LmajesticL} castle close to a {Lmysterious andL} dark forest {LL} .
\end{document}
答案4
你可以用 encTeX 的原语替换 "{L '\hideBEG
并将 " L}"替换为。然后删除参数是一个简单的 TeX 任务:\hideEND
\mubyte
\mubyte\hideBEG {L \endmubyte % "{L " -> \hideBEG
\mubyte\hideEND \space\space L}\endmubyte % " L}" -> \hideEND
\newcount\switch \switch=0
\ifnum\switch>0
\def\hideBEG #1\hideEND{\unskip}
\else
\def\hideBEG #1\hideEND{#1}
\fi
This is test {L word L} here.
\end
EncTeX 是 pdfTeX 内置的简单预处理器,但 LaTeX 默认不激活它。必须在格式生成期间激活它。例如,csplain 格式默认激活 encTeX,因此我的示例可以通过 csplain 格式(无 LaTeX)进行测试。