\fpeval、\or 和 \CountToken 之间发生冲突

\fpeval、\or 和 \CountToken 之间发生冲突

(这是我在这里的第一个问题,对于它的任何“副作用”深表歉意......)

我想实现的是,根据 的值\MyR(0 到 1 之间的数字,不包括 1)选择集合中的第一个/第二个/...项。在下面的 MWE 中,集合以 格式实现{item1\or item2\or item3 ...}。例如,如果集合有两个元素:那么,对于低于 0.5{item1\or item2}的值,将返回 ,对于高于 0.5 的值,将返回 。对于集合,0.33 将产生 ,而 0.34 将导致。下面我使用,并计算应返回其哪个分支。\MyRitem1item2{item1\or item2\or item3}item1item2\ifcase

版本(*)(见下文,通过 实现)似乎有效。但是,当我们取消注释最后一行(但只有一行) 时,\newcommandFromSet变体(**)(***)( 的两次尝试)会失败。 的成功似乎证明了基本概念的合理性,但我如何才能纠正 的定义?谢谢!\FromSet%\fpeval...(*)\FromSet

关联给@egreg's \CountToken。)

[格式{item1\SomeShortToken item2\SomeShortToken item3 ...}要容易输入,计算项目数也是为了方便用户。]

\documentclass{article}  %% MWE
\usepackage{xfp}

\def\finish{\finish}                    %% Frequency of token #1 (stored
\def\CountToken[#1,#2]{%                %% in counter #2) in what's
  \def\TestedToken{#1}%                 %% between \CountToken[#1,#2]
  \ifdefined#2#2=0 \else\newcount#2\fi  %% and \finish. Code copied from
  \let\TotalOccurrence#2%               %% https://tex.stackexchange.com
  \let\next\TestNext\next               %% questions/525556/token-
}                                       %% counter-strange-behaviour-
\long\def\TestNext#1{%                  %% of-math-mode (egreg's version)
  \def\CurrentToken{#1}%                %%
  \ifx\CurrentToken\finish              %%
    \let\next\relax                     %%
  \else                                 %%
    \ifx\CurrentToken\TestedToken       %%
      \advance\TotalOccurrence by 1     %%
    \fi                                 %%
  \fi                                   %%
  \next                                 %%
}                                       %%

\newcommand{\MyR}{0.67}  %% my "global variable".

\newcommand{\newcommandFromSet}[2]{\CountToken[\or,\cnti]#2\finish  %% (*)
  \xdef#1{\ifcase\fpeval{floor(\MyR*(1+\cnti))} #2\fi}}
\newcommand{\FromSet}[1]{\CountToken[\or,\cnti]#1\finish  %% (**)
          \ifcase\fpeval{floor(\MyR*(1+\cnti))} #1\fi}
%\renewcommand{\FromSet}[1]{\newcommandFromSet{\MyTemp}{#1}\MyTemp}  %% (***)

\begin{document}
\newcommandFromSet{\MyText}{first\or second\or third}
\newcommandFromSet{\MyNumber}{11\or 12\or 13}
The \MyText\ number is \MyNumber, I repeat,
\fpeval{1*\MyNumber}.  %% everything seems to be good.

The \FromSet{first\or second\or third} number is  %% this line seems to work.
\FromSet{11\or 12\or 13}, I repeat,  %% this line also seems to work.
%\fpeval{1*\FromSet{\or 11\or 12\or 13}}.  %% ! Extra \or. \TestedToken ->\or
\end{document}

答案1

\or恐怕你不能在那种情况下使用。但代码可以变得更简单。

我更喜欢用逗号分隔项目,而不是用 分隔\or,这样\FromSet宏是完全可扩展的。

通过\clist_count:n可扩展地访问项目的数量,我们可以缩放变量;然后截断并加 1。

\documentclass{article}
\usepackage{xfp}

\ExplSyntaxOn
\NewDocumentCommand{\newcommandFromSet}{O{\MyR}mm}
 {
  \cs_new:Npx #2
   {
    \clist_item:nn { #3 }
     {
      \fp_eval:n { trunc(#1*\clist_count:n { #3 },0) + 1 }
     }
   }
 }
\NewExpandableDocumentCommand{\FromSet}{O{\MyR}m}
 {
  \clist_item:nn { #2 }
   {
    \fp_eval:n { trunc(#1*\clist_count:n { #2 },0) + 1 } }
 }
\ExplSyntaxOff

\newcommand{\MyR}{0.67}  %% my "global variable".
\newcommand{\MyS}{0.1}  %% another "global variable".

\begin{document}

\newcommandFromSet{\MyText}{first,second,third}
\newcommandFromSet{\MyNumber}{,11,12,13}

The \MyText\ number is \MyNumber, I repeat,
\fpeval{1*\MyNumber}.

The \FromSet{first,second,third} number is
\FromSet{11,12,13}, I repeat,
\fpeval{1*\FromSet{11,12,13}}.

\newcommandFromSet[\MyS]{\MyTextA}{first,second,third}
\newcommandFromSet[\MyS]{\MyNumberA}{11,12,13}

The \MyTextA\ number is \MyNumberA, I repeat,
\fpeval{1*\MyNumberA}.

The \FromSet[\MyS]{first,second,third} number is
\FromSet[\MyS]{11,12,13}, I repeat,
\fpeval{1*\FromSet[\MyS]{11,12,13}}.

\end{document}

请注意,您可以使用不同的变量;默认值为\MyR

在此处输入图片描述

相关内容