只是为了好玩,我编写了一个十进制数转换器,以 < 37 的基数打印它们:
\documentclass{article}
\usepackage{fixltx2e,hyperref,ifthen}
\usepackage{tipx}
\makeatletter
\newcount\mod
\newcommand*{\modulo}[2]{%
\mod=#1
\@tempcnta=#2
\ifnum\mod<\@tempcnta\else
\loop
\advance\mod by -#2
\unless\ifnum\mod<#2
\repeat
\fi}%
\newcount\cnv@quotient \cnv@quotient=0
\newcount\cnv@power \cnv@power=1
\newcount\cnv \cnv=0
\def\comv{}
\newcommand*{\convertdec}[2][2]{%
\begingroup
\let\uppercase\relax %if symbols should not be uppercased
\cnv@quotient=#2
\whiledo{\cnv@quotient>0}{%
\modulo{\cnv@quotient}{#1}
\edef\conv{\uppercase{\basechange{\the\mod}}\conv}
\divide\cnv@quotient by #1}%
\texorpdfstring{\conv\textsubscript{#1}}{\conv}
\endgroup}%
\newcommand{\basechange}[1]{%
\ifcase#1
0\or 1\or 2\or 3\or 4\or 5\or 6\or 7\or 8\or 9\or
\x \or \xi \or \xii \or \xiii \or \xiv \or \xv \or
\xvi \or \xvii \or \xviii \or \xix \or \xx \or
\xxi \or \xxii \or \xxiii \or \xxiv \or \xxv \or
\xxvi \or \xxvii \or \xxviii \or \xxix \or \xxx \or
\xxxi \or \xxxii \or \xxxiii \or \xxxiv \or \xxxv\fi}%
\def\x{a}
\def\xi{b}
\def\xii{c}
%and so on
\makeatother
\begin{document}
\convertdec[12]{131}
\end{document}
如果我改变数字控制字,例如
\def\x{$\alpha$}
\def\xi{$\beta$}
一切都很好。但是,当我说\def\x{\textturntwo}
编译不会终止时;似乎陷入了无限循环。奇怪的是控制台没有产生 TeX 容量超出的消息。文件.log
不完整。这里出了什么问题?
答案1
错误在于使用\xdef
而不是\protected@xdef
;\text...
LaTeX 中的所有宏不能用于替换文本\edef
(因此\xdef
)。
\documentclass{article}
\usepackage{fixltx2e,hyperref,ifthen}
\usepackage{tipx}
\makeatletter
\newcount\mod
\newcommand*{\modulo}[2]{%
\mod=#1
\@tempcnta=#2
\ifnum\mod<\@tempcnta\else
\loop
\advance\mod by -#2
\unless\ifnum\mod<#2
\repeat
\fi}%
\newcount\cnv@quotient \cnv@quotient=0
\newcount\cnv@power \cnv@power=1
\newcount\cnv \cnv=0
\def\conv{}
%% Switch the comment if you want to uppercase
\let\maybe@uppercase\@firstofone
%\let\maybe@uppercase\uppercase
\newcommand*{\convertdec}[2][2]{%
\cnv@quotient=#2
\whiledo{\cnv@quotient>0}{%
\modulo{\cnv@quotient}{#1}
\protected@edef\conv{\maybe@uppercase{\basechange{\the\mod}}\conv}
\divide\cnv@quotient by #1}%
\texorpdfstring{\conv\textsubscript{#1}}{\conv}
\let\conv\@empty}%
\newcommand{\basechange}[1]{%
\ifcase#1
0\or 1\or 2\or 3\or 4\or 5\or 6\or 7\or 8\or 9\or
\x \or \xi \or \xii \or \xiii \or \xiv \or \xv \or
\xvi \or \xvii \or \xviii \or \xix \or \xx \or
\xxi \or \xxii \or \xxiii \or \xxiv \or \xxv \or
\xxvi \or \xxvii \or \xxviii \or \xxix \or \xxx \or
\xxxi \or \xxxii \or \xxxiii \or \xxxiv \or \xxxv\fi}%
\def\x{\textturntwo}
\def\xi{b}
\def\xii{c}
%and so on
\makeatother
\begin{document}
\convertdec[12]{131}
\end{document}
我还修复了以下问题\uppercase
:在组外重新定义它是一个错误。无论如何都应该\let\uppercase\@firstofone
删除括号。但最好使用可以随意重新定义的其他宏,而不是重新定义原始宏。
在以下情况下更容易expl3
:
\documentclass{article}
\usepackage{fixltx2e,xparse,hyperref}
\usepackage{tipx}
\ExplSyntaxOn
\NewDocumentCommand{\convertdec}{O{2}m}
{
\ruben_convertdec:nn { #1 } { #2 }
}
\NewDocumentCommand{\definedigits}{m}
{
\ruben_define_digits:n { #1 }
}
\tl_new:N \l__ruben_converted_tl
\tl_new:N \l__ruben_temp_tl
\prop_new:N \l_ruben_digits_prop
\cs_new_protected:Npn \ruben_convertdec:nn #1 #2
{
\tl_set:Nx \l__ruben_converted_tl { \int_to_base:nn { #2 } { #1 } }
\tl_map_inline:Nn \l__ruben_converted_tl
{
\ruben_use_digit:n { ##1 }
}
\texorpdfstring{$\sb{#1}$}{}
}
\cs_new_protected:Npn \ruben_use_digit:n #1
{
\prop_item:Nn \l_ruben_digits_prop { #1 }
}
\cs_new_protected:Npn \ruben_define_digits:n #1
{
\clist_map_inline:nn { #1 }
{
\prop_put:Nnn \l_ruben_digits_prop ##1
}
}
% initialize
\int_step_inline:nnnn { 1 } { 1 } { 36 }
{
\tl_set:Nx \l__ruben_temp_tl { \int_to_base:nn { #1 } { 36 } }
\prop_put:NVV \l_ruben_digits_prop \l__ruben_temp_tl \l__ruben_temp_tl
}
\ExplSyntaxOff
\definedigits{
{a}{\textturntwo},
{b}{\&} % just for showing the syntax
}
\begin{document}
\convertdec[12]{131}
\end{document}
请注意,这不需要特殊保护。数字被初始化为0123456789abc
等。要更改特定数字,请使用括号对(例如{c}{C}
在 的参数中)\definedigits
,用逗号分隔括号对,如示例中所示。