我正在尝试定义一个\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