这个问题不是关于某件事情不起作用。
这个问题是关于如何完成一个巧妙的技巧。
interface3.pdf,“12.2 文件操作功能”一节中介绍了该功能
\file_parse_full_name:nNNN {⟨full name⟩} ⟨dir⟩ ⟨name⟩ ⟨ext⟩
:
在解析之前,⟨full name⟩ 会被扩展,直到只剩下不可扩展的标记,但活动字符也不会被扩展。引号 (") 在文件名中是无效的,会从输入中丢弃。
您能否概述一下用于防止活动字符扩展而不防止其他可扩展标记扩展的技巧?
答案1
尽管正如 Phelype 所说,当前的代码依赖于活动字符的“合理”定义,但完全有可能选择性地扩展材料。最后一次使用旧代码检查是a03c651350。其名称清理代码如下:
% \begin{macro}[EXP]{\__kernel_file_name_sanitize:n}
% \begin{macro}[EXP]{\__kernel_file_name_expand_loop:w}
% \begin{macro}[EXP]{\__kernel_file_name_expand_N_type:Nw}
% \begin{macro}[EXP]{\__kernel_file_name_expand_group:nw}
% \begin{macro}[EXP]{\__kernel_file_name_expand_space:w}
% \begin{macro}[EXP]{\__kernel_file_name_strip_quotes:n}
% \begin{macro}[EXP]{\__kernel_file_name_strip_quotes:nnnw}
% \begin{macro}[EXP]{\__kernel_file_name_strip_quotes:nnn}
% \begin{macro}[EXP]{\__kernel_file_name_trim_spaces:n}
% \begin{macro}[EXP]{\__kernel_file_name_trim_spaces:nw}
% \begin{macro}[EXP]{\__kernel_file_name_trim_spaces_aux:n}
% \begin{macro}[EXP]{\__kernel_file_name_trim_spaces_aux:w}
% Expanding the file name without expanding active characters is done
% using the same token-by-token approach as for example case changing.
% The finale outcome only need be \texttt{e}-type expandable, so there
% is no need for the shuffling that is seen in other locations.
% \begin{macrocode}
\cs_new:Npn \__kernel_file_name_sanitize:n #1
{
\exp_args:Ne \__kernel_file_name_trim_spaces:n
{
\exp_args:Ne \__kernel_file_name_strip_quotes:n
{
\__kernel_file_name_expand_loop:w #1
\q_@@_recursion_tail \q_@@_recursion_stop
}
}
}
\cs_new:Npn \__kernel_file_name_expand_loop:w #1 \q_@@_recursion_stop
{
\tl_if_head_is_N_type:nTF {#1}
{ \__kernel_file_name_expand_N_type:Nw }
{
\tl_if_head_is_group:nTF {#1}
{ \__kernel_file_name_expand_group:nw }
{ \__kernel_file_name_expand_space:w }
}
#1 \q_@@_recursion_stop
}
\cs_new:Npn \__kernel_file_name_expand_N_type:Nw #1
{
\@@_if_recursion_tail_stop:N #1
\bool_lazy_and:nnTF
{ \token_if_expandable_p:N #1 }
{
\bool_not_p:n
{
\bool_lazy_any_p:n
{
{ \token_if_protected_macro_p:N #1 }
{ \token_if_protected_long_macro_p:N #1 }
{ \token_if_active_p:N #1 }
}
}
}
{ \exp_after:wN \__kernel_file_name_expand_loop:w #1 }
{
\token_to_str:N #1
\__kernel_file_name_expand_loop:w
}
}
\cs_new:Npx \__kernel_file_name_expand_group:nw #1
{
\c_left_brace_str
\exp_not:N \__kernel_file_name_expand_loop:w
#1
\c_right_brace_str
}
\exp_last_unbraced:NNo
\cs_new:Npx \__kernel_file_name_expand_space:w \c_space_tl
{
\c_space_tl
\exp_not:N \__kernel_file_name_expand_loop:w
}
% \end{macrocode}
% Quoting file name uses basically the same approach as for
% \texttt{luaquotejobname}: count the |"| tokens and remove them.
% \begin{macrocode}
\cs_new:Npn \__kernel_file_name_strip_quotes:n #1
{
\__kernel_file_name_strip_quotes:nnnw {#1} { 0 } { }
#1 " \q_@@_recursion_tail " \q_@@_recursion_stop
}
\cs_new:Npn \__kernel_file_name_strip_quotes:nnnw #1#2#3#4 "
{
\@@_if_recursion_tail_stop_do:nn {#4}
{ \__kernel_file_name_strip_quotes:nnn {#1} {#2} {#3} }
\__kernel_file_name_strip_quotes:nnnw {#1} { #2 + 1 } { #3#4 }
}
\cs_new:Npn \__kernel_file_name_strip_quotes:nnn #1#2#3
{
\int_if_even:nT {#2}
{
\__kernel_msg_expandable_error:nnn
{ kernel } { unbalanced-quote-in-filename } {#1}
}
#3
}
% \end{macrocode}
% Spaces need to be trimmed from the start of the name and from the end of
% any extension. However, the name we are passed might not have an extension:
% that means we have to look for one. If there is no extension, we still use
% the standard trimming function but deliberately prevent any spaces being
% removed at the end.
% \begin{macrocode}
\cs_new:Npn \__kernel_file_name_trim_spaces:n #1
{ \__kernel_file_name_trim_spaces:nw {#1} #1 . \q_@@_nil . \s_@@_stop }
\cs_new:Npn \__kernel_file_name_trim_spaces:nw #1#2 . #3 . #4 \s_@@_stop
{
\@@_quark_if_nil:nTF {#3}
{
\exp_args:Ne \__kernel_file_name_trim_spaces_aux:n
{ \tl_trim_spaces:n { #1 \s_@@_stop } }
}
{ \tl_trim_spaces:n {#1} }
}
\cs_new:Npn \__kernel_file_name_trim_spaces_aux:n #1
{ \__kernel_file_name_trim_spaces_aux:w #1 }
\cs_new:Npn \__kernel_file_name_trim_spaces_aux:w #1 \s_@@_stop {#1}
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
如图所示,这使用“tl
动作”循环依次抓取每个标记/组(将{
/}
标记标准化)。然后我们可以检查每个N
-type 标记并过滤掉受保护的宏和活动标记。
这种方法的缺点是速度很慢。当前代码的编写速度更快,使用 来扩展标记,并依赖于 UTF-8 和类似的 active-char 支持在活动字符标记的定义中\csname
包含 的事实。\ifincsname