2010-10-25 51 views
5

Tôi đang cố gắng viết một lệnh trong LaTeX lấy một chuỗi như 8: 00A và chuyển đổi nó thành số phút, như một phần của tập lệnh để vẽ lịch học bằng TikZ. Tuy nhiên, tôi đang gặp một số vấn đề - có vẻ như LaTeX không thực sự đánh giá nội dung của một lệnh.Đánh giá ngay lập tức LaTeX

lệnh của tôi hiện là:

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

Nếu bạn in ra văn bản từ nó, nó sẽ tính toán một cách chính xác số phút từ nửa đêm. Tuy nhiên, nếu được sử dụng bên trong một hàm khác, nó trở nên rõ ràng rằng nó không thực hiện thực sự chạy bất kỳ lệnh nào trong số đó - nó chỉ trả về văn bản bao gồm các lệnh đó. Vì vậy, nếu tôi viết:

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

Thay vì \myfunc nhìn thấy một cái gì đó hữu ích như 0+00+60*8, nó thấy \IfSubStr{8:00A}{P}{720}{0}+\IfSubStr{8:00A}{P}{\StrBetween{8:00A}{:}{P}}{\StrBetween{8:00A}{:}{A}}+60*\StrBefore{8:00A}{:}. Điều này hoàn toàn vô dụng đối với tôi và tôi không thể nhìn thấy để tìm cách buộc LaTeX thực hiện các lệnh con trước phiên bản chính. Tôi cho rằng có một cách để làm điều đó, nhưng tài liệu LaTeX khan hiếm và tôi dường như không tìm thấy gì cả.

Ngoài ra, nếu có cách nào để LaTeX ngừng phàn nàn về quá nhiều } s (khi tôi có số chính xác), điều đó có thể hoạt động.

+2

Tại sao bạn muốn thực hiện điều này trong LaTeX? Bạn có thể viết một kịch bản bằng một số ngôn ngữ khác để đọc chuỗi, xử lý, sau đó xuất ra TikZ. –

+0

giống như một công việc cho luatex. Tôi xin lỗi tôi không thể cung cấp một giải pháp trong Lua. Tôi chắc rằng người khác có thể mặc dù. – Mica

+0

Tôi lấy cảm hứng từ khả năng mở rộng cú pháp của TikZ và nghĩ rằng tôi có thể tạo ra một thứ tương tự như vậy. Khi nó quay ra, tôi đã sai. – Ethan

Trả lời

3

Thật không may, không. Khi xstring bang gói:

Các macro của gói này không phải là hoàn toàn có thể mở rộng

(Phần 3.2 của xtring_doc_en.pdf.)

"mở rộng" Khái niệm này, nếu bạn 'không quen thuộc với nó, là một chủ đề khá nhiều trong TeX. Nói một cách đơn giản, cái gì đó không thể mở rộng không thể được đánh giá như một đối số. Bất cứ điều gì sử dụng một bài tập ở đâu đó được đảm bảo không thể mở rộng được trong hầu hết các giống TeX, nhưng các trình kích hoạt không mở rộng khác cũng tồn tại. Giải pháp cho các vấn đề như vậy là khá khó khăn đối với bất kỳ ai không quen thuộc với các hoạt động bên trong của "miệng" TeX (một phần của TeX xử lý những thứ như mở rộng).

Gợi ý: Nếu mã LaTeX được tạo bởi tập lệnh: sử dụng tập lệnh để chuyển đổi biểu thức thời gian, vì mọi ngôn ngữ lập trình đều dễ sử dụng hơn TeX khi nói đến thao tác chuỗi. (Hoặc chỉ là về bất cứ điều gì khác cho rằng vấn đề.)


Các xstring gói không gợi ý tại một lối thoát: Bạn có thể lưu trữ các kết quả của hầu hết các hoạt động trong một biến, bằng cách thêm [\variable] đến khi kết thúc cuộc gọi. Điều này có nghĩa là bạn cần phải viết lại \timetominutes vào thứ gì đó tích hợp từng mảnh kết quả, sau đó lưu trữ kết quả đó trong một chuỗi lệnh để sử dụng sau này.

Cách sử dụng:

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

Lưu ý việc sử dụng \expandafter, mà nói với TeX để làm một mở rộng một cấp đơn giản (đánh giá) của một chuỗi lệnh sau tiếp theo.Nếu bạn không sử dụng hai số \expandafter, bạn sẽ nhận được \somevar làm đối số cho \myfunc, chứ không phải 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 là TeX nguyên thủy tương ứng với LaTeX của \newcommand/\renewcommand (Chú ý xấu xí đang TeX trước!). \edef nghĩa là Mở rộng \def, đánh giá định nghĩa trước khi gán kết quả cho chuỗi lệnh. \numexpr đánh giá một biểu thức số đơn giản, như x + m + h * 60 được tạo bởi lệnh ở trên.

Cũng có thể tính kết quả ngay lập tức dưới dạng số, không xây dựng công thức, bằng cách sử dụng số học số nguyên. Nhưng điều đó sẽ làm cho mã thậm chí còn xa hơn so với ý định ban đầu của bạn.

Có thể thực hiện các thao tác chuỗi này thông qua chính TeX mà không cần sử dụng gói xstring (thậm chí có thể mở rộng trong trường hợp cụ thể này). Nhưng đó là công cụ cấp độ khá thấp, không thể lặp lại dễ dàng nếu bạn không phải là một trận bão tuyết TeX.

+0

Mã LaTeX sẽ không được tạo ra bởi một tập lệnh, nhưng tại thời điểm này tôi nghĩ sẽ dễ dàng hơn khi viết mã phân tích cú pháp trong C# và sử dụng nó để tạo. May mắn thay, đây sẽ là mục duy nhất trong toàn bộ tài liệu LaTeX, vì vậy tôi có thể trực tiếp in mã từ C# và biên dịch nó. Mặc dù vậy, tôi rất tò mò về cách thức hoạt động của loại công việc này - bạn có thể giới thiệu bất kỳ sách hoặc trang web nào hướng dẫn toàn diện về LaTeX và đặc biệt là lập trình trong LaTeX không? – Ethan

+0

TeXbook (Máy tính và Sắp chữ, Phần A) của D.E. Knuth vẫn là một trong những nguồn lực tốt nhất để tìm hiểu bên trong của TeX. Tiếp theo, Đồng hành LaTeX có lẽ sẽ là một nguồn lực tốt để dựa vào phía LaTeX. Tâm trí bạn, có rất nhiều thông tin về CTAN là tốt. – Ruben

2

Tôi là người hâm mộ lớn của PerlTeX cho tương tác có lập trình trong LaTeX. Sử dụng Perl để định nghĩa các hàm thường dễ dàng hơn lập trình trong TeX và để thao tác nhiều chương trình hơn, nó có thể mạnh hơn rất nhiều. PerlTeX cung cấp cho bạn một liên lạc hai chiều giữa perl và latex, có nghĩa là bạn nhúng đoạn mã Perl trong nguồn LaTeX của bạn, thay vì phải viết một tập lệnh tạo toàn bộ tệp nguồn của bạn.

Dưới đây là ví dụ về những gì bạn muốn. Biên dịch với perltex --latex=pdflatex test.tex nơi tệp đã được lưu dưới dạng test.tex và bạn có thể bỏ qua tùy chọn --latex=pdflatex để tạo 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} 

Theo như mở rộng đi, nếu bạn vẫn còn có vấn đề với \ myfunc, bất cứ điều gì nó là, bạn có thể định nghĩa nó hoặc một chức năng bao bọc cho nó như là một chức năng perltex hoặc sử dụng lợi nhuận thay thế được cung cấp.

Các vấn đề liên quan