测试是否可以将标记列表分配给 \dimendef 的数量

测试是否可以将标记列表分配给 \dimendef 的数量

给定一个任意的标记列表(例如01abpt),如何检查它是否可以分配给一个维度(例如\@tempdima)?LaTeX\@defaultunits不是为这种类型的测试而设计的。如果标记列表的形式为10pt,那么很容易。但标记列表可以是任意的。例如,abpt将导致“!缺失数字,视为零”,我们不能这样做

\@tempdima\dimexpr 0pt+abpt\relax

为了增加问题的严重性,我们可能(在考虑到的情况下)接受10ptABD它是可维度的。

注意:未定义的控制序列被排除在标记列表之外。

关于数字测试的讨论这里,但这并不相关。

答案1

只是为了给出一些味道,这里是测试,检查第一个标记(在f-expansion 之后)是否是\dimen或,\skip并且后面跟着一个小于 32768 的整数:

\documentclass{article}
\usepackage{xparse,l3regex}

\ExplSyntaxOn
\tl_new:N \l_ahmed_arg_tl
\tl_new:N \l_ahmed_first_tl
\tl_new:N \l_ahmed_rest_tl
\tl_new:N \l_ahmed_temp_tl
\seq_new:N \l_ahmed_extr_seq
\prg_new_protected_conditional:Npnn \ahmed_if_dimen:n #1 {T,F,TF}
 {
  \tl_set:Nf \l_ahmed_arg_tl { #1 }
  \ahmed_check_primitive:
 }
\cs_generate_variant:Nn \token_if_eq_meaning_p:NN {NV}
\cs_new_protected:Npn \ahmed_check_primitive:
 {
  \tl_set:Nx \l_ahmed_first_tl { \tl_head:V \l_ahmed_arg_tl }
  \tl_set:Nx \l_ahmed_rest_tl { \tl_tail:V \l_ahmed_arg_tl }
  \bool_if:nTF
   {
    \token_if_eq_meaning_p:NV \tex_dimen:D \l_ahmed_first_tl
    ||
    \token_if_eq_meaning_p:NV \tex_skip:D \l_ahmed_first_tl
   }
   { \ahmed_check_integer: }
   { \ahmed_check_def_token: }
 }

\cs_generate_variant:Nn \regex_extract_once:nnN {nV}
\cs_new_protected:Npn \ahmed_check_integer:
 {
  \tl_set:Nf \l_ahmed_temp_tl { \l_ahmed_rest_tl } 
  \regex_extract_once:nVN { \A \d * } \l_ahmed_temp_tl \l_ahmed_extr_seq
  \seq_if_empty:NTF \l_ahmed_extr_seq
    { \prg_return_false: }
    {
     \int_compare:nTF { \seq_item:Nn \l_ahmed_extr_seq {0} < 32768 }
       { \prg_return_true: }
       { \prg_return_false: }
    }
 }

\cs_new:Npn \ahmed_test:n #1
 {
  \ahmed_if_dimen:nTF { #1 }{ \typeout{YES} } { \typeout{NO} }
 }

\ahmed_test:n {\dimen34abc}
\ahmed_test:n {\skip1234567}
\def\xyz{\dimen22}
\ahmed_test:n {\xyz}
\ahmed_test:n {aaa}

输出为

YES
NO
YES
! Undefined control sequence.
<argument> \ahmed_check_def_token: 

l.53 \ahmed_test:n {aaa}

表明在第四种情况下,控制确实转移到了下一阶段。这实际上仍然是不完整的,因为后面的整数\dimen\skip 可能是一个“隐式数字”(例如计数寄存器或\chardef令牌),因此需要检查。或者更糟的是,它可能嵌入在宏中:

\def\fake{2}
\dimen1\fake 1=1pt

将是一项合法的任务\dimen121

如果对令牌列表有更多的控制,例如我们确信它可以扩展为不可扩展令牌列表,检查可以更容易。

答案2

到目前为止,我发现以下测试足以满足我的需求。我考虑的唯一输入类型是以下类型

{1pt,1.5pt,...,10pt,13pt,15pt,...,21pt}
{1ex,2ex,...,10ex,13ex,15ex,...,21ex}

例如,它已由用户直接提供,用于在回调中进行解析。因此,catcode-12不需要将标记作为输入的一部分,但很容易容纳此类标记。我还可以\dimendef'd通过以下测试容纳寄存器:测试给定的控制序列是否是长度寄存器。在预期的应用程序中,我不需要测试\count'd\skip'd寄存器。问题实际上出在内部尺寸上,但它们不应该成为上述用户输入类型的一部分。

\documentclass{article}

\makeatletter
% Also test for number (without unit)
\newif\ifisnumber
\def\ifbooltrue#1{%
  \csname @\csname if#1\endcsname first\else second\fi oftwo\endcsname
}
\def\ifcmdcmp@#1#2\@nil{\expandafter#1}
\def\ifcmdcmp#1#2{%
  \csname @\expandafter\expandafter\expandafter
  \ifx\ifcmdcmp@#1\batchmode\@nil\@car#2\noboundary\@nil
  first\else second\fi oftwo\endcsname
}
\def\findunit#1#2#3\@nil{%
  % Check for a valid unit.
  \in@{,#1,}{,\paperwidth,\paperheight,\textwidth,\textheight,%
    \hsize,\vsize,\columnwidth,\linewidth,}%
  \ifbooltrue{in@}{%
    \@firstoftwo
  }{%
    \lowercase{\in@{,#1#2,}}{,em,ex,in,pt,pc,cm,mm,dd,cc,nd,nc,bp,sp,}%
    \ifbooltrue{in@}%
  }%
}
\def\catchremainder#1\@nil{\endgroup\def\remainder{#1}}
\def\ifdimensionable#1{%
  \isnumberfalse\begingroup
  \afterassignment\catchremainder
  \@tempcnta0#1\relax\@nil
  \ifcmdcmp\remainder\empty{%
    \isnumbertrue\@secondoftwo
  }{%
    \expandafter\ifcmdcmp\expandafter{\remainder}\relax{%
      \isnumbertrue\@secondoftwo
    }{%
      \expandafter\findunit\remainder xx\@nil
    }%
  }%
}
\makeatother

%\ifdimensionable{01}{\def\x{T}}{\def\x{F}}
%\ifdimensionable{01pt}{\def\x{T}}{\def\x{F}}
\ifdimensionable{01abpt}{\def\x{T}}{\def\x{F}}
%\ifdimensionable\paperwidth{\def\x{T}}{\def\x{F}}
% Is 'pt' 0pt or 1pt? Make it invalid input in revised code:
%\ifdimensionable{pt}{\def\x{T}}{\def\x{F}} 

\begin{document}
x
\end{document}

答案3

任意令牌列表?

如何赶上永无止境的 eTeX 情况,例如

\newdimen\tempdima
\def\Collatz#1{%
  \expandafter\Collatz
  \expandafter{\number\numexpr#1\ifodd#1 *3+1\else/2\fi\relax}%
}%
%
\tempdima=\Collatz{2057}pt %
%
\bye

如何处理产生不平衡括号的问题,例如,

\tempdima=\iffalse{\fi}4pt

如何处理可能存在的\outer-token?
(你可以这样做

\newdimen\tempdima
\outer\def\somenumber{17}
\tempdima=\somenumber pt
\showthe\tempdima
\bye

,但\somenumber不能作为宏参数的一部分进行处理,因为宏会触发对可能传递给的内容的检查\tempdima。)

相关内容