以下代码按预期运行,并在终端上打印“答案是 5”。我如何更改以下代码,以便用伪代码替换行 B 和 C,
set \l_width_int to \width:N \l_test_seq
我在 A、B、C 线和其他地方尝试了很多方法,但都无法正常工作。我很困惑。谢谢。
\documentclass{article}
\usepackage[check-declarations]{expl3}
\begin{document}
\ExplSyntaxOn
\int_new:N \l_width_int
\seq_new:N \l_test_seq
\seq_set_from_clist:Nn \l_test_seq {alpha,beta,gamma}
% This function sets \l_width_int to the number of characters
% in the longest element of the sequence argument.
\cs_new:Npn \width:N #1
{
\int_new:N \l__width_curwidth_int
\int_new:N \l__width_maxwidth_int
\tl_new:N \l__width_cur_tl
\int_set:Nn \l__width_maxwidth_int {-1}
\seq_map_inline:Nn {#1}
{
\tl_set:Nn \l__width_cur_tl {##1}
\int_set:Nn \l__width_curwidth_int {\tl_count:N \l__width_cur_tl}
\int_compare:nT
{\l__width_curwidth_int > \l__width_maxwidth_int}
{\int_set:Nn \l__width_maxwidth_int \l__width_curwidth_int}
}
\int_set:Nn \l_width_int \l__width_maxwidth_int % line A
}
\width:N \l_test_seq % line B
\immediate\write16{answer~is~\int_use:N \l_width_int} % line C
\ExplSyntaxOff
\end{document}
答案1
为了能够\l_width_int
在 TeX 中将函数(实际上是宏)的结果设置为(或任何变量),我们必须安排通过扩展进行计算。换句话说expl3
,这意味着您只能使用 中带有星号的函数interface3
。为此,我们需要重新排列代码。我会选择类似
\cs_new:Npn \MS_width:N #1
{
\seq_map_function:NN {#1} \__MS_width:n
\__MS_result:n { -1 }
}
\cs_new:Npn \__MS_result:n #1 {#1}
\cs_new:Npn \__MS_width:n #1 #2 \__MS_result:n #3
{
\__MS_width:fnn
{ \int_eval:n { \tl_count:n {#1} } } {#2} {#3}
}
\cs_new:Npn \__MS_width:nnn #1#2#3
{
\int_compare:nNnTF {#1} > {#3}
{ #2 \__MS_result:n {#1} }
{ #2 \__MS_result:n {#3} }
}
\cs_generate_variant:Nn \__MS_width:nnn { f }
这个想法是设置映射,使得结果始终保持在输入流中:我使用它\__MS_result:n
作为标记来知道它在哪里,并允许映射标记“移动”。我还安排了一个简单的“不做任何事”函数,最终在映射结束时转储结果。这将在
\iow_term:x { answer~is~\MS_width:N \l_MS_test_seq }
(我在这里给你的公共序列起了一个‘正确’的名字。)
请注意,我已经使用 -type 扩展“强制”评估标记列表的长度f
,因此该值是精确计算出来的,而不是每次都可能计算出来的(如果列表中的第一个项目是最长的)。
我在这里使用的事实是,我知道我可以使用序列映射“移动东西”。我不想依赖序列的特定内部形式,所以必须坚持\seq_map_function:NN
。有人可能会说,直接从逗号列表中工作会更好,因此可以确切地知道所有代码中发生了什么:
\cs_new:Npn \MS_width_comma:N #1
{
\exp_after:wN \__MS_width:w #1 , \q_nil , \q_stop
{ -1 }
}
\cs_new:Npn \__MS_width:w #1 , #2 \q_stop #3
{
\quark_if_nil:nTF {#1}
{ #3 }
{
\__MS_width:fnn { \int_eval:n { \tl_count:n {#1} } }
{#2} {#3}
}
}
\cs_new:Npn \__MS_width:nnn #1#2#3
{
\int_compare:nNnTF {#1} > {#3}
{ \__MS_width:w #2 \q_stop {#1} }
{ \__MS_width:w #2 \q_stop {#3} }
}
\cs_generate_variant:Nn \__MS_width:nnn { f }
基本思想当然是一样的:根据输入的性质,你可以选择任何一种方式。(我不清楚你是从用户逗号列表开始,还是有一个包含空项的序列,ETC。)
答案2
你把事情弄得太复杂了。;-)
\documentclass{article}
\usepackage[check-declarations]{expl3}
\ExplSyntaxOn
\int_new:N \l_senn_width_int
\seq_new:N \l_senn_test_seq
\seq_set_from_clist:Nn \l_senn_test_seq {alpha,beta,gamma}
% This function sets \l_senn_width_int to the number of characters
% in the longest element of the sequence argument.
\cs_new_protected:Npn \senn_width:N #1
{
\int_set:Nn \l_senn_width_int {-1}
\seq_map_inline:Nn #1
{
\int_set:Nn \l_senn_width_int
{
\int_max:nn { \l_senn_width_int } { \tl_count:n { ##1 } }
}
}
}
\senn_width:N \l_senn_test_seq
\typeout{answer~is~\int_use:N \l_senn_width_int}
\ExplSyntaxOff
需要注意的几点:
使用前缀。
永远不要在函数中分配变量,除非函数专门设计用于分配变量未来用法。
您可以使用变量的当前值来设置变量。
该函数
\tl_count:n
可扩展,可以在整数环境中使用。主要功能
\senn_width:N
应该是protected
,因为它对变量进行赋值。
关于你的问题,比如
\int_set:Nn \l_senn_width_int { \senn_width:N \l_senn_test_seq }
需要\senn_width:N
完全可扩展,但我认为这并不容易。
您可以做的是定义一个双参数宏:
\senn_width_set:NN \l_senn_width_int \l_senn_test_seq
因此克服了可扩展性问题:
\cs_new_protected:Npn \senn_width_set:NN #1 #2
{
\int_set:Nn #1 {-1}
\seq_map_inline:Nn #2
{
\int_set:Nn #1
{
\int_max:nn { #1 } { \tl_count:n { ##1 } }
}
}
}
\senn_width_set:NN \l_senn_width_int \l_senn_test_seq