正如标题所暗示的,本质上我想将数字转换为字母,并且此主题在解决这个问题上做得非常出色。
egreg 给出了一个很好的解决方案,我一直在研究它,但是尽管我研究了可以找到的相关文档,我似乎无法调整他的解决方案以输出 0=A,而不是 1=A。
这是我正在尝试使用的 egreg 解决方案之一:
\newcommand\makeAlph[1]{%
\ifcase #1\or a\or b\or c\or d\or e\or f\or g\or h\or
i\or j\or k\or l\or m\or n\or o\or p\or q\or r\or
s\or t\or u\or v\or w\or x\or y\or z\fi}
我是否可以轻松地以这种方式进行调整,或者是否有更好的解决方案适合我的具体用例?这感觉像是一件非常简单的事情,但我似乎无法确定它。
我很乐意探索任何其他提议的路线,或者在需要时提供更多细节(尽管这看起来很简单)。
谢谢!
(我也提出了相反的问题稍后介绍如何将字母转换为数字。)
答案1
语法\ifcase
是
\ifcase <number>
% case 0
\or % case 1
\or % case 2
...
\else % other cases
\fi
因此,最简单的更改是放入a
而case 0
不是放入case 1
,因此只需删除第一个\or
(但使用下一个选项):
\newcommand\makeAlph[1]{%
\ifcase #1 a\or b\or c\or d\or e\or f\or g\or h\or
i\or j\or k\or l\or m\or n\or o\or p\or q\or r\or
s\or t\or u\or v\or w\or x\or y\or z\fi}
您可以使其更安全一些,并且还可以使用以下方法接受数值表达式(类似于2+2
)作为参数\numexpr
:
\newcommand\makeAlph[1]{%
\ifcase\numexpr#1\relax a\or b\or c\or d\or e\or f\or g\or h\or
i\or j\or k\or l\or m\or n\or o\or p\or q\or r\or
s\or t\or u\or v\or w\or x\or y\or z\fi}
答案2
有多种方法可以实现。一种“较新”的方法是用expl3
,它有\int_to_alph:n
,它接受参数中的表达式。
但是,此函数返回的字母组合值大于 26,而您并不想出现这种情况。很简单:添加一个可接受范围的测试。
\documentclass{article}
\ExplSyntaxOn
\NewExpandableDocumentCommand{\makeAlph}{m}
{
\int_compare:nTF { 0 <= #1 <= 25 }
{
\int_to_alph:n { #1 + 1 }
}
{
Bummer!
}
}
\ExplSyntaxOff
\begin{document}
\makeAlph{0}--\makeAlph{25}
\makeAlph{26}
\end{document}
如果您希望命令忽略超出范围的值,
\ExplSyntaxOn
\NewExpandableDocumentCommand{\makeAlph}{m}
{
\int_compare:nT { 0 <= #1 <= 25 } { \int_to_alph:n { #1 + 1 } }
}
\ExplSyntaxOff
本质上是一行代码。
答案3
这是我LuaLaTeX
基于的解决方案。我喜欢它是Lua
因为Python
我首选的脚本语言,而且它在语法上有很多相似之处。我很容易在心理上区分和管理编码和排版的内容。如果您想包含错误检查/抛出,例如,如果用户将 -1、28 或“alpha”传递给函数/命令,则建议的解决方案应该很容易扩展。
\documentclass{letter}
\usepackage{luacode}
\begin{luacode*}
function num2let(arg)
local argInt = tonumber(arg)
if argInt ~= nil then
if (0 <= argInt) and (argInt <= 25) then
tex.print(string.char(65 + argInt))
end -- can put an else statement for error tracking
end -- can put an else statement for error tracking
end
\end{luacode*}
\newcommand{\NumToLet}[1]{\directlua{num2let(#1)}}
\begin{document}
Valid: \NumToLet{0}\NumToLet{1}...\NumToLet{25}
Invalid: \NumToLet{-1}, \NumToLet{26}, \NumToLet{alpha}
\end{document}
答案4
我可以提供一个宏
\ExtractKthArg{⟨TeX-⟨number⟩-quantity with integer-value K⟩}%
{⟨tokens in case list of undelimited arguments doesn't have a k-th argument⟩}%
{⟨list of undelimited arguments⟩}%
其作用如下:
如果没有⟨K⟩-th 参数⟨无界参数列表⟩:
是否提供⟨如果未限定参数列表没有第 k 个参数,则使用 tokens⟩。
如果有⟨K⟩-th 参数⟨无界参数列表⟩:
确实实现了⟨K⟩-th 参数删除了一层括号。
例子:
\ExtractKthArg{0}{not available}{ABCDE}
产量:not available
\ExtractKthArg{3}{not available}{ABCDE}
产量: C
\ExtractKthArg{3}{not available}{AB{CD}E}
产量: CD
\ExtractKthArg{4}{not available}{{001}{002}{003}{004}{005}}
产量:004
\ExtractKthArg{6}{not available}{{001}{002}{003}}
产量:not available
您可以轻松地定义 \makeAlph
如下内容\ExtractKthArg
:
\newcommand\makeAlph[2]{%
\ExtractKthArg{\number\numexpr#1+1\relax}{#2}{abcdefghijklmnopqrstuvwxyz}%
}%
这种方式\makeAlph
需要二参数,第一个参数是 TeX-⟨数字⟩-quantity 转换为字符,第二个参数表示在第一个参数不在 0..25 范围内时要传递的标记。
下面的最小工作示例仅依赖于\makeAlph
的第一个参数是 TeX-⟨数字⟩-数量。没有检查 的\makeAlph
第一个参数是否是 TeX-⟨数字⟩-quantity:第一个参数是一组标记,因此可能形成任意(基于扩展的)算法。检查执行此类算法的结果是否产生 TeX-⟨数字⟩-quantity 包括检查这种算法是否完全终止/终止时没有错误消息。这反过来让我想起了停机问题 ...
!!!\makeAlph
的第一个参数不是 TeX-⟨数字⟩-数量可能会导致各种不可预测的行为,从而导致难以理解的错误消息!!!
以下是最小的工作示例:
\errorcontextlines=10000
\documentclass{article}
\makeatletter
%% Code for \ExtractKthArg
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond, \UD@Exchange,
%% \UD@stopromannumeral, \UD@CheckWhetherNull
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{%
\expandafter\UD@stopromannumeral\UD@firstoftwo}%
}%
%%=============================================================================
%% Extract K-th inner undelimited argument:
%%
%% \ExtractKthArg{<integer K>}%
%% {<tokens in case list of undelimited arguments doesn't have a k-th argument>}%
%% {<list of undelimited arguments>}%
%%
%% In case there is no K-th argument in <list of indelimited arguments> :
%% Does deliver <tokens in case list of undelimited arguments doesn't have a k-th argument.
%% In case there is a K-th argument in <list of undelimited arguments> :
%% Does deliver that K-th argument with one level of braces removed.
%%
%% Examples:
%%
%% \ExtractKthArg{0}{not available}{ABCDE} yields: not available
%%
%% \ExtractKthArg{3}{not available}{ABCDE} yields: C
%%
%% \ExtractKthArg{3}{not available}{AB{CD}E} yields: CD
%%
%% \ExtractKthArg{4}{not available}{{001}{002}{003}{004}{005}} yields: 004
%%
%% \ExtractKthArg{6}{not available}{{001}{002}{003}} yields: not available
%%
%%=============================================================================
\newcommand\ExtractKthArg[2]{%
\romannumeral%
% #1: <integer number K>
% #2: <action if there is no K-th argument>
\expandafter\UD@ExtractKthArgCheck
\expandafter{\romannumeral\number\number#1 000}{#2}%
}%
\newcommand\UD@ExtractKthArgCheck[3]{%
\UD@CheckWhetherNull{#1}{\UD@stopromannumeral#2}{% empty
\expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}#1}{#2}{#3}%
}%
}%
\begingroup
\def\UD@ExtractFirstArgLoop#1{%
\endgroup
\@ifdefinable\UD@RemoveTillFrozenrelax{%
\long\def\UD@RemoveTillFrozenrelax##1##2#1{{##1}}%
}%
\newcommand\UD@ExtractKthArgLoop[3]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo##3{}.}{\UD@stopromannumeral##2}{%
\UD@CheckWhetherNull{##1}{%
\UD@ExtractFirstArgLoop{##3#1}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}##3}%
{\expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}##1}{##2}}%
}%
}%
}%
}%
\expandafter\expandafter\expandafter\UD@ExtractFirstArgLoop
\expandafter\expandafter\expandafter{%
\expandafter\expandafter\ifnum0=0\fi}%
%% Usage of frozen-\relax as delimiter is for speeding things up by reducing the
%% amount of iterations needed. I chose frozen-\relax because David Carlisle
%% pointed out in <https://tex.stackexchange.com/a/578877>
%% that frozen-\relax cannot be (re)defined in terms of \outer and cannot be
%% affected by \uppercase/\lowercase.
%%
%% \UD@ExtractFirstArg's argument may contain frozen-\relax:
%% The only effect is that internally more iterations are needed for
%% obtaining the result.
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{\expandafter\UD@stopromannumeral\UD@firstoftwo#1{}}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillFrozenrelax#1}}%
}%
%% End of code for \ExtractKthArg.
\makeatother
\newcommand\makeAlph[2]{%
\ExtractKthArg{\number\numexpr#1+1\relax}{#2}{abcdefghijklmnopqrstuvwxyz}%
}%
\begin{document}
\noindent
\verb|\makeAlph{0}{\makeAlpherrordefault}| yields: \makeAlph{0}{\makeAlpherrordefault}\\
\verb|\makeAlph{1}{\makeAlpherrordefault}| yields: \makeAlph{1}{\makeAlpherrordefault}\\
\verb|\makeAlph{2}{\makeAlpherrordefault}| yields: \makeAlph{2}{\makeAlpherrordefault}\\
\verb|\makeAlph{3}{\makeAlpherrordefault}| yields: \makeAlph{3}{\makeAlpherrordefault}\\
\verb|\makeAlph{4}{\makeAlpherrordefault}| yields: \makeAlph{4}{\makeAlpherrordefault}\\
\verb|\makeAlph{5}{\makeAlpherrordefault}| yields: \makeAlph{5}{\makeAlpherrordefault}\\
\verb|\makeAlph{6}{\makeAlpherrordefault}| yields: \makeAlph{6}{\makeAlpherrordefault}\\
\verb|\makeAlph{7}{\makeAlpherrordefault}| yields: \makeAlph{7}{\makeAlpherrordefault}\\
\verb|\makeAlph{8}{\makeAlpherrordefault}| yields: \makeAlph{8}{\makeAlpherrordefault}\\
\verb|\makeAlph{9}{\makeAlpherrordefault}| yields: \makeAlph{9}{\makeAlpherrordefault}\\
\verb|\makeAlph{10}{\makeAlpherrordefault}| yields: \makeAlph{10}{\makeAlpherrordefault}\\
\verb|\makeAlph{11}{\makeAlpherrordefault}| yields: \makeAlph{11}{\makeAlpherrordefault}\\
\verb|\makeAlph{12}{\makeAlpherrordefault}| yields: \makeAlph{12}{\makeAlpherrordefault}\\
\verb|\makeAlph{13}{\makeAlpherrordefault}| yields: \makeAlph{13}{\makeAlpherrordefault}\\
\verb|\makeAlph{14}{\makeAlpherrordefault}| yields: \makeAlph{14}{\makeAlpherrordefault}\\
\verb|\makeAlph{15}{\makeAlpherrordefault}| yields: \makeAlph{15}{\makeAlpherrordefault}\\
\verb|\makeAlph{16}{\makeAlpherrordefault}| yields: \makeAlph{16}{\makeAlpherrordefault}\\
\verb|\makeAlph{17}{\makeAlpherrordefault}| yields: \makeAlph{17}{\makeAlpherrordefault}\\
\verb|\makeAlph{18}{\makeAlpherrordefault}| yields: \makeAlph{18}{\makeAlpherrordefault}\\
\verb|\makeAlph{19}{\makeAlpherrordefault}| yields: \makeAlph{19}{\makeAlpherrordefault}\\
\verb|\makeAlph{20}{\makeAlpherrordefault}| yields: \makeAlph{20}{\makeAlpherrordefault}\\
\verb|\makeAlph{21}{\makeAlpherrordefault}| yields: \makeAlph{21}{\makeAlpherrordefault}\\
\verb|\makeAlph{22}{\makeAlpherrordefault}| yields: \makeAlph{22}{\makeAlpherrordefault}\\
\verb|\makeAlph{23}{\makeAlpherrordefault}| yields: \makeAlph{23}{\makeAlpherrordefault}\\
\verb|\makeAlph{24}{\makeAlpherrordefault}| yields: \makeAlph{24}{\makeAlpherrordefault}\\
\verb|\makeAlph{25}{\makeAlpherrordefault}| yields: \makeAlph{25}{\makeAlpherrordefault}
\bigskip
\noindent
\verb|\newcounter{scratchcounter}|\newcounter{scratchcounter}\\
\verb|\setcounter{scratchcounter}{12}|\setcounter{scratchcounter}{12}\\
\verb|\makeAlph{\value{scratchcounter}}{\makeAlpherrordefault}| yields: \makeAlph{\value{scratchcounter}}{\makeAlpherrordefault}
\bigskip
\noindent
% \makeAlpherrordefault delivers an error-message. Instead we want the phrase "Error-Tokens".
% \verb|\makeAlph{-1}{\makeAlpherordefault}| yields: \makeAlph{-1}{\makeAlpherordefault}\\
\verb|\makeAlph{-1}{Error-Tokens.}| yields: \makeAlph{-1}{Error-Tokens.}\\
% \verb|\makeAlph{26}{\makeAlpherrordefault}| yields: \makeAlph{26}{\makeAlpherrordefault}\\
\verb|\makeAlph{26}{Error-Tokens.}| yields: \makeAlph{26}{Error-Tokens.}
\bigskip
\noindent
\verb|\setcounter{scratchcounter}{28}|\setcounter{scratchcounter}{28}\\
%\verb|\makeAlph{\value{scratchcounter}}{\makeAlpherrordefault}| yields: \makeAlph{\value{scratchcounter}}{\makeAlpherrordefault}\\
\verb|\makeAlph{\value{scratchcounter}}{Error-Tokens.}| yields: \makeAlph{\value{scratchcounter}}{Error-Tokens.}
\end{document}