2010-10-25 12 views
5

Próbuję napisać polecenie w LaTeX, które pobiera ciąg, taki jak 8: 00A i konwertuje go na liczbę minut, jako część skryptu do narysowania harmonogramu zajęć za pomocą TikZ. Jednakże mam pewne problemy - wydaje się, że LaTeX nie ocenia zawartości polecenia.LaTeX Natychmiastowa ocena

Moje polecenie jest obecnie:

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

Jeśli wydrukować tekst z nim, to będzie poprawnie obliczyć liczbę minut od północy. Jeśli jednak zostanie użyty w innej funkcji, okaże się, że nie wykonuje żadnego z tych poleceń - po prostu zwraca tekst zawierający te polecenia. Więc jeśli piszę:

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

Zamiast \myfunc widząc coś pożytecznego jak 0+00+60*8, widzi \IfSubStr{8:00A}{P}{720}{0}+\IfSubStr{8:00A}{P}{\StrBetween{8:00A}{:}{P}}{\StrBetween{8:00A}{:}{A}}+60*\StrBefore{8:00A}{:}. Jest to całkowicie bezużyteczne dla mnie i nie widzę sposobu, aby zmusić LaTeXa do wykonywania podpoleceń przed głównym. Zakładam, że jest sposób, aby to zrobić, ale dokumentacja LaTeXa jest skąpa i nie mogę niczego znaleźć.

Alternatywnie, jeśli istnieje sposób, aby LaTeX przestał narzekać na zbyt dużą liczbę } s (gdy mam prawidłowy numer), to może zadziałać.

+2

Dlaczego na świecie chcesz to zrobić w LaTeX? Można napisać skrypt w innym języku, aby odczytać ciąg, przetwarzać, a następnie wyprowadzać do TikZ. –

+0

brzmi jak zadanie dla luatex. Przepraszam, nie mogę podać rozwiązania w Lua. Jestem pewien, że mógł to zrobić ktoś inny. – Mica

+0

Zainspirował mnie rozszerzalność składni TikZ i myśl, że mogę stworzyć coś podobnego do rozszerzenia. Jak się okazało, myliłem się. – Ethan

Odpowiedz

3

Niestety, nie. Jak xstring stanach pakiet:

makr tego pakietu nie są czysto rozszerzalna

(sekcja 3.2 xtring_doc_en.pdf.)

Ten "rozbudowy" pojęcie, jeśli ciebie "Nie jestem zaznajomiony z tym, jest dość owłosiony temat w TeX. Mówiąc prosto, czegoś, co nie jest rozszerzalne, nie można ocenić jako argumentu. Wszystko, co używa gdzieś przydziału, jest gwarantowane, że nie jest rozszerzalne w większości odmian TeX, ale istnieją również inne nierozszerzalne wyzwalacze. Rozwiązanie takich problemów jest trudne dla każdego, kto nie jest zaznajomiony z wewnętrznym działaniem "ust" TeX-a (części TeX-a, która zajmuje się ekspansją).

Podpowiedź: Jeśli kod LaTeX jest generowany przez skrypt: użyć skryptu do przekształcania wyrażeń czasu, bo prawie każdy język programowania, jest łatwiejszy w użyciu niż TeX, jeśli chodzi o ciąg manipulacji. (Lub czegokolwiek innego w tym zakresie.)


xstring pakiet ma wskazywać na wyjście: można przechowywać wynik większości operacji w zmiennej, dodając [\variable] do końca połączenia. Oznacza to, że trzeba przepisać \timetominutes na coś, co buduje wynik po fragmencie, a następnie zapisać ten wynik w sekwencji poleceń do późniejszego wykorzystania.

Zastosowanie:

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

Uwaga zastosowanie \expandafter, który mówi tex do wykonać proste rozszerzenie jednego poziomu (oceny) sekwencji poleceń po następnego.Jeśli nie użyjesz obu tych \expandafter s, otrzymasz \somevar jako argument do \myfunc, a nie 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 jest TeX prymitywny odpowiadający lateksu za \newcommand/\renewcommand (Uwaga brzydki kod TeX przodu!). \edef oznacza Rozszerzanie \def, które ocenia definicję przed przypisaniem wyniku do sekwencji poleceń. \numexpr oblicza proste wyrażenie liczbowe, takie jak x + m + h * 60 utworzone przez powyższe polecenie.

Możliwe jest również natychmiastowe obliczenie wyniku jako liczby, bez tworzenia wzoru, za pomocą arytmetycznych liczb całkowitych. Ale to uczyniłoby kod jeszcze bardziej odległym od pierwotnego zamiaru.

Możliwe jest wykonywanie tych operacji na łańcuchach za pomocą samego TeX-a, bez użycia pakietu xstring (nawet rozszerzalnego w tym konkretnym przypadku). Ale to dość niski poziom rzeczy, których nie da się łatwo powtórzyć, jeśli nie jesteś wizualizerem TeX.

+0

Kod LaTeX nie został wygenerowany przez skrypt, ale w tym momencie myślę, że łatwiej będzie napisać kod parsujący w języku C# i użyć go do generowania. Na szczęście będzie to jedyny element w całym dokumencie LaTeX, więc mogę bezpośrednio wydrukować kod z C# i skompilować go. Ciekawi mnie jednak, jak to działa - czy mógłbyś polecić jakieś książki lub strony internetowe, które są obszernymi przewodnikami do LaTeXa, a konkretnie do programowania w LaTeX? – Ethan

+0

The TeXbook (Computers and Typesetting, Part A) by D.E. Knuth pozostaje jednym z najlepszych zasobów do nauki wnętrz TeX. Następnie LaTeX Companion będzie prawdopodobnie dobrym źródłem pochylania strony LaTeX. Pamiętaj, że na CTAN również jest dużo informacji. – Ruben

2

Jestem wielkim fanem PerlTeX do programowej interakcji w LaTeX. Używanie Perla do definiowania funkcji jest często łatwiejsze niż programowanie w TeX-ie, a dla bardziej programowej manipulacji może być znacznie potężniejsze. PerlTeX zapewnia dwukierunkową komunikację między perłem i lateksem, co oznacza, że ​​osadzasz fragmenty kodu Perla w źródle LaTeX, zamiast pisać skrypt, który tworzy cały plik źródłowy.

Oto przykład tego, co chciałeś. Skompiluj z perltex --latex=pdflatex test.tex, gdzie plik został zapisany jako test.tex i możesz ominąć opcjonalne --latex=pdflatex dla generowania 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} 

O ile rozbudowa idzie, jeśli nadal mają problemy z \ myfunc, cokolwiek to jest, można go lub funkcji otoki dla niego jako funkcję perltex zdefiniować lub użyć alternatywnego zwrotu przewidziane.