LaTeX Немедленная оценка - PullRequest
       4

LaTeX Немедленная оценка

6 голосов
/ 25 октября 2010

Я пытаюсь написать команду в 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}}

Вместо \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 перестать жаловаться на слишком много } s (когда у меня будет правильный номер), это может сработать.

Ответы [ 2 ]

3 голосов
/ 25 октября 2010

К сожалению, нет.Как говорится в пакете 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 с, вы получите \somevar в качестве аргумента \myfunc, а не 48.

(Внимание! Впереди уродливый код 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}%
}

\def - это примитив TeX, соответствующий \newcommand / \renewcommand LaTeX.\edef означает Расширение \def, которое оценивает определение перед присвоением результата последовательности команд.\numexpr вычисляет простое числовое выражение, например x + m + h * 60, созданное вышеуказанной командой.

Это такжеМожно рассчитать результат сразу как число, не выстраивая формулу, используя целочисленную арифметику.Но это сделает код еще более удаленным от вашего первоначального намерения.

Эти манипуляции со строками можно выполнять через сам TeX, без использования пакета xstring (даже расширяемого в данном конкретном случае).Но это довольно низкоуровневый материал, который нельзя легко повторить, если вы не волшебник TeX.

2 голосов
/ 26 октября 2010

Я большой поклонник PerlTeX для программного взаимодействия в LaTeX. Используя Perl, определить функции часто проще, чем программировать в TeX, и для более программных манипуляций он может быть гораздо более мощным. PerlTeX предоставляет вам двустороннюю связь между perl и latex, что означает, что вы встраиваете фрагменты кода Perl в исходный код LaTeX, вместо того, чтобы писать сценарий, который создает весь ваш исходный файл.

Вот пример того, что вы хотели. Скомпилируйте с 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 или использовать предоставленные альтернативные возвращаемые значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...