检查控制序列的参数是否是控制序列的最佳方法是什么?

检查控制序列的参数是否是控制序列的最佳方法是什么?

我尝试找到一种方法,实际上我得到了

更新 :

\documentclass{article}
\def\IsArgaCs#1{%
\ifcat\relax\noexpand#1true \else false \fi%
}%
\begin{document}
\def\a{a}%
\let\b=~%
\def\c{1}%
1)\IsArgaCs{\a}%    
2)\IsArgaCs{a}%
3)\IsArgaCs{\b}%
4)\IsArgaCs{\c}%
\def\name{A}%
\def\i{1}%
5)\IsArgaCs{\name\i}%
\let\d=z %
6)\IsArgaCs{\d}%
\end{document}

在此处输入图片描述

但我不确定这个测试是否正确。我需要这个测试,因为我想知道参数是像“A”这样的节点名称,还是像“\startpoint”这样的定义节点坐标的宏。

我读过这个如何检查令牌是否是宏但它非常复杂。

补充 :

代码示例:

\makeatletter
\newdimen\pt@xa
\newdimen\pt@ya
\def\SavedPoint#1#2{%
    \pgfextractx{\pt@xa}{\pgfpointanchor{#2}{center}}%
    \pgfextracty{\pt@ya}{\pgfpointanchor{#2}{center}}%
    \pgfextract@process\tkzsavepoint{\pgfpoint{\pt@xa}{\pt@ya}}%
    \global\expandafter\edef\csname #1\endcsname{\tkzsavepoint}% 
}
\def\macro#1#2#3{%
% if #1 a node get the coordinates
% else #1 is a macro defined by \SavedPoint get the coordinates
% I'm not sure that it's possible to get with the same way the coordinates
% etc. idem for #2 #3
% then work with the coordinates 
}
\makeatother

\path   coordinate (a) at (0,1)
        coordinate (b) at (1,2)
        coordinate (c) at (2,3);

        \SavedPoint{pta}{a}
        \SavedPoint{ptb}{b}
        \SavedPoint{ptc}{c}

\macro{a}{b}{c} or \macro{\pta}{\ptb}{\ptc}
 or  a mix \macro{a}{\ptb}{\ptc}

 possible \x\i  for the nodes for example inside a loop \foreach

答案1

您确实要检查控制序列标记吗?

类似的原语\relax不是宏,而是控制序列。

活动字符(类别代码为 13 的字符标记)不是控制序列标记,但可以将其定义为宏。

控制序列标记或活动字符标记,其含义表示未定义,也不是宏。

所讨论的参数为空的情况也是没有宏/没有控制序列标记的情况。

以左花括号 /catcode-1-characters 开头的参数可能需要特别注意。

以下代码通过检查所讨论参数的第一个标记的含义(如果该参数不为空)来提供测试。

前导空格标记和前导 catcode-1 字符均被考虑在内。

%%===============================================================
%% \firstoftwo and \secondoftwo:
%%...............................................................
\long\def\firstoftwo#1#2{#1} \long\def\secondoftwo#1#2{#2}
%%---------------------------------------------------------------
%% \AtIfArgsFirstTokenIsMacro - takes three macro-arguments and
%%              forks depending on whether the first argument
%%              holds a first/leading token whose \meaning equals
%%              one of the phrases "macro:", "\long macro:".
%%              If so delivers the second argument, otherwise
%%              delivers the third argument.
%%
%%              The macro is suitable for expansion contexts
%%              and due to \romannumeral-expansion delivers the
%%              result after two expansion steps/after "being
%%              hit by two \expandafter-chains".
%%
%%              The case of the first argument being empty/not
%%              holding any token at all is considered a case
%%              where the argument does not hold a first/leading
%%              token at all and thus does not hold a first/leading
%%              token whose meaning equals one of the phrases
%%              "macro:", "\long macro:".
%%
%%              The test does not rely on some token being
%%              undefined. eTeX- or whatsoever extensions are not
%%              required.
%%
%%              I assume there is room for improvement/shortening
%%              the code.
%%
%%              Testing by means of macros for a leading
%%              \outer-macro-token in the argument is somehat
%%              obsolete and impossible as \outer-tokens cannot
%%              occur inside macro-arguments.
%%
%%...............................................................
\def\AtIfArgsFirstTokenIsMacro#1#2{%
  \long\def\AtIfArgsFirstTokenIsMacro##1##2##3{%
    \romannumeral\iffalse{\fi\expandafter\secondoftwo\expandafter
    {\expandafter{\string##1}\expandafter\expandafter\expandafter
    \firstoftwo\expandafter\expandafter\expandafter\firstoftwo
    \expandafter\secondoftwo\expandafter{\expandafter{\iffalse}}\fi
    \expandafter\secondoftwo\string}\expandafter\firstoftwo
    \expandafter{\iffalse}\fi\iffalse{\fi
    \expandafter\innerAtIfArgsFirstTokenIsMacro\meaning##1#1}{}%
      {%
        \iffalse{\fi
        \expandafter\innerAtIfArgsFirstTokenIsLong\meaning##1#2 #1}{}%
      }{\secondoftwo}%
    }{\firstoftwo}%
    {0 ##3}{0 ##2}%
  }%
  \long\def\innerAtIfArgsFirstTokenIsMacro##1#1{%
    \innerAtIfArgsFirstTokenIs{##1}%
  }%
  \long\def\innerAtIfArgsFirstTokenIsLong##1#2 #1{%
    \innerAtIfArgsFirstTokenIs{##1}%
  }%
  \long\def\innerAtIfArgsFirstTokenIs##1{%
    \iffalse{\fi\expandafter\secondoftwo\expandafter{\string##1}%
    \expandafter\firstoftwo\expandafter{\iffalse}\fi\expandafter
    \expandafter\expandafter\firstoftwo}{\expandafter\expandafter
    \expandafter\secondoftwo}\expandafter\secondoftwo\expandafter
    {\iffalse}\fi
  }%
}%
% Somehow get the catcode-12-token-phrases "macro:" and "\long"
% as argument of \AtIfArgsFirstTokenIsMacro - hereby
% it is relied on the usual catcode settings and on primitives not
% being redefined and on integer parameters like \globaldefs and
% \endlinechar and \escapechar holding usual values, thus:
\begingroup
\edef\AtIfArgsFirstTokenIsMacro{%
  {\string m\string a\string c\string r\string o%
  \string :}{\string\long}%
}%
\expandafter\endgroup%
\expandafter\AtIfArgsFirstTokenIsMacro%
\AtIfArgsFirstTokenIsMacro%
%%===============================================================

\def\test{defined}

\long\def\testb{defined}

\catcode`\Z=13

1 \AtIfArgsFirstTokenIsMacro{\UndFINeD}{Macro}{Not Macro} % OK

2 \AtIfArgsFirstTokenIsMacro{\undefined A}{Macro}{Not Macro} % OK

3 \AtIfArgsFirstTokenIsMacro{\undefined A\fi}{Macro}{Not Macro} % OK

4 \AtIfArgsFirstTokenIsMacro{}{Macro}{Not Macro}  % OK

5 \AtIfArgsFirstTokenIsMacro{Z}{Macro}{Not Macro} % OK

6 \AtIfArgsFirstTokenIsMacro{\relax}{Macro}{Not Macro} % OK

7 \AtIfArgsFirstTokenIsMacro{\TeX}{Macro}{Not Macro} % OK

8 \AtIfArgsFirstTokenIsMacro{\test}{Macro}{Not Macro} % OK

9 \AtIfArgsFirstTokenIsMacro{\par}{Macro}{Not Macro} % Evaluate/OK

10 \AtIfArgsFirstTokenIsMacro{\fi}{Macro}{Not Macro} % OK

11 \AtIfArgsFirstTokenIsMacro{\else}{Macro}{Not Macro} % OK

12 \AtIfArgsFirstTokenIsMacro{\if}{Macro}{Not Macro} % OK

13 \AtIfArgsFirstTokenIsMacro{#}{Macro}{Not Macro} % OK

14 \AtIfArgsFirstTokenIsMacro{ }{Macro}{Not Macro} % OK

15 \AtIfArgsFirstTokenIsMacro{\endcsname}{Macro}{Not Macro} % OK

16 \AtIfArgsFirstTokenIsMacro{\AtIfArgsFirstTokenIsMacro}{Macro}{Not Macro} %Long Macro

17 \AtIfArgsFirstTokenIsMacro{\bgroup}{Macro}{Not Macro}% OK

18 \AtIfArgsFirstTokenIsMacro{\egroup}{Macro}{Not Macro}% OK

\letZ=\relax

19 \AtIfArgsFirstTokenIsMacro{Z}{Macro}{Not Macro}% OK

20 \AtIfArgsFirstTokenIsMacro{\testb}{Macro}{Not Macro}% OK

21 \AtIfArgsFirstTokenIsMacro{\testb bla bla}{Macro}{Not Macro}% OK

22 \AtIfArgsFirstTokenIsMacro{bla \fi}{Macro}{Not Macro}% OK

23 \AtIfArgsFirstTokenIsMacro{several tokens}{Macro}{Not Macro}% OK

24 \AtIfArgsFirstTokenIsMacro{A}{Macro}{Not Macro}% OK

25 \AtIfArgsFirstTokenIsMacro{{\undefined A}\fi}{Macro}{Not Macro}% OK

26 \csname\AtIfArgsFirstTokenIsMacro{\tEx}{tEx}{TeX}\endcsname% OK

27 \if0\AtIfArgsFirstTokenIsMacro{\tEx}{0}{1}\tEx \else \TeX\fi% OK

\bye

答案2

如果您指的是控制序列以反斜杠开头(与其含义无关),那么您可以尝试以下代码。请注意,此代码会检查所有替代方案(包括空格、参数中的更多标记或{})。

{\escapechar=-1\xdef\nb{\string\\}} % normal backslash
\def\IsArgaCs#1{\futurelet\next\isargacsA#1\end}
\def\isargacsA{\def\nextB{\expandafter\isargacsB\string}%
   \expandafter\ifx\space\next \def\nextB{\isargacsB.}\fi
   \ifx\next\bgroup \def\nextB{\expandafter\isargacsC\string}\fi
   \ifx\next\end \def\nextB{\isargacsB.}\fi
   \nextB
}
\def\isargacsB#1#2\end{\if\nb#1TRUE\else FALSE\fi}
\def\isargacsC#1{%
   \if\nb#1\def\nextB{\isargacsB\nb}\else
      \def\nextB{\expandafter\isargacsB\expandafter.\expandafter}%
   \fi
   \nextB{\iffalse}\fi
}

1)\IsArgaCs{\a}
2)\IsArgaCs{a}
3)\IsArgaCs{\b\c\d}
4)\IsArgaCs{\c}
\def\name{A}
\def\i{1}
5)\IsArgaCs{\name\i}
\let\d=z 
6)\IsArgaCs{\d}
7)\IsArgaCs{~}
8)\IsArgaCs{ }
9)\IsArgaCs{{}}

\bgroup编辑:我改进了因为必须返回 TRUE 但真正的开括号必须返回 FALSE 的测试\bgroup。必须使用相对平衡括号的技巧。

答案3

正如本 MWE 所示,该tokcycle包具有相当广泛的能力来收集标记的特征。在第 1.-7. 行中,我展示了其中一些能力。在第 8a. 和 8b. 行中,我提出了如何查找宏,我在此将其定义为可扩展的控制序列。

\documentclass{article}
\usepackage{tokcycle}
\newcommand\characteristics{%
  \ifactivetokunexpandable Unexpandable-Active-Token \else
    \ifactivetok Active-Token \fi\fi
  \ifactivechar Active-Char-Code \fi
  \ifimplicittok Implicit \fi
  \ifcatSIX Cat-6 \fi
}
\newcommand\IsArgaCs[1]{%
  \tokencycle{\characteristics}{}{Control Sequence \characteristics}%
  {Space \characteristics}#1\endtokencycle}
\parindent 0pt
\begin{document}
1: \IsArgaCs a\par
2: \IsArgaCs\relax\par
\let\littlet t
3: \IsArgaCs \littlet\par
\def\tmp{Q}
\catcode`Q=\active
\def Q{X}
4a: \IsArgaCs Q\par
\let QX
4b: \IsArgaCs Q\par
4c: \expandafter\IsArgaCs\tmp\par
\catcode`Q=11 
4d: \IsArgaCs Q\par
5a. \IsArgaCs #\par
\let\svhash#
5b. \IsArgaCs\svhash\par
6. \IsArgaCs\space\par
\makeatletter
7. \IsArgaCs\@sptoken\par
\smallskip
One can determine macro-ness by letting active character to the test token
  and testing the active character.  If not a macro, it comes up as 
  unexpandable:\\
\catcode`Q=\active
\let Q\relax
8A: \IsArgaCs Q\par
\let Q\today
8B: \IsArgaCs Q\par
\end{document}

在此处输入图片描述

答案4

如果你想了解控制序列标记,而不是那些含义表示它们是宏的标记:

应用于控制序列标记的结果\string受整数参数的值的影响\escapechar

让 TeX 应用\string不同的值\escapechar并检查结果是否不同。

通过应用尾随字符标记来确保字符串化的参数不为空。

确保不要对左括号应用字符串化,以免产生不平衡括号的构造。

\AtIfControlSequence检查参数的第一个标记是否是控制序列标记。

\AtIfControlSequence不可扩展/不适合扩展上下文,因为它在本地范围内执行分配。为了在本地范围内保存分配,\AtIfControlSequence 依赖于\globaldef的值是 0。

%%----------------------------------------------------------------------
%% Paraphernalia:
%%......................................................................
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
%%----------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a
%% catcode-1-character-token, e.g., an opening brace:
%%......................................................................
\long\def\CheckWhetherLeadingBrace#1{%
  \expandafter\secondoftwo\expandafter{\expandafter{\string#1.%
  }\expandafter\firstoftwo\expandafter{\expandafter\firstoftwo
  \expandafter\firstoftwo\expandafter}\string}\secondoftwo
}%
%%----------------------------------------------------------------------
%% Check whether argument's first token is a control-sequence
%% This test is _not_ expandable / is _not_ suitable for
%% expansion-contexts as it performs assignments.
%% Also it relies on \globaldef's value being 0.
%%......................................................................
\long\def\AtIfControlSequence#1{%
  \CheckWhetherLeadingBrace{#1}{\secondoftwo}{%
    \begingroup
    \escapechar=`\A\relax
    \expandafter\def\expandafter\tempa\expandafter{\string#1.}%
    \escapechar=`\B\relax
    \expandafter\def\expandafter\tempb\expandafter{\string#1.}%      
    \ifx\tempa\tempb
      \expandafter\endgroup\expandafter\secondoftwo
    \else
      \expandafter\endgroup\expandafter\firstoftwo
    \fi      
  }%
}%

1 \AtIfControlSequence{\relax}{}{not a }control sequence token

2 \AtIfControlSequence{{\relax}}{}{not a }control sequence token

3 \AtIfControlSequence{relax}{}{not a }control sequence token

4 \AtIfControlSequence{}{}{not a }control sequence token

5 \AtIfControlSequence{ \relax}{}{not a }control sequence token

\bye 

相关内容