我有以下定义:
\newcount\tmpcounta
\def\convertletter#1{%
\tmpcounta `#1\relax
\ifnum\tmpcounta<`a{%
\ifnum\tmpcounta<`A{%
#1%
}\else{%
\ifnum\tmpcounta>`Z{%
#1%
}\else{%
\advance\tmpcounta by -`A\relax
\advance\tmpcounta by 26\relax
\number\tmpcounta-%
}\fi
}\fi
}\else{%
\ifnum\tmpcounta>`z{%
#1%
}\else{%
\advance\tmpcounta by -`a\relax
\number\tmpcounta-%
}\fi
}\fi
}
以及以下代码片段
\usepackage{tikz}% for "foreach" and because I ultimately use it to draw stuff
\def\mylist#1{%
\foreach \myitem in {#1} {%
(\expandafter\convertletter\myitem)
}
}
\mylist{a8,f12}
\usepackage{tikz}
\def\mylist#1{%
\foreach \myitem in {#1} {%
\edef\myitem{\expandafter\convertletter\myitem}%
(\myitem)
}
}
\mylist{a8,f12}
我最终想进一步处理结果\expandafter\convertletter\myitem
。这就是我尝试将其保存在宏中的原因。但似乎我从根本上误解了宏扩展(尤其是\edef
)在 TeX 中的工作方式。
有没有办法保存中间结果以便将其用作其他宏的输入?
答案1
TeX 中的条件语法不是使用括号。你应该说
\ifnum\tmpcnta<`a
do something
\else
do something else
\fi
无论如何,您的\convertletter
宏使用赋值,因此它不能在中使用\edef
。
这是一个expl3
完全可扩展的实现。
\documentclass{article}
\usepackage{tikz}
\ExplSyntaxOn
\NewExpandableDocumentCommand{\convertletter}{m}
{
\mdm_convertletter:N #1
}
\cs_new:Nn \mdm_convertletter:N
{
\bool_if:nTF { \int_compare_p:n { `a <= `#1 <= `z } || \int_compare_p:n { `A <= `#1 <= `Z } }
{
\int_eval:n { \int_from_alph:n { #1 } - 1 } -
}
{
#1
}
}
\ExplSyntaxOff
\newcommand{\mylist}[1]{%
\foreach \x in {#1} {%
\edef\myitem{\expandafter\convertletter\x}%
(\myitem)%
}
}
\begin{document}
\mylist{a8,f12,111}
\end{document}
一个“经典”的实现是
\newcommand\convertletter[1]{%
\ifnum`#1<`a
\ifnum`#1<`A
#1%
\else
\ifnum`#1>`Z
#1%
\else
\the\numexpr`#1-`A-26\relax-%
\fi
\fi
\else
\ifnum`#1>`z
#1%
\else
\the\numexpr`#1-`a\relax-%
\fi
\fi
}
您来决定哪一个更容易。
我们可以使用“布尔表达式”。如果 的字符代码介于和的字符代码之间,\bool_if:nTF
则谓词形式返回 true ;连接词表示“或”。该函数与大小写无关,对于或,返回 1;对于或,返回 2,依此类推。\int_compare_p:n { `a <= `#1 <= `z }
#1
a
z
||
\int_from_alph:n
a
A
b
B
答案2
您可以\convertletter
使用\isinrange
辅助宏来定义宏。语法为\isinrange
:
\isinrange X(a-z)\iftrue Yes, X is in a-z\else No, X isn't in a-z\fi
那么\convertleter
宏定义就更加简单了:
\def\isinrange #1(#2-#3)\iftrue{%
\ifnum 1=\numexpr 0%
\ifnum`#1<\numexpr`#3+1\relax
\ifnum`#1>\numexpr`#2-1\relax 1\fi\fi \relax
}
\def\convertletter#1{%
\isinrange#1(a-z)\iftrue \the\numexpr`#1-`a\relax-%
\else \isinrange#1(A-Z)\iftrue \the\numexpr`#1-`A-26\relax-%
\else #1%
\fi\fi
}
使用 TeX 进行编程是一种乐趣。