我尝试找到一种方法,实际上我得到了
更新 :
\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