我想定义一个命令,使其根据输入的最后一个字符的性质做出反应。但我很难让命令的各个部分正常工作。
我以为我可以抓住细绳我传递命令并使用expl
魔法将其变为大写。然后我会测试最后一个字母和它的大写版本是否相同。但我甚至无法做到这一点。
在这个 MWE 中,我定义了两个命令。第一个命令只是用来抓取第一个令牌并将其更改为大写。它无法做到这一点。第二个应该反转字符串并仅返回第一个标记。这也失败了。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\tl_new:N \l_ae_lasttoken_tl
\tl_new:N \l_ae_upper_lasttoken_tl
\NewDocumentCommand{\aeupcasefirstelement}{ m }
{
\tl_set:Nn \l_ae_lasttoken_tl { \tl_head:n { #1 } }
\tl_set:Nn \l_ae_upper_lasttoken_tl { \tl_to_uppercase:n { \l_ae_lasttoken_tl } }
%% show results of these actions
\textbf{ \l_ae_lasttoken_tl {~ vs. ~} \l_ae_upper_lasttoken_tl }
}
\NewDocumentCommand{\aelastelement}{ m }
{
\tl_set:Nn \l_ae_lasttoken_tl { \tl_head:V { \tl_reverse:V #1 } }
%% show results of these actions
\textbf{ \l_ae_lasttoken_tl }
}
\ExplSyntaxOff
\pagestyle{empty}
\setlength{\parindent}{0pt}
\begin{document}
\begin{tabular}{ll}
Expecting to see & Getting \\
\textbf{T vs. T} & \aeupcasefirstelement{This is a test of my command} \\
\textbf{t vs. T} & \aeupcasefirstelement{this is a test of my command} \\
\textbf{d} & \aelastelement{This is a test of my command}
\end{tabular}
\end{document}
答案1
这定义了一个条件,测试标记列表中的最后一项是否为大写;标记列表应该仅由 ASCII 字符组成。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\prg_new_protected_conditional:Npnn \ae_if_last_uc:n #1 { T , F , TF }
{
\tl_set:Nx \l_ae_testa_tl { \tl_item:nn { #1 } { -1 } }
\tl_set:Nx \l_ae_testb_tl { \text_uppercase:V \l_ae_testa_tl }
\tl_if_eq:NNTF \l_ae_testa_tl \l_ae_testb_tl
{ \prg_return_true: }
{ \prg_return_false: }
}
\cs_generate_variant:Nn \text_uppercase:n { V }
% A test
\ae_if_last_uc:nTF { abc } { \typeout{UC} } { \typeout{LC} }
\ae_if_last_uc:nTF { abC } { \typeout{UC} } { \typeout{LC} }
\ExplSyntaxOff
\stop
测试输出
LC
UC
您的问题很常见:\tl_to_uppercase:n
(即原始的\uppercase
)不可扩展。
让我们看看你的宏。
\NewDocumentCommand{\aeupcasefirstelement}{ m }
{
\tl_set:Nn \l_ae_lasttoken_tl { \tl_head:n { #1 } }
\tl_set:Nn \l_ae_upper_lasttoken_tl { \tl_to_uppercase:n { \l_ae_lasttoken_tl } }
%% show results of these actions
\textbf{ \l_ae_lasttoken_tl {~ vs. ~} \l_ae_upper_lasttoken_tl }
}
你\aeupcasefirstelement{abc}
存储在\l_ae_lasttoken_tl
代币中\tl_head:n{a}
,在\l_ae_upper_lasttoken_tl
代币中
\tl_to_uppercase:n{\l_ae_lasttoken_tl}
这肯定不是你想要的。打印结果似乎是正确的,这纯属偶然,因为在排版过程中,TeX 会扩展并执行标记。为了存储第一个项目,\l_ae_lasttoken_tl
你需要扩张函数\tl_item:nn
,因此使用
\tl_set:Nx \l_ae_lasttoken_tl { \tl_item:nn { #1 } }
是正确的习惯用法。对于大写,您必须\text_uppercase:n
像我上面所做的那样,或者以不同的间接方式进行大写:
\exp_args:Nx \tl_to_uppercase:n
{
\exp_not:n { \tl_set:Nn \l_ae_lasttoken_uppercase_tl } { \l_ae_lasttoken_tl }
}
\tl_to_uppercase:x
(当然,定义一个变体会更好)。
最大的问题是\tl_to_uppercase:n
无法扩展,并且工作方式很奇怪。另请注意,\tl_to_uppercase:n
不再存在于中expl3
,因为它的奇怪之处和工作方式与代码范围不符expl3
。
答案2
这将抓取最后一个字符并将其填充到 中\lastchar
。然后将该字符大写并将其填充到 中\uplastchar
。然后,一个简单的操作\if
就会区分。
\documentclass{article}
\usepackage{stringstrings}
\begin{document}
\def\strng{This is a test of the emergency broadcast system}
\strng
\substring[q]{\strng}{$}{$}
\edef\lastchar{\thestring}
\caseupper[q]{\thestring}
\edef\uplastchar{\thestring}
\lastchar~\uplastchar
\if\lastchar\uplastchar SAME\else DIFFERENT\fi
\end{document}
ps 一般来说,字符串不能包含宏,但如果有必要,也有各种例外和一些解决方法。
答案3
另一个要探索的可能性是pdfTeX
原始的\pdfmatch
。宏\islastcap
检查字符串中最后一个字母的状态,忽略其他字符。
\def\islastcap#1{%
\ifnum\pdfmatch subcount 1 {[A-Z][^a-zA-Z]*$}{#1}=1 %
[U] \else [L] \fi \ #1}
\def\str{ arl kdS }
\islastcap{\str}
\islastcap{\str a }
\islastcap{\str . }
\islastcap{\str . Y; }
\islastcap{\str . Yn/T/f/; }
\bye
输出:
[U] arl kdS
[L] arl kdS a
[U] arl kdS .
[U] arl kdS . Y;
[L] arl kdS . Yn/T/f/;