2010-10-25 54 views
5

我想在LaTeX中编写一个命令,它需要一个字符串如8:00A,并将其转换为分钟数,作为使用TikZ绘制课程计划的脚本的一部分。然而,我遇到了一些问题 - 看起来LaTeX实际上并没有评估一个命令的内容。LaTeX立即评估

我的命令是目前:

\newcommand{\timetominutes}[1]{ 
    \IfSubStr{#1}{P}{720}{0}+\IfSubStr{#1}{P}{\StrBetween{#1}{:}{P}}{\StrBetween{#1}{:}{A}}+60*\StrBefore{#1}{:} 
} 

如果您打印输出的文字时,它会正确计算从午夜的分钟数。但是,如果在另一个函数中使用,显然它不会实际上运行这些命令中的任何一个 - 它只是返回包含这些命令的文本。所以,如果我写:

\myfunc{\timetominutes{8:00A}} 

而不是\myfunc看到类似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在主要命令之前执行子命令。我认为有办法做到这一点,但LaTeX文档很少,我似乎无法找到任何东西。

或者,如果有办法让LaTeX停止抱怨太多}(当我有正确的号码时),那可以工作。

+2

为什么在世界上你想在LaTeX内部做到这一点?你可以写一些其他语言的脚本来读取字符串,处理,然后输出到TikZ。 – 2010-10-25 17:35:46

+0

听起来像luatex的工作。对不起,我无法在Lua中提供解决方案。我相信别人可以。 – Mica 2010-10-25 17:59:27

+0

我受到TikZ语法的可扩展性的启发,并认为我可以创建类似可扩展的东西。事实证明,我错了。 – Ethan 2010-10-25 18:11:18

回答

3

不幸的是,没有。由于xstring包状态:

这个包的宏并不是纯粹的扩张

(第3.2节xtring_doc_en.pdf的。)

这种 “扩张” 的概念,如果你不熟悉它,在TeX中是一个相当多的主题。简而言之,不可扩展的东西不能作为一个参数进行评估。任何在某处使用赋值的东西都可以保证在大多数TeX变种中不可扩展,但也存在其他不可扩展的触发器。对于那些不熟悉TeX的“嘴”(TeX处理扩展的部分)的内部工作的人来说,解决这些问题是相当困难的。

提示:如果是由脚本生成的LaTeX的代码:使用脚本转换的时间表达式,因为几乎所有的编程语言更容易,当涉及到字符串操作比TeX的使用。 (或者是任何其他为此事)。


xstring包并暗示出路:可以存储在变量中的大多数操作的结果,通过增加[\variable]到的结束调用。这意味着您需要重写\timetominutes以逐个构建结果,然后将结果存储在命令序列中供稍后使用。

用法:

\timetominutesinto\somevar{8:00A} % \somevar contains 48 
\expandafter\myfunc\expandafter{\somevar} % calls \myfunc{48} 

注使用\expandafter,它告诉的TeX到下一后做的命令序列的一个简单的单级膨胀(评价)。如果您没有使用两个\expandafter s,您会得到\somevar作为\myfunc的参数,而不是48

\makeatletter % allow @ in command names 
\def\timetominutesinto#1#2{% 
    % #1 = command to store the result in 
    % #2 = the text to parse 
    % \[email protected] and \[email protected] are temporary variables for this macro 
    \let\[email protected]\empty % make the command empty 
    \IfSubStr{#2}{P}{% 
    \def\[email protected]{720+}% set tempa to "720+" 
    \StrBetween{#2}{:}{P}[\[email protected]]% store substring between : and P into tempb 
    \edef\[email protected]{\[email protected] \[email protected]}% set tempa to tempa + tempb 
    }{% 
    \def\[email protected]{0+}% set tempa to 0+ 
    \StrBetween{#2}{:}{A}[\[email protected]]% store substring between : and A into tempb 
    \edef\[email protected]{\[email protected] \[email protected]}% set tempa to tempa + tempb 
    }% 
    \edef\[email protected]{\[email protected]+60*}% set tempa to tempa + "+60*" 
    \StrBefore{#2}{:}[\[email protected]]% store substring before : into tempb 
    % now, set #1 to the result of evaluating the formula returned by concatenating 
    % tempa and tempb 
    \edef#1{\numexpr \[email protected] \[email protected]}% 
} 

\def是TeX的原始对应的LaTeX的\newcommand/\renewcommand(注意提前丑陋的TeX的代码!)。 \edef表示扩展\def,它在将结果分配给命令序列之前对其定义进行评估。 \numexpr评估简单数字表达式,如x + m + h * 60通过上述命令创建。

也可以使用整数运算,立即将结果计算为数字,而不用建立公式。但是这会使代码更加偏离您的原意。

可以通过TeX本身进行这些字符串操作,而不使用xstring包(在这种情况下甚至可以扩展)。但这是相当低层次的东西,如果你不是TeX wizzard,那么这些东西不能轻易重复。

+0

LaTeX代码不会由脚本生成,但此时我认为在C#中编写解析代码并将其用于生成会更容易。幸运的是,这将是整个LaTeX文档中唯一的项目,所以我可以直接打印来自C#的代码并编译它。不过,我很好奇,至于这种事情是如何起作用的 - 你能推荐任何书籍或网站,它们是对LaTeX的综合指南,特别是在LaTeX中进行编程吗? – Ethan 2010-10-25 18:02:12

+0

D.E.的TeXbook(Computers and Typesetting,Part A) Knuth仍然是学习TeX内幕的最佳资源之一。接下来,LaTeX Companion可能是倾斜LaTeX事物的好资源。请注意,CTAN上还有很多信息。 – Ruben 2010-10-25 21:16:45

2

我是PerlTeX在LaTeX中编程交互的忠实粉丝。使用Perl来定义函数通常比TeX中的编程更容易,而对于更多的编程操作,它可以更加强大。 PerlTeX为您提供了perl和latex之间的双向通信,这意味着您可以在LaTeX源代码中嵌入Perl代码片段,而不必编写一个脚本来创建整个源文件。

这里是你想要的一个例子。编译为perltex --latex=pdflatex test.tex,文件已保存为test.tex,您可以省略可选的--latex=pdflatex以生成dvi。

\documentclass{article} 
\usepackage{perltex} 

\perlnewcommand{\timetominutes}[1]{ 
    #Argument is [h]h:mm[ ][a/p[m]] ie 8:00am or 4:05 P or 15:30 (24hr fmt) 
    my $input = shift; 
    my ($hours, $minutes, $AMPM) = $input =~ /(\d+)\:(\d+)\ *(\w*)/; 
    if ($AMPM =~ /p/i) { 
    $hours += 12; 
    } elsif ($AMPM =~ /a/i and $hours == 12) { 
    $hours = 0; 
    } 
    my $numberofminutes = 60*$hours + $minutes; 
    return $numberofminutes; 
    ## or you could 
    # return '\myfunc{' . $numberofminutes . '}'; 
    ## or simply 
    # return "\\myfunc\{$numberofminutes\}"; 
    ## I can't remember if you need to escape the curly braces 
} 

\begin{document} 

It has been \timetominutes{8:00 pm} minutes since midnight. 

\end{document} 

至于扩张去,如果你仍然有\ MYFUNC问题,不管它是什么,你可以定义它或它作为一个perltex功能的包装功能或使用提供的备用回报。