最近我和一些朋友真正陷入了“让一切都可编译”的泥潭。更具体地说,我们需要做大量的 matlab 计算,然后我们需要将结果放入 tex 文档中。
最近我有点空闲,决定写一个 matlab 脚本来将值及其不确定性界限输出到一个文件中,以正确的格式输出,这样它们就可以在 LaTeX 中调用,并具有正确的有效位数等等,所以不需要动脑子。让我给你举个例子:
1)我有一个 matlab 脚本do.m
,它使用数据表单输入文件,对其进行处理并计算我想要的,比如存储在a
和 中的值b
。
2)在脚本的末尾我调用我的savefortex
脚本来保存变量a
并b
保存到一个文件中,比如说out.txt
,它看起来像这样:
\def\a{123}
\def\b{456}
3)我放入\input{out.txt}
了我的 LaTeX 文档。
4)我设置了我的 makefile,以便它知道do.m
应该调用以获取最新的out.txt
。
当需要输入大量变量时,这种方法非常方便。不过,最近我遇到了一个问题。我通常将变量及其相应的不确定性边界命名为:a
、s_a
、 b 、s_b
等。但这与 Tex 不兼容。在家试试这个
\def\s_a{10}
\def\s_b{20}
\s_a and \s_b.
这根本行不通。 同样适用于a1
、a2
等。 但是,例如:
\def\s_a{10}
\s_a
确实有效!似乎 tex 不允许多个带有下划线的宏在下划线前使用相同的文本,即使下划线后的文本不同(同样,这与宏名称中的数字相同)。因此,虽然和可以s_a
单独s_b
使用,但如果它们都已定义,tex 就不能使用它们中的任何一个!
有什么好的解决方案吗?有没有其他命名方案的建议?或者也许有另一种方法可以从文件中获取数据(这很好,因为当定义了很多宏时,输入会花费很多时间)?
我也希望能够使用siunitx
,所以虽然\SI{\a+-\b}{\metre}
可以工作,\SI{\a+-\s_a}{\metre}
但不能。如果可以的话我会很高兴。
答案1
有两个问题:第一个是
\def\sa{10}
\def\sb{20}
文本\sa and \sb
将呈现为
10和20
因为 TeX 忽略控制字后的空格。
第二个问题。控制序列可以由以下任一部分组成:
- 仅有的一非字母字符(控制符号);或
- 由一个或多个字母组成的字符串,即
[A-Za-z]
(控制字)
控制符号后的空格不会被忽略。
然而,定义\def
允许使用相当通用的语法:
\def\cs<parameter text>{<replacement text>}
这里<parameter text>
可以是任意的标记序列,包括参数指示符#1
来#9
表示参数。但如果存在与参数指示符不同的标记,则它们必须出现在之后\cs
。所以
\def\s_a{10}
是合法的,并定义了一个\s
命令需要_a
后面的两个标记。如果你在这之后说
\def\s_b{20}
该命令\s
已重新定义,使用\s_a
将触发错误消息
! Use of \s doesn't match its definition.
由于\s
后面没有_b
。
要同时解决这两个问题,请使用
\def\sa/{10}
\def\sb/{20}
然后\sa/ and \sb/
渲染为
10 和 20
/
因为命令名称后面的必填项会停止忽略空格的功能。
答案2
_
您可以通过更改符号的 catcode 来强制 latex 接受。在 (La)Tex 中,每个符号都有其 catcode,因此如果我们将 catcode 更改_
为正常,catcode
您的命令将起作用。但更改 catcode 可能会导致意外错误。我建议您使用其他命名方案。
\documentclass[12pt]{article}
\catcode`_=11
\def\s_a{10}
\def\s_b{20}
\begin{document}
\s_a and \s_b
\end{document}
您可以使用以下方法解决间距问题xspace
:
\documentclass[12pt]{article}
\usepackage{xspace}
\catcode`_=11
\def\s_a{10\xspace}
\def\s_b{20\xspace}
\begin{document}
\s_a and \s_b
\end{document}
答案3
我的解决方案:
我已经提出了自己的解决方案,虽然它符合“从文件获取数据的另一种方法“。
我使用这个函数来设置一个值:
\DeclareDocumentCommand{\Mset}{m m g}
{
\IfNoValueTF{#3}{
\pgfkeyssetvalue{/matlab/#1/val}{#2}
\pgfkeyssetvalue{/matlab/#1/e}{}
}{
\pgfkeyssetvalue{/matlab/#1/val}{#2}
\pgfkeyssetvalue{/matlab/#1/e}{e#3}
}
}
% eg:
\Mset{a}{124} % set value of 'a' to 124
\Mset{b}{124}{2} % set value of 'a' to 124e2
我可以使用以下方法获取它的文字值:
\newcommand{\M}[1]
{
\pgfkeysvalueof{/matlab/#1/val}\pgfkeysvalueof{/matlab/#1/e}
}
% eg:
\M{a} % results in: 124
\M{b} % results in: 124e2
或者它的值不带指数:
\newcommand{\Mval}[1]
{
\pgfkeysvalueof{/matlab/#1/val}
}
% eg:
\Mval{a} % results in: 124
\Mval{b} % results in: 124
然后我定义了自己的SI
命令:\MSI
。
\DeclareDocumentCommand{\Mparse}{m g m}{
\IfNoValueTF{#2}{
\SI{ \M{#1}}{#3}
}{
\SI{ \Mval{#1}+-\M{#2} }{#3}
}
}
\DeclareDocumentCommand \MSI { >{ \SplitArgument{1}{+} } m m}
{
\Mparse #1 {#2}
}
%eg:
\MSI{a}{m} % same as: \SI{124}{m}
\MSI{b}{m} % same as: \SI{124e2}{m}
这是一个很酷的功能:
\Mset{c}{100}{2}
\Mset{s_c}{12}{2}
\MSI{c+s_c}{m} % same as: \SI{100+-12e2}{m}
我实际上可以调用\MSI
值的名称。这只有在和的指数值相同时才能正常工作c
,s_c
因为它只取的指数值s_c
。因为我的 matlab 函数输出的值与c
和的指数对应s_c
,这对我来说并不重要。但我可能很快就会实现某种警告。
这需要xparse
包,以及pgfplots
包。
\Mparse
用这个定义替换一些最小的错误跟踪:
\DeclareDocumentCommand{\Mparse}{m g m}{
\IfNoValueTF{#2}{
\SI{ \M{#1}}{#3}
}{
\comparestrict
\IfStrEq{\Mexp{#1}}{\Mexp{#2}}{
\SI{ \Mval{#1}+-\M{#2} }{#3}
}{
\text{\tt > > ERROR: not equal exponents in MSI < < }
\GenericError{(cont.)\space\space}{The exponents for the inputs here aren't the same, as should be for decent output.}{Check that the exponents are the same.}{Check tex.stackexchange.com question 40070}
}
}
}
这利用了以下命令\Mexp
:
\newcommand{\Mexp}[1]
{
\pgfkeysvalueof{/matlab/#1/e}
}
它还需要xstring
包检查 /matlab/#1/e 中的字符串是否相等。
答案4
我已在以下位置使用标签mymacros.tex
:
\newlabel{@S_L(d)}{{\unit{-118}{\mega\pascal}}}
然后使用tex
文件中的引用:
\ref{@S_L(d)}