我正在尝试在LaTeX中编写一个命令,它接受一个字符串,例如8:00A,并将其转换为分钟数,作为使用TikZ绘制课程表的脚本的一部分.但是,我遇到了一些问题 - 似乎LaTeX实际上并没有评估命令的内容.
我的命令目前是:
\newcommand{\timetominutes}[1]{
\IfSubStr{#1}{P}{720}{0}+\IfSubStr{#1}{P}{\StrBetween{#1}{:}{P}}{\StrBetween{#1}{:}{A}}+60*\StrBefore{#1}{:}
}
Run Code Online (Sandbox Code Playgroud)
如果从中打印出文本,它将正确计算从午夜开始的分钟数.但是,如果在另一个函数中使用,很明显它实际上并不运行任何这些命令 - 它只返回包含那些命令的文本.所以,如果我写:
\myfunc{\timetominutes{8:00A}}
Run Code Online (Sandbox Code Playgroud)
它看到了,而不是\myfunc看到有用的东西.这对我来说绝对没用,我无法找到一种方法来强制LaTeX在主要命令之前执行子命令.我假设有一种方法可以做到,但是LaTeX文档很少,我似乎找不到任何东西.0+00+60*8\IfSubStr{8:00A}{P}{720}{0}+\IfSubStr{8:00A}{P}{\StrBetween{8:00A}{:}{P}}{\StrBetween{8:00A}{:}{A}}+60*\StrBefore{8:00A}{:}
或者,如果有办法让LaTeX停止抱怨太多}s(当我有正确的数字时),那可能会有效.
很不幸的是,不行。正如xstring包所述:
该包的宏不是纯粹可扩展的
(xtring_doc_en.pdf 第 3.2 节。)
如果您不熟悉的话,这个“可扩展”概念在 TeX 中是一个相当棘手的主题。简而言之,不可扩展的东西不能被评估为参数。在大多数 TeX 变体中,任何在某处使用赋值的东西都保证不可扩展,但也存在其他不可扩展的触发器。对于不熟悉 TeX“嘴”(TeX 中处理扩展等事务的部分)内部工作原理的人来说,解决此类问题相当困难。
提示:如果 LaTeX 代码是由脚本生成的:使用脚本来转换时间表达式,因为在字符串操作方面几乎任何编程语言都比 TeX 更容易使用。(或者任何其他与此相关的事情。)
xstring包确实暗示了一种出路:您可以通过添加到调用末尾来将大多数操作的结果存储在变量中。[\variable]这意味着您需要重写\timetominutes一些内容来逐步构建结果,然后将该结果存储在命令序列中以供稍后使用。
用法:
\timetominutesinto\somevar{8:00A} % \somevar contains 48
\expandafter\myfunc\expandafter{\somevar} % calls \myfunc{48}
Run Code Online (Sandbox Code Playgroud)
请注意 的使用,它告诉 TeX在下一个命令序列之后\expandafter对命令序列进行简单的一级扩展(评估)。如果您没有使用这两个s,您将得到, not的参数。\expandafter\somevar\myfunc48
(注意:前面是丑陋的 TeX 代码!)
\makeatletter % allow @ in command names
\def\timetominutesinto#1#2{%
% #1 = command to store the result in
% #2 = the text to parse
% \ttm@tempa and \ttm@tempb are temporary variables for this macro
\let\ttm@tempa\empty % make the command empty
\IfSubStr{#2}{P}{%
\def\ttm@tempa{720+}% set tempa to "720+"
\StrBetween{#2}{:}{P}[\ttm@tempb]% store substring between : and P into tempb
\edef\ttm@tempa{\ttm@tempa \ttm@tempb}% set tempa to tempa + tempb
}{%
\def\ttm@tempa{0+}% set tempa to 0+
\StrBetween{#2}{:}{A}[\ttm@tempb]% store substring between : and A into tempb
\edef\ttm@tempa{\ttm@tempa \ttm@tempb}% set tempa to tempa + tempb
}%
\edef\ttm@tempa{\ttm@tempa+60*}% set tempa to tempa + "+60*"
\StrBefore{#2}{:}[\ttm@tempb]% store substring before : into tempb
% now, set #1 to the result of evaluating the formula returned by concatenating
% tempa and tempb
\edef#1{\numexpr \ttm@tempa \ttm@tempb}%
}
Run Code Online (Sandbox Code Playgroud)
\def\newcommand是对应于 LaTeX 的/的 TeX 原语\renewcommand。\edef表示 Expanding \def,它在将结果分配给命令序列之前评估定义。\numexpr计算一个简单的数字表达式,例如由上面的命令创建的x + m + h * 60。
还可以通过使用整数算术立即将结果计算为数字,而无需建立公式。但这会使代码更加偏离您的初衷。
可以通过 TeX 本身进行这些字符串操作,而无需使用xstring包(在这种特殊情况下甚至是可扩展的)。但这是相当低级的东西,如果您不是 TeX 专家,就很难重复。