我尝试找到一种方法来制作
\newcommand
这样它就有了不同的输出,它是随机选择的。在最好的情况下,宏还应该避免单词重复(例如,仅当这个单词在 50 个单词中未被使用时才选择它)。
在这个宏中,我想将相似的单词分组,我在文档中经常使用它们。例如,如果我经常写同一个名字,它有时应该只打印姓氏,有时应该打印全名。
编辑另一个例子:宏应该打印“the group”或“the group of people”或任何不同的同义词,这样我对这个词池就只有一个宏。
答案1
您可以通过指定相对频率来定义宏:
\documentclass{article}
\usepackage{xparse}
\input{random}
\ExplSyntaxOn
% alias \setrannum to an expl3 function
\cs_set_eq:NN \benutzer_set_rannum:Nnn \setrannum
\NewDocumentCommand{\newrandomcommand}{mm}
{% #1 is the macro name, #2 is the data
\cs_if_exist:cTF { #1 }
{
ERROR!
}
{
\benutzer_new_random_command:nn { #1 } { #2 }
}
}
\seq_new:N \l__benutzer_data_seq
\int_new:N \l__benutzer_random_int
\cs_new_protected:Npn \benutzer_new_random_command:nn #1 #2
{
\seq_set_split:Nnn \l__benutzer_data_seq { , } { #2 }
\seq_new:c { g_benutzer_#1_data_seq }
\benutzer_process_data:n { #1 }
\cs_new_protected:cpn { #1 }
{
\benutzer_set_rannum:Nnn \l__benutzer_random_int { 1 }
{ \seq_count:c { g_benutzer_#1_data_seq } }
\seq_item:cn { g_benutzer_#1_data_seq } { \l__benutzer_random_int }
}
}
\cs_new_protected:Npn \benutzer_process_data:n #1
{
\seq_map_inline:Nn \l__benutzer_data_seq
{
\__benutzer_process_item:nw { #1 } ##1 // \q_stop
}
}
\cs_new:Npn \__benutzer_process_item:nw #1 #2 / #3 / #4 \q_stop
{
\tl_if_blank:nTF { #3 }
{
\__benutzer_add_item:nnn { #1 } { #2 } { 1 }
}
{
\__benutzer_add_item:nnn { #1 } { #2 } { #3 }
}
}
\cs_new_protected:Npn \__benutzer_add_item:nnn #1 #2 #3
{
\prg_replicate:nn { #3 }
{
\seq_put_right:cn { g_benutzer_#1_data_seq } { #2 }
}
}
% this is just for testing
\NewDocumentCommand{\test}{mm}
{
\prg_replicate:nn { #2 } { #1\space }
}
\ExplSyntaxOff
% Fyodor will appear 10/61 times on average
% Michailovich will appear 1/61 times on average
% Dostoyevsky will appear 50/61 times on average
\newrandomcommand{fyodor}{Fyodor/10, Mikhailovich, Dostoyevsky/50}
\begin{document}
\raggedright
\test{\fyodor}{100}
\end{document}
答案2
这是初步版本。到目前为止,尚未统计一个单词被调用了多少次。我会更新解决方案...
只需定义一个单词池列表\NewWordPool{poolname}{WordA,WordB,{SentenceA}}
并说\pickuprandomword{\poolname}
池名称就像一个宏名称,但没有\
字符
\documentclass{article}
\usepackage{datetime}%
\usepackage{tikz}%
\usepackage{ifthen}%
\usepackage{etoolbox}%
\listgadd{\GroupWordsPools}{}%
\listgadd{\GroupWordsPoolsCount}{}%
\usepackage{forloop}%
\newcommand{\NewWordPool}[2]{%
\csxdef{#1}{}%
\forcsvlist{\listcsxadd{#1}}{#2}%
\csxdef{#1values}{}%
\forcsvlist{\listcsxadd{#1values}}{0}%
}%
\newcounter{loopcounter}%
\newcounter{randompos}%
\def\lastrandom{0}%
\newcommand{\pickuprandomword}[2][50]{%
\def\currentrandom{}%
%First counter the number of elements in the list
\renewcommand*{\do}[1]{%
\stepcounter{randompos}%
}{}%
\dolistloop{#2}%
\pgfmathrandominteger{\currentrandom}{1}{\number\value{randompos}}%
\whiledo{\lastrandom =\currentrandom}{%
\pgfmathrandominteger{\currentrandom}{1}{\number\value{randompos}}%
}%
\setcounter{randompos}{0}%
\renewcommand*{\do}[1]{%
\stepcounter{randompos}%
\ifnumequal{\number\value{randompos}}{\currentrandom}{%
% Output the name
##1%
\listbreak%
}{}%
}%
\dolistloop{#2}%
\edef\lastrandom{\currentrandom}%
}%
\begin{document}
\NewWordPool{GroupWordsPool}{Hamlet,{Hamlet -- Prince of Denmark}, Shakespeare,{William Shakespeare}, Einstein,{Albert Einstein},Frodo, Bilbo, Gandalf,Aragorn,Galadriel,{Thorin Oakshield},Pippin,Elrond,Heisenberg,StackExchange}%
\forloop{loopcounter}{1}{\value{loopcounter} < 30}{%
\pickuprandomword{\GroupWordsPool}\par
}%
\结束{文档}
编辑我仍在努力寻找更好的解决方案,但这需要时间。
答案3
更新
lua 文件的更好版本,具有不同的概率
n = math.random(1,6)
if n == 6 then tex.sprint("foo1")
elseif n >= 4 then tex.sprint("foo2")
else tex.sprint("foo3")
end
(示例概率:
1/6 => foo1
1/3 => foo2
1/2 => foo3
)
另一个更简单的解决方案,但选项较少(并且仅当使用 Lualatex 时):
设置新命令:
\newcommand{\test}{\directlua{ dofile("test.lua") }\xspace}
测试.lua:
local test = { 'a','b'}
tex.sprint(test[math.random( #test )])
A和b需要更改为所需的文本输出(当然可以添加更多单词)
和测试可以更改为所需的命令名称。
我不知道是否或如何像其他解决方案一样限制单词重复或如何设置单词的平均出现次数。