提前查看不在标记列表中的下一个标记

提前查看不在标记列表中的下一个标记

这个问题导致了一个新的方案的出现:
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}

相关内容