如何制作带有强制括号的命令?

如何制作带有强制括号的命令?

部分灵感来自这个问题,我对这个问题很感兴趣,我们是否可以(假设)切换到一种新的 LaTeX 语法,其中括号括起来的参数是强制性的。也就是说,不再是\frac12; 总是\frac{1}{2}。在许多方面,这种语法会更好,造成的混乱也会少得多。

无论如何,我想到的第一个(非常丑陋的)解决方案是滥用g-type 参数(见下文)。什么才是最好的/最强大的解决方案?

\documentclass{article}

\usepackage{xparse}

\NewDocumentCommand\foo{g}{%
    \IfValueTF{#1}{%
        foo(#1)%
    }{%
        \PackageError{foo}{Missing braces around argument}%
        {This is the newest trend in LaTeX syntax}%
    }%
}

\begin{document}

\foo{bar} % prints foo(bar)

\foo1 % issues an error

\end{document}

在此处输入图片描述

答案1

如果滚动浏览错误,错误恢复会有点残酷,但是......

\foo 1给出:

 ! Package foo Error: unexpected text before brace.
\documentclass{article}

\begin{document}

\long\def\foo#1#{%
  \if\relax\detokenize{#1}\relax\expandafter\foox
  \else\PackageError{foo}{unexpected text before brace}{you are doomed}\fi}
\def\foox#1{foo(#1)}



\foo{bar}

\foo1

\end{document}

答案2

使用令牌循环。

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tokcycle}
\newcommand\abortfoo{\tcpush{\empty\endfoo}}
\xtokcycleenvironment\foo
  {Bad syntax (unbraced character)\abortfoo}
  {\addcytoks{\fooaux{##1}}\abortfoo}
  {Bad syntax (unbraced control sequence)\abortfoo}
  {Bad syntax (unbraced space)\abortfoo}
  {\stripgroupingtrue}
  {}
\newcommand\fooaux[1]{Foo argument ``\detokenize{#1}''}
\begin{document}
\foo A

\foo\today

\foo\tcsptoken

\foo{X}

\foo{\today}
\end{document}

在此处输入图片描述

答案3

另一种自动给出缺失{错误并且不会浪费整个文档去寻找的机制{

\documentclass{article}

\def\foo{\afterassignment\foox\toks0 }
\def\foox{foo(\the\toks0)}

\begin{document}

\foo{bar}

\foo1
\end{document}

这使

! Missing { inserted.
<to be read again> 
                   1
l.10 \foo1

答案4

除了检测 catcode-1-左括号和 catcode-2-右括号的所需类型(显式/隐式/特定字符代码)的问题之外,另一个问题可能是检测左括号和右括号的正确嵌套。

(我想到的是 Lua 扩展,但据我所知,当通过 Lua 代码向前看时,TeX 引擎的字符标记的类别代码将不会被考虑在内。)

一种在扩展上下文中也能 100% 可靠地运行的机制,用于检测标记流中的下一个标记是否是类别代码 1(组开头)的(显式)字符标记,可能是字符代码 123({) ),如果不是,则仅发出定制的错误消息(而不发出其他任何消息),这需要 100% 可靠的可扩展前瞻标记流的下一个标记。
这在传统的 TeX 引擎中是不可能的。

通过 -notation使用{-delimited 参数可能会导致在没有明确说明的#{情况下,生成有关与您定制的错误消息之前/之后的定义不匹配的内容的 TeX 错误消息。{1

基于抓取的方法⟨一般文本⟩倾向于(\toks0=...} 不可扩展,或(\scantokens等)不保留 catcode-régime,或(\uppercase/ \lowercase)不保留字符代码。除此之外,⟨一般文本⟩之前的左括号标记⟨平衡文本⟩可以是显式的或隐式的,并且在扫描时不会抑制扩展⟨一般文本⟩的左括号标记。

基于\@ifnextchar\let或的方法\futurelet基于赋值,因此不可扩展。如果可扩展性不是您感兴趣的,那么例如使用\futurelet,遵循其微妙之处,您可以让 TeX 提前查看下一个标记的含义,如果它表示 catcode-1 标记,则可能在通过参数处理宏检查后续标记的(字符代码)之前应用\string或,\meaning然后再进行任何在正确的 catcode 机制下重新插入字符串化标记的技巧。如果\escapechar当前具有负值,则可能会出现区分显式字符标记与控制符号标记/单字母控制字标记的问题。可能会出现区分显式字符标记与让其相等的活动吊坠的问题。


在你的问题中你提到需要括号的 TeX 基本语法其中

\def\seq{abcdef}%
\uppercase\seq  %

出现问题是因为在\upppercase扫描⟨一般文本⟩\seq以作为“起点”的左括号标记扩展不会产生以开头的标记序列⟨填料⟩后面跟着一个左括号标记(可能是隐式的,也可能是显式的),后面跟着⟨平衡文本⟩ 随后是⟨右括号⟩(必须明确)。

虽然无法以可扩展且 100% 可靠的方式检测 TeX 口中产生的标记流的下一个标记是否明确 ,但可以在扩展阶段(即在 TeX 的喉咙中)进行测试,如果一组来自已经抓取的宏参数(抓取过程中已删除最外层括号)的标记形成{1⟨平衡文本⟩嵌套在明确的catcode 1/2 的字符标记:

% A TeX-engine is needed which brings along the \expanded-primitive.

\tt
\hyphenchar\font=`\-\relax
\emergencystretch 3em
\frenchspacing
\parindent=0pt


\chardef\stopromannumeral=`\^^00
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
%%-----------------------------------------------------------------------------
%% Check whether argument forms <balanced text> that is nested 
%% between a pair of matching explicit catcode1/2-character-
%% tokens:
%%.............................................................................
%% \CheckWhetherNestedInExplicitBraces{<Argument which is to be checked>}%
%%                                    {<Tokens to be delivered in case that argument
%%                                      which is to be checked is nested between 
%%                                      whatsoever explicit braces>}%
%%                                    {<Tokens to be delivered in case that argument
%%                                      which is to be checked is not nested between 
%%                                      whatsoever explicit braces>}%
\long\def\CheckWhetherNestedInExplicitBraces#1{%
  \romannumeral\expandafter\secondoftwo\expandafter{\expandafter{\string#1.}%
  \expandafter\firstoftwo\expandafter{\expandafter\secondoftwo\string}%
  \expandafter\secondoftwo\string{\expandafter\expandafter\expandafter
  \secondoftwo\expandafter\expandafter\expandafter{\expandafter\expandafter
  \expandafter{\expandafter\string\firstoftwo{}#1}\expandafter\secondoftwo
  \string}\expandafter\firstoftwo\expandafter{\expandafter\secondoftwo\string}%
  \expandafter\stopromannumeral\secondoftwo}{\expandafter\stopromannumeral
  \firstoftwo}}{\expandafter\stopromannumeral\secondoftwo}%
}%


01. \CheckWhetherNestedInExplicitBraces{A{B}C}{Nested in explicit braces}{Not nested in explicit braces}%

02. \CheckWhetherNestedInExplicitBraces{}{Nested in explicit braces}{Not nested in explicit braces}%

03. \CheckWhetherNestedInExplicitBraces{ }{Nested in explicit braces}{Not nested in explicit braces}%

04. \CheckWhetherNestedInExplicitBraces{{A}BC}{Nested in explicit braces}{Not nested in explicit braces}%

05. \CheckWhetherNestedInExplicitBraces{ABC}{Nested in explicit braces}{Not nested in explicit braces}%

06. \CheckWhetherNestedInExplicitBraces{{A}{B}{C}}{Nested in explicit braces}{Not nested in explicit braces}%

07. \CheckWhetherNestedInExplicitBraces{{ABC} }{Nested in explicit braces}{Not nested in explicit braces}%

08. \CheckWhetherNestedInExplicitBraces{ {ABC} }{Nested in explicit braces}{Not nested in explicit braces}%

09. \CheckWhetherNestedInExplicitBraces{ {ABC}}{Nested in explicit braces}{Not nested in explicit braces}%

10. \CheckWhetherNestedInExplicitBraces{{ABC}}{Nested in explicit braces}{Not nested in explicit braces}%

\noindent\hrulefill\null

11.
\def\seq{{abcdef}}%
\expandafter\CheckWhetherNestedInExplicitBraces\expandafter{\expanded{\seq}}{%
  \uppercase\seq 
}{%
  %\errmessage
     {Here could be a customized error-message about things not being nested between
      explicit brace tokens (although with \string\uppercase\space an implicit left 
      brace would do as well.)}%
  %Or try one of the following:
  %\uppercase\expandafter{\seq}%
  %\uppercase\expandafter{\expanded{\seq}}%
}%


\noindent\hrulefill\null

12.
\def\seq{abcdef}%
\expandafter\CheckWhetherNestedInExplicitBraces\expandafter{\expanded{\seq}}{%
  \uppercase\seq 
}{%
  %\errmessage
     {Here could be a customized error-message about things not being nested between
      explicit brace tokens (although with \string\uppercase\space an implicit left 
      brace would do as well.)}%
  %Or try one of the following:
  %\uppercase\expandafter{\seq}%
  %\uppercase\expandafter{\expanded{\seq}}%
}%

\bye

在此处输入图片描述

相关内容