如何扩展 newtoks 定义的 token 中存储的值

如何扩展 newtoks 定义的 token 中存储的值

在这个项目中,目录结构和文件名基于三个参数,但两者都有一个例外。

目录路径:\GetTexFilePath{}{}{}

目录路径基于顶级目录(#1),这是传递给宏的第一个参数。

通常路径的形式为../#1/xxx#2/#3/,除非#1=\SpecialCase在这种情况下,xxx不是路径的一部分。

文件名:\GetTexFileName{}{}{}

文件名取决于当前的代币的价值:\the\CurrentTokenValue

文件名称的形式为#1-#2-#3,但有一种特殊情况除外,即\the\CurrentTokenValue=\SpecialCase,在这种情况下,文件名就是#3


下面我使用的expl3解决方案改编自输出不应显示的文本

根据@egreg的要求,我在开头添加了一个部分来测试各种情况,并在注释中添加了预期的输出。还为失败的输出添加了红色,为正确的输出添加了蓝色。

上述列表之后的前两部分工作正常,但第三种情况(其中文件名取决于的值)\the\CurrentTokenValue失败。

还请注意,在第 3 节中,#1=\the\CurrentTokenValue目录名称正确不是xxx(这是正确的)。但文件名并没有缩短。第 3 节得出:

../特殊/02/z/特殊-02-z

但案例 3 的正确值应该是

../特殊/02/z/z

问题:

  1. 我该如何调整\GetTexFileName以便文件名取决于令牌?
  2. 为什么这个标记的扩展问题在用于文件路径(仅用于文件名)时没有问题?

我需要使用路径和文件名宏的连接输出(/中间带有)才能检查\IfFileExists

回答:

  • 我已经确认,按照@egreg 的回答将 更改为 适用于所有这些情况。我担心的是,我不知道这是否会对 的使用产生任何其他影响\def\SpecialValue{special},因此最好使用和本地的解决方案。\protected\def\SpecialValue{special}\SpecialValue\GetTexFilePath\GetTexFileName
  • \expandafter\emptyBruno 建议在第一个参数之前添加\str_if_eq:xxTF,以用于此测试,但由于某种原因,在我的实际使用中失败了。

笔记:

  • 关于文件未找到的抱怨不是问题。
  • 所有工作案例均为蓝色。
  • 所有失败的案例都以红色显示。

代码:

\documentclass{article}
\usepackage{xcolor}
\usepackage{xparse}

\def\SpecialValue{special}
\newtoks{\CurrentTokenValue}

\ExplSyntaxOn
% Determine path: Always #1/xxx#2/#3 unless #1=\SpecialValue
\NewDocumentCommand{\GetTexFilePath}{m m m}{%
    \str_if_eq:xxTF{#1}{\SpecialValue}{../#1/#2/#3}{../#1/xxx#2/#3}%
}%

% Determine file name: Always #1-#2-#3 unless \the\CurrentTokenValue=\SpecialValue.
\NewDocumentCommand{\GetTexFileName}{m m m}{%
    \str_if_eq:xxTF{\the\CurrentTokenValue}{\SpecialValue}{#3}{#1-#2-#3}%
}%
\ExplSyntaxOff

\newcommand*{\GetFileNameWithPath}[3]{%
    \GetTexFilePath{#1}{#2}{#3}/%
    \GetTexFileName{#1}{#2}{#3}%
}%

\newcommand*{\TestFile}[2][red]{%
    \noindent%
    Token Value = \the\CurrentTokenValue%
    \par\noindent%
    \IfFileExists{#2}{%
        \textcolor{#1}{File \FileWithPath\ found.}%
    }{%
        \textcolor{#1}{File \FileWithPath\ not found.}%
    }%
}%
\begin{document}
\CurrentTokenValue={NonSpecial}%

\color{blue}% These work (up until the change to red color)
1a. \GetTexFilePath{A}{B}{C}             \par%          ../A/xxxB/C           Note: xxx
2a. \GetTexFilePath{\SpecialValue}{B}{C} \par%          ../special/B/C        Note: no xxx
3a. \GetTexFilePath{\the\CurrentTokenValue}{B}{C} \par% ../NonSpecial/xxxB/C  Note: xxx
%   ----------------
4a. \GetTexFileName{A}{B}{C}             \par%          A-B-C
5a. \GetTexFileName{\SpecialValue}{B}{C} \par%          special-B-C
6a. \GetTexFileName{\the\CurrentTokenValue}{B}{C} \par% NonSpecial-B-C

\smallskip\hrule\smallskip

% Changing the value of \CurrentTokenValue to this one special value, 
% should only change the file name, and should not effect the 
% file path.  Absolutely no reason why the first two here should be 
% any different than above, but included here for completeness.
\CurrentTokenValue={\SpecialValue}% 

1b. \GetTexFilePath{A}{B}{C}             \par%          ../A/xxxB/C           Note: xxx
2b. \GetTexFilePath{\SpecialValue}{B}{C} \par%          ../special/B/C        Note: no xxx
\color{red}% These next 4 fail
3b. \GetTexFilePath{\the\CurrentTokenValue}{B}{C} \par% ../special/B/C        ** FAILS **
%   ---------------
4b. \GetTexFileName{A}{B}{C}             \par%          C                     ** FAILS **
5b. \GetTexFileName{\SpecialValue}{B}{C} \par%          C                     ** FAILS **
6b. \GetTexFileName{\the\CurrentTokenValue}{B}{C} \par% C                     ** FAILS **
\color{black}

\bigskip\hrule\hrule\bigskip

\CurrentTokenValue={NonSpecial}

\section{Normal Case: Works}
Neither the first parameter, nor the \verb|\the\CurrentTokenValue| is  \verb|\SpecialValue| so should have \verb|xxx| in the path, and a file name with two dashes:

\edef\FileWithPath{\GetFileNameWithPath{NonSpecial}{02}{z}}%
\TestFile[blue]{\FileWithPath}

\section{Top directory is special case: Works}
The first parameter is \verb|\SpecialValue|, but not \verb|\the\CurrentTokenValue| so should \textbf{not} have \verb|xxx| in the path, and a file name with two dashes:

\edef\FileWithPath{\GetFileNameWithPath{\SpecialValue}{02}{z}}%
\TestFile[blue]{\FileWithPath}

\section{Both Top directory and TokenValue are special cases}
Since both the first parameter is \verb|\SpecialValue| and \verb|\the\CurrentTokenValue| are a special case, we should \textbf{not} have \verb|xxx| in the path, and a file name should be short:

\CurrentTokenValue={\SpecialValue}
\edef\FileWithPath{\GetFileNameWithPath{\the\CurrentTokenValue}{02}{z}}%
\TestFile{\FileWithPath}

\bigskip
\noindent
Correct result for the above case is
\def\FileWithPath{../special/02/z/z}%

\TestFile[blue]{\FileWithPath}
\end{document}

答案1

我会使用令牌列表,但简单的修复

\protected\def\SpecialValue{special}

似乎给出了所需的输出:在第 3 部分中我得到

令牌值 =
未找到特殊文件 ../special/02/z/z。

此案例的正确值是
Token Value = special
File ../special/02/z/z not found。

在“特殊”情况下,比较恰好在\SpecialValue和之间\SpecialValue(未扩展)。

另一种方法是避免使用令牌寄存器:

\ExplSyntaxOn
\tl_new:N \SpecialValue
\tl_set:Nn \SpecialValue {special}
\tl_new:N \l_grill_current_value_tl

\NewDocumentCommand{\CurrentTokenValue}{m}
  {
   \tl_set:Nn \l_grill_current_value_tl { #1 }
  }
\DeclareExpandableDocumentCommand{\GetCurrentTokenValue}{ }
  {
   \tl_use:N \l_grill_current_value_tl
  }
% Determine path: Always #1/xxx#2/#3 unless #1=\SpecialValue
\NewDocumentCommand{\GetTexFilePath}{m m m}
  {
   \str_if_eq:xxTF{#1}{\SpecialValue}{../#1/#2/#3}{../#1/xxx#2/#3}
  }

% Determine file name: Always #1-#2-#3 unless \the\CurrentTokenValue=\SpecialValue.
\NewDocumentCommand{\GetTexFileName}{m m m}
  {
   \str_if_eq:xxTF{\l_grill_current_value_tl}{\SpecialValue}{#3}{#1-#2-#3}%
  }
\ExplSyntaxOff

现在将语法改为\CurrentTokenValue={...}\CurrentTokenValue{...}\the\CurrentTokenValue足够了\GetCurrentTokenValue

相关内容