Latex 乳胶即时评价

Latex 乳胶即时评价,latex,Latex,我正在尝试用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}{:}

我正在尝试用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}{:}
}
如果您从中打印文本,它将正确计算从午夜开始的分钟数。然而,如果在另一个函数中使用,很明显,它实际上并不运行这些命令中的任何一个——它只返回包含这些命令的文本。所以如果我写:

\myfunc{\timetominutes{8:00A}}
它没有看到像
0+00+60*8
这样有用的东西,而是看到
\IfSubStr{8:00A}{p}{720}{0}+\IfSubStr{8:00A}{p}{\strb{8:00A}{p}{p}}{p}{。这对我来说是完全无用的,我无法找到一种方法来强制LaTeX在主命令之前执行子命令。我想有办法做到这一点,但LaTeX文档很少,我似乎找不到任何东西


或者,如果有一种方法可以让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}
注意
\expandafter
的用法,它告诉TeX在下一个命令序列之后对命令序列进行简单的一级扩展(评估)。如果不使用这两个
\expandafter
s,则会将
\somevar
作为
\myfunc
的参数,而不是
48

(注意:前面是丑陋的TeX代码!)

\def
是与LaTeX的
\newcommand
/
\renewcommand
相对应的TeX原语
\edef
表示展开
\def
,它在将结果分配给命令序列之前评估定义
\numexpr
计算一个简单的数字表达式,如上面的命令创建的x+m+h*60

通过使用整数运算,也可以在不建立公式的情况下立即将结果计算为数字。但这会使代码更加远离您的原始意图


可以通过TeX本身执行这些字符串操作,而无需使用
xstring
包(在这种特殊情况下甚至可以扩展)。但这是相当低级的东西,如果你不是TeX wizzard,就很难重复。

我非常喜欢PerlTeX在LaTeX中进行编程交互。使用Perl do define函数通常比用TeX编程更容易,而且对于更多的编程操作,它可以更强大。PerlTeX为您提供了perl和latex之间的双向通信,这意味着您可以在latex源代码中嵌入perl代码片段,而不必编写创建整个源文件的脚本

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

\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函数,或使用提供的备用返回。

您到底为什么要在LaTeX中执行此操作?您可以用其他语言编写一个脚本来读取字符串、处理,然后输出到TikZ。听起来像luatex的工作。很抱歉,我无法在Lua中提供解决方案。我相信其他人也可以。我受到TikZ语法可扩展性的启发,认为我可以创建类似的可扩展性。事实证明,我错了。@Mica,我仍然对luatex感到困惑,我一直在用TeX编程,但我认为它仍然比典型的用户交互更深刻。在我找到答案之前,我将继续使用PerlTeX(见下面的答案),但如果能够摆脱包装器编译器那就太好了。LaTeX代码不是由脚本生成的,但在这一点上,我认为用C#编写解析代码并将其用于生成会更容易。幸运的是,这将是整个LaTeX文档中的唯一项目,因此我可以直接从C#打印代码并编译它。不过,我很好奇,关于这类事情是如何运作的——你能推荐一些全面指导LaTeX的书籍或网站吗?特别是LaTeX编程的书籍或网站吗?D.E.Knuth的TeXbook(计算机和排版,A部分)仍然是学习TeX内部知识的最佳资源之一。接下来,乳胶伴侣可能是一个很好的资源来倾斜L
\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}