测试传递的参数是数字(可能是浮点数)还是维度

测试传递的参数是数字(可能是浮点数)还是维度

含钛Z 使用calc库你可以写类似的东西

\node (A) at ($(0,0)!0.75!(1,1)$) {};

或者你可以写一些(相当不同的东西)

\node (B) at ($(0,0)!2in!(1,1)$) {};

我想要做的是创建一个接受标量或维度参数的命令。

我天真地想做类似的事情

\def\test#1{\ifdim#1\relax ... \else ... \fi}

当然,这是完全错误的,因为\ifdim比较的是两个维度的值。所以我真正想要的是

\def\test#1{\ifIsDimension#1\relax ... \else ... \fi}

有什么建议我该如何做吗?

答案1

如果你不介意pgfmath解析器的开销,你可以解析数字并检查\ifpgfmathunitsdeclared。如果指定了 TeX 单位,则情况确实如此在任何时候在表达式中,或者如果表达式包含 TeX 认为具有单位的内容,例如跳过和盒子尺寸。

\documentclass[border=0.125cm]{standalone}

\usepackage{pgfmath,pgffor}
\parindent0pt

\def\print#1{\expandafter\Print#1@}
\def\Print#1{\if#1@\else\string#1\relax\expandafter\Print\fi}

\begin{document}

\newcount\mycount
\newdimen\mydimen
\newskip\myskip
\mycount=1
\mydimen=1pt
\myskip=1pt plus 1pt
\newbox\mybox
\setbox\mybox=\hbox{1}

\begin{minipage}{3in}
\foreach \value in {1, 1.0, 1e0, sin(1), 1cm, 1pt, 1mm, 1sp, 1mu, sin(1pt), 1+1pt,
    \mycount, \mydimen, \myskip, \wd\mybox, \mycount+1pt, width("1")}{%
    \pgfmathparse{\value}
    Expression \hbox to 2.5cm{\hfill`{\tt\print\value}'}
    \ifpgfmathunitsdeclared
        \emph{\bfseries has} a unit
    \else
        has no units
    \fi

}
\end{minipage}
\end{document}

在此处输入图片描述

还值得注意的是,\pgfmathpostparse在解析器完成之后但在退出之前会执行一个宏,其中可以完成进一步的操作。最初将其设置为,\relax但建议检查其值,以防某些库或其他包更改它。

解析的结果将会\pgfmathresult可能的来改变它(如果有人真的想的话)。然而它仍然在 TeX 组内,因此\global如果需要某些测试的结果,就必须使用它。

下面使用粗略整数测试的例子并不好,因为解析器很少返回整数(下面显示了一些例外)但说明了如何使用它。

\documentclass[border=0.125cm]{standalone}
\usepackage{pgfmath,pgffor}
\parindent0pt

\makeatletter
\newif\ifpgfmathresultinteger
\def\pgfmathpostparse{%
    \expandafter\pgfutil@in@\expandafter.\expandafter{\pgfmathresult}%
    \ifpgfutil@in@%
        \global\pgfmathresultintegerfalse%
    \else%
        \global\pgfmathresultintegertrue%
    \fi%
}

\def\print#1{\expandafter\Print#1@}
\def\Print#1{\if#1@\else\string#1\relax\expandafter\Print\fi}


\begin{document}

\newcount\mycount
\newdimen\mydimen

\mycount=1
\mydimen=1pt

\begin{minipage}{3.5in}
\foreach \value in {1, int(1.0), \mycount, \mydimen, int(\mydimen+1pt), \mycount+1pt}{%
    \pgfmathparse{\value}
    Parsing \hbox to 3.5cm{\hfill`{\tt\print\value}'} 
    does
    \ifpgfmathresultinteger
    \else
        \emph{\bfseries not} 
    \fi
    give an integer

}
\end{minipage}

\end{document}

在此处输入图片描述

答案2

这当然很慢,但应该处理所有情况(数字、尺寸、错误输入)。

\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\NewDocumentCommand{\IfIsDim}{mmm}
 {
  \aellet_ifisdim:nnn { #1 } { #2 } { #3 }
 }

\tl_new:N \l_aellet_ifisdim_arg_tl
\bool_new:N \l_aellet_ifisdim_has_unit_bool
\regex_const:Nn \c_aellet_unit_regex { (pt|pc|in|bp|cm|mm|dd|cc|sp|em|ex|px)\s*\Z }
\regex_const:Nn \c_aellet_number_regex { \A\s*(\+|\-)*[0-9]*\.?[0-9]*\s*\Z }
\cs_new_protected:Npn \aellet_ifisdim:nnn #1 #2 #3
 {
  \tl_set:Nn \l_aellet_ifisdim_arg_tl { #1 }
  \regex_match:NnTF \c_aellet_unit_regex { #1 }
   {% there is a unit of measure at the end
    \bool_set_true:N \l_aellet_ifisdim_has_unit_bool
    \regex_replace_once:NnN \c_aellet_unit_regex { } \l_aellet_ifisdim_arg_tl
   }
   {% no unit of measure
    \bool_set_false:N \l_aellet_ifisdim_has_unit_bool
   }
  \regex_match:NVTF \c_aellet_number_regex \l_aellet_ifisdim_arg_tl
   {
    \bool_if:NTF \l_aellet_ifisdim_has_unit_bool { #2 } { #3 }
   }
   {
    \ERROR
   }
 }
\cs_generate_variant:Nn \regex_match:NnTF { NV }
\ExplSyntaxOff

\IfIsDim{3.5pt}{\typeout{IS DIM}}{\typeout{IS NUMBER}}
\IfIsDim{3.5}{\typeout{IS DIM}}{\typeout{IS NUMBER}}
\IfIsDim{-3}{\typeout{IS DIM}}{\typeout{IS NUMBER}}
\IfIsDim{+--.5}{\typeout{IS DIM}}{\typeout{IS NUMBER}}
\IfIsDim{ .5 }{\typeout{IS DIM}}{\typeout{IS NUMBER}}
\IfIsDim{3.5 in}{\typeout{IS DIM}}{\typeout{IS NUMBER}}
\IfIsDim{3.5pq}{\typeout{IS DIM}}{\typeout{IS NUMBER}}

\stop

这是终端上的输出

IS DIM
IS NUMBER
IS NUMBER
IS NUMBER
IS NUMBER
IS DIM
! Undefined control sequence.
<argument> \ERROR

l.41 ...pq}{\typeout{IS DIM}}{\typeout{IS NUMBER}}

?

答案3

以下是 PSTricks 设置带或不带单位的长度的方式(使用 运行tex):

\catcode`\@=11
\newdimen\psunit \psunit=10pt% the current unit, can be any value
\def\pstunit@off{\let\@psunit\ignorespaces\ignorespaces}
%
\def\pssetlength#1#2{%  #1: dimen  #2 value (unit)
  \let\@psunit\psunit
  \afterassignment\pstunit@off
  #1 #2\@psunit}

\pssetlength\psunit{2} \the\psunit   %  2 times of the current unit

\pssetlength\psunit{1cm} \the\psunit %  absolute 1cm, the new current unit and so on
\bye

这真的很简单:

  • 如果#2没有单位,则尺寸#1设置为#2\@psunit,并且\afterassignment没有意义,因为它被执行 长度设置。
  • 如果#2有单位,则尺寸#1设置为#2,以下\@psunit就像\ignorespaces;它被重新定义\afterassignment

答案4

我使用了 A. Ellet 的答案,但将其缩短为

\def\isdimen#1{\afterassignment\isdimen@\tempdimen=#1em\relax}
\def\isdimen@#1\relax{\ifx&#1&\expandafter\@secondoftwo\else \expandafter\@firstoftwo\fi}

另外,你可以使用相同的想法来检查某个东西是否是整数:

\def\isint#1{\afterassignment\isint@\tempcount=#1\relax}
\def\isint@#1\relax{\ifx&#1&\expandafter\@firstoftwo\else \expandafter\@secondoftwo\fi}

遗憾的是,这些是不可扩展的。

此外,如果您想使用路由\pgfmathparse来检查某个东西是否为整数,则以下可扩展宏可以检查的值是否\pgfmathresultn或 的形式n.0

\def\ifpgfmathresultisint{\expandafter\ifpgfmathresultisint@\pgfmathresult..\nil}
\def\ifpgfmathresultisint@#1.#2.#3\nil{%
    \ifx\nil#2\nil
        \expandafter\@firstoftwo
    \else
        \ifnum#2=0
            \expandafter\expandafter\expandafter\@firstoftwo
        \else
            \expandafter\expandafter\expandafter\@secondoftwo
        \fi
    \fi
}

相关内容