这个问题导致了一个新的方案的出现:
xpeek
我一直在发展我的xpeek
软件包得到了 TeX.SX 各位的大力帮助。它旨在帮助编写命令,这些命令(如常见的\xspace
)会提前查看输入流并根据后续内容选择要执行的操作。尽管界面需要更改,但它具有足够的功能来实现 xspace 之类的功能,或者 LaTeX 的 \textit 中的智能斜体校正。
这意味着它具有与 \textit 相同的熟悉限制,最好通过示例来说明:
\textit{foof}\xspace. \textit{foof}\xspace! % bad italic correction before "."
\def\nocorrlist{.,\xspace}
\textit{foof}\xspace. \textit{foof}\xspace! % no italic correction before "!"
思考这个问题,似乎我需要能够在输入流中向前扫描,忽略一个列表中的标记,同时查找另一个列表中的标记。在 Expl3 术语中,我希望定义类似的东西\peek_inlist_ignore_auxlist:nnTF
。
作为实现此目的的第一步,我尝试简单地向前扫描下一个不在忽略列表中的输入标记。例如:
\def\ignorelist{ ,.;:!}
\newcommand{\nextnonpunc}{\scanignoring{\ignorelist}`\scanfound'}
The next non-punctuation mark is \nextnonpunc.,;:! xyz
屈服
下一个非标点符号是 'x'.,;:! xyz
(实际上,因为我使用的是 Expl3,所以语法应该是
\ExplSyntaxOn
\tl_const:Nn \ignorelist {~,.;:!}
\NewDocumentCommand { \nextnonpunc } { }
{
\peek_ignore_list:N \ignorelist
`\l_peek_token'
}
\ExplSyntaxOff
或类似的东西。)
那么我该如何实现呢\peek_ignore_list:N
?
我正在考虑的方向是提前读取,消耗标记。读取的每个标记都会添加到保存列表并与忽略列表进行比较。如果它在忽略列表中,则继续;否则将保存列表放回输入流并停止。
到目前为止这听起来合理吗?
为了逐个使用令牌,我构建了这个函数:
\cs_new_protected:Npn \peek_meaning_really_remove:NTF #1 #2 #3
{
\peek_meaning_remove:NTF #1
{ #2 }
{
\peek_meaning_remove:NT \l_peek_token
{ #3 }
}
}
但上述问题仍然存在:我该如何实现\peek_ignore_list:N
?
答案1
这是我的拙见。我坚信一定有更好的方法,但它似乎可以满足您的需要。
以下几行
\AddToIgnoreList{,.;:!\xspace}
\nextnonpunc,.;:!xyz
\nextnonpunc,.;:! xyz
\nextnonpunc,.;:!\xspace xyz
\nextnonpunc,.;:!{something}
给出这个输出:
完整代码如下:
\documentclass{article}
\usepackage{expl3,xparse,xspace}
\ExplSyntaxOn
% ----------------------------------------
% variables:
\tl_new:N \l_solomon_current_ignore_token_tl
\tl_new:N \l_solomon_ignorelist_tokens_tl
\tl_new:N \l_solomon_ignored_tokens_tl
% ----------------------------------------
% setup the list:
\cs_new:Npn \solomon_add_to_ignorelist:n #1
{ \tl_put_right:Nn \l_solomon_ignorelist_tokens_tl { #1 }}
\cs_new:Npn \solomon_remove_from_ignorelist:n #1
{
\tl_map_inline:nn { #1 }
{ \tl_remove_all:Nn \l_solomon_ignorelist_tokens_tl { ##1 } }
}
\NewDocumentCommand \AddToIgnoreList { m }
{ \solomon_add_to_ignorelist:n { #1 } }
\NewDocumentCommand \RemoveFromIgnoreList { m }
{ \solomon_remove_from_ignorelist:n { #1 } }
% ----------------------------------------
% check if next token is part of the ignore-list; store it in
% \l_solomon_current_ignore_token_tl
\cs_new:Npn \solomon_check_ignorelist:NTF #1#2
{ \solomon_check_ignorelist_auxi:nTF { 0 } { #1 } { #2 } }
\cs_new:Npn \solomon_check_ignorelist_auxi:nTF #1#2#3
{
% get the first token from the list and compare:
\solomon_get_head:NN
\l_solomon_current_ignore_token_tl
\l_solomon_ignorelist_tokens_tl
\peek_meaning_remove:VTF \l_solomon_current_ignore_token_tl
{ #2 }
{
\solomon_check_ignorelist_auxii:nnn { #1 }
{ \solomon_check_ignorelist_auxi:VTF \l_tmpa_int { #2 } { #3 } }
{
\solomon_get_head:NN
\l_solomon_current_ignore_token_tl
\l_solomon_ignorelist_tokens_tl
#3
}
}
}
\cs_new:Npn \solomon_check_ignorelist_auxii:nnn #1#2#3
{
% test was successful; rotate the list and go on if there are more
\int_set:Nn \l_tmpa_int { #1 }
\int_incr:N \l_tmpa_int
\tl_remove_all:NV
\l_solomon_ignorelist_tokens_tl
\l_solomon_current_ignore_token_tl
\tl_put_right:NV \l_solomon_ignorelist_tokens_tl
\l_solomon_current_ignore_token_tl
\int_compare:nTF { \l_tmpa_int < \tl_length:V \l_solomon_ignorelist_tokens_tl }
{ #2 }
{ #3 }
}
\cs_generate_variant:Nn \solomon_check_ignorelist_auxi:nTF { V }
\cs_generate_variant:Nn \peek_meaning_remove:NTF { V }
\cs_generate_variant:Nn \tl_remove_all:Nn { NV }
\cs_generate_variant:Nn \tl_put_right:Nn { NV }
\cs_new:Npn \solomon_get_head:NN #1#2
{ \exp_after:wN \solomon_get_head_aux:Nw \exp_after:wN #1#2 \q_stop }
\cs_new:Npn \solomon_get_head_aux:Nw #1#2#3 \q_stop
{ \tl_set:Nn #1 { #2 } }
% ----------------------------------------
% now do some testing:
\cs_new:Npn \solomon_nextnonpunc:
{
\solomon_check_ignorelist:NTF
{
\tl_put_right:NV \l_solomon_ignored_tokens_tl
\l_solomon_current_ignore_token_tl
\nextnonpunc
}
{
(The~next~non-punctuation~mark~is:~`\l_peek_token')~
\tl_use:N \l_solomon_ignored_tokens_tl
\tl_clear:N \l_solomon_ignored_tokens_tl
}
}
\NewDocumentCommand \nextnonpunc {} { \solomon_nextnonpunc: }
\ExplSyntaxOff
\begin{document}
\AddToIgnoreList{,.;:!\xspace}
\nextnonpunc,.;:!xyz
\nextnonpunc,.;:! xyz
\nextnonpunc,.;:!\xspace xyz
\nextnonpunc,.;:!{something}
\end{document}