pdfTeX 引擎引入了\pdfstrcmp
可扩展字符串比较的原语,输入本身完全展开,例如
\edef\foo{\detokenize{foo}}
\ifnum\pdfstrcmp{\foo}{foo}=0 %
\TRUE
\else
\FALSE
\fi
详情纯 TeX 中的 \pdfstrcmp 或 \strcmp,这(几乎肯定)无法在 TeX90 中完全模拟。因此,该功能必须由引擎本身提供。哪些引擎提供了相当于的功能\pdfstrcmp
?
答案1
除了 pdfTeX 本身,e-pTeX 和 e-upTeX 也提供了\pdfstrcmp
这个名称下的原语。在 XeTeX 中,同样的想法被实现为\strcmp
:缺少pdf
反映了这与 PDF 无关的事实。在 LuaTeX 中,可以模拟 Lua 中的结果:
\directlua{
local write = tex.write
function strcmp(A,B)
if A == B then
write("0")
elseif A < B then
write("-1")
else
write("1")
end
end
}
\long\def\luaescapeexpandedstring#1{%
\luaescapestring{\detokenize\expandafter{\expanded{#1}}}%
}
\long\def\luastrcmp#1#2{%
\directlua{%
strcmp("\luaescapeexpandedstring{#1}","\luaescapeexpandedstring{#2}")
}%
}
请注意,我们必须在这里讨论以下几点:
- 正确处理
#
token 需要做一些扩展工作 - 除了“明显的”“它们相等”的结果之外,还需要涵盖“一个大于另一个”的结果(例如,在比较相同位数的大整数值时很有用!)
因此,我们可以设置类似
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname ifdefined\endcsname\relax
\ERROR
\expandafter\endinput
\fi
\ifdefined\directlua
\directlua{
local write = tex.write
function strcmp(A,B)
if A == B then
write("0")
elseif A < B then
write("-1")
else
write("1")
end
end
}
\long\def\luaescapeexpandedstring#1{%
\luaescapestring{\detokenize\expandafter{\expanded{#1}}}%
}
\long\def\stringcompare#1#2{%
\directlua{%
strcmp("\luaescapeexpandedstring{#1}","\luaescapeexpandedstring{#2}")
}%
}
\else
\ifdefined\pdfstrcmp
\long\def\stringcompare#1#2{\pdfstrcmp{#1}{#2}}
\else
\ifdefined\strcmp
\long\def\stringcompare#1#2{\strcmp{#1}{#2}}
\else
\ERROR
\fi
\fi
\fi
以引擎中立的方式进行定义\stringcompare
(注意,我避免使用原始名称,因为所需的扩展数与宏包装器不同)。