\romannumeral通过技巧重复

\romannumeral通过技巧重复

我正在尝试定义一个\repeatstring{#1}{#2}重复字符串#2 #1次数的命令。以下是我尝试的方法:(它基于我在如何将字符串连接成单个命令?

\documentclass[11pt, a4paper]{article}
\usepackage{etoolbox}
\newcounter{countdown}
\newcommand\concathere{}
\newcommand\repeatstring[2]{
    \setcounter{countdown}{#1}
    \renewcommand\concathere{}
    \whileboolexpr
        {test {\ifnumcomp{\thecountdown}{>}{0}{true}{false}}}
        {
        \addtocounter{countdown}{-1}
        \appto\concathere{#2}          % here the concatenation happens
        }
    \concathere
    }
\begin{document}
\repeatstring{5}{abc}
\end{document}

\concathere旨在包含所需次数的字符串。当我运行时,\repeatstring{5}{abc}输出只是“true”。不多也不少。有趣的是,当我用结果替换命令的最后一行时,aaa\concathere bbb结果是“true aaabbb”。这应该表明哪里出了问题,但我搞不清楚。可能它只是因为 5>0 而打印“true”,然后因为某种原因停止。

答案1

您误解了应该如何给出逻辑<expression>。结果应该是“逻辑上正确”,而不是文本true

\documentclass{article}

\usepackage{etoolbox}
\newcounter{countdown}
\newcommand\concathere{}
\newcommand\repeatstring[2]{%
    \setcounter{countdown}{#1}%
    \renewcommand\concathere{}%
    \whileboolexpr
        {test {\ifnumcomp{\thecountdown}{>}{0}}}% 
        {%
        \addtocounter{countdown}{-1}%
        \appto\concathere{#2}% here the concatenation happens
        }%
    \concathere
    }
\begin{document}
\repeatstring{5}{abc}

\end{document}

请注意,在表达式部分,我刚刚得到了一些可以产生逻辑结果的东西。手册中有几个例子etoolbox:例如,参见第 21 页。

%(我通过在行尾添加适当的内容来防止结果中出现虚假空格:与问题无关但对实际使用很重要。)

答案2

\romannumeral通过技巧重复

将该数字乘以 1000,将其转换为罗马数字。然后 TeX 生成一个由字母 组成的长字符串m,其长度为原始数字。

然后\repeatstringX查看下一个标记,如果是m,则输出字符串 unit。否则下一个标记是结束标记F,循环停止。

\documentclass[11pt, a4paper]{article}

\newcommand\repeatstring[2]{%
  \def\tempParam{#2}%
  \expandafter\repeatstringX\romannumeral\the\numexpr(#1)\relax000 F%
}
\newcommand*{\repeatstringX}[1]{%
  \csname repeatstring#1\endcsname
}
\newcommand*{\repeatstringm}{%
  \tempParam
  \repeatstringX
}
\newcommand*{\repeatstringF}{}

\begin{document}
  [\repeatstring{5}{abc}]
\end{document}

结果

修复 MWE

  • 如果\ifnumcomp在表达式中使用test,则省略 true 和 false 的参数,请参阅的描述test中的描述记录etoolbox

  • 存在许多不需要的空格,这是由 的定义中的行尾引起的\repeatstring

固定MWE:

\documentclass[11pt, a4paper]{article}
\usepackage{etoolbox}
\newcounter{countdown}
\newcommand\concathere{}
\newcommand\repeatstring[2]{%
  \setcounter{countdown}{#1}%
  \renewcommand\concathere{}%
  \whileboolexpr
     {test {\ifnumcomp{\thecountdown}{>}{0}}}
     {%
       \addtocounter{countdown}{-1}%
       \appto\concathere{#2}% here the concatenation happens
     }%
  \concathere
}
\begin{document}
  [\repeatstring{5}{abc}]
\end{document}

答案3

有多种方法可以满足您的需求。

\documentclass[11pt]{article}
\usepackage{xparse} % for D

% for A, B, C
\newcounter{mycount}

\makeatletter
\newcommand\repeatstringA[2]{%
  \setcounter{mycount}{#1}%
  \ifnum\themycount>0
    #2%
    \addtocounter{mycount}{-1}%
    \expandafter\@firstofone
  \else
    \expandafter\@gobble
  \fi
  {\repeatstringA{\themycount}{#2}}%
}

\newcommand\repeatstringB[2]{%
  \setcounter{mycount}{#1}%
  \@whilenum{\value{mycount}>0}\do{#2\addtocounter{mycount}{-1}}%
}

\newcommand\repeatstringC[2]{%
  \ifnum#1>0
    \expandafter\@firstofone
  \else
    \expandafter\@gobble
  \fi
  {#2\expandafter\repeatstringC\expandafter{\the\numexpr#1-1\relax}{#2}}%
}
\makeatother

\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\repeatstringD}{mm}
 {
  \prg_replicate:nn { #1 } { #2 }
 }
\ExplSyntaxOff

\begin{document}
\repeatstringA{5}{abc}

\repeatstringB{5}{abc}

\repeatstringC{5}{abc}

\repeatstringD{3*2-1}{abc}
\end{document}

最后一点尤其有吸引力。前两个本质上是等价的。

在此处输入图片描述

如果你想生成一个包含重复的控制序列,那么改变很容易:

\documentclass[11pt]{article}
\usepackage{xparse} % for D

% for A, B, C
\newcounter{mycount}

% a container
\newcommand{\concathere}{}

\makeatletter
\newcommand\repeatstringA[2]{%
  \renewcommand{\concathere}{}%
  \setcounter{mycount}{#1}%
  \ifnum\themycount>0
    \expandafter\def\expandafter\concathere\expandafter{\concathere #2}%
    \addtocounter{mycount}{-1}%
    \expandafter\@firstofone
  \else
    \expandafter\@gobble
  \fi
  {\repeatstringA{\themycount}{#2}}%
}

\newcommand\repeatstringB[2]{%
  \setcounter{mycount}{#1}%
  \@whilenum{\value{mycount}>0}\do{%
     \expandafter\def\expandafter\concathere\expandafter{\concathere #2}%
     \addtocounter{mycount}{-1}%
  }%
}

\newcommand\repeatstringC[2]{%
  \ifnum#1>0
    \expandafter\@firstofone
  \else
    \expandafter\@gobble
  \fi
  {%
   \expandafter\def\expandafter\concathere\expandafter{\concathere #2}%
   \expandafter\repeatstringC\expandafter{\the\numexpr#1-1\relax}{#2}%
  }%
}
\makeatother

\ExplSyntaxOn
\NewDocumentCommand{\repeatstringD}{mm}
 {
  %\tl_clear:N \concathere
  %\prg_replicate:nn { #1 } { \tl_put_right:Nn \concathere { #2 } }
  % a faster method suggested by Bruno Le Floch
  \tl_set:Nx \concathere { \prg_replicate:nn { #1 } { \exp_not:n { #2 } } }
 }
\ExplSyntaxOff

\begin{document}
\repeatstringA{5}{abc}\concathere

\repeatstringB{5}{abc}\concathere

\repeatstringC{5}{abc}\concathere

\repeatstringD{3*2-1}{abc}\concathere
\end{document}

\repeatstringX{5}{abc}宏执行结束时\concathere将包含abcabcabcabcabc

代替

\expandafter\def\expandafter\concathere\expandafter{\concathere #2}

(其中\def用于提高效率),你当然可以使用

\appto\concathere{#2}

只要你已经加载了etoolbox

这些方法都不会溢出输入堆栈大小;但是,大数字可能会溢出内存的其他部分。

答案4

ConTeXt 解决方案

\def\repeatstring#1#2{\edef\concathere{\dorecurse{#1}{#2}}}
\starttext
\repeatstring{5}{abc}\concathere
\stoptext 

相关内容