针对范围和一系列线条、测量值等的更强大的宏

针对范围和一系列线条、测量值等的更强大的宏

首先@egregxparse对我关于 缩略范围的宏(页面、音乐小节)

如何定义一个类似的命令,可以处理不连续的引用(范围和系列)?

此命令的幻想版本将接受像 这样的输入\range{\measures}{3-4,7,+9-11}并将其扩展为mm.~3--4, 7, and 9--1。这将取决于序列逗号的使用设置和连词的语言(如果+是输入)。

以下是@egreg 的出发点:

\documentclass{article}
\usepackage{xparse}

\NewDocumentCommand{\range}{ m >{\SplitArgument{1}{ }}m }
 {%
  \dorange{#1}#2%
 }

\NewDocumentCommand{\dorange}{ m m m }
 {%
  \IfNoValueTF{#3}{#1~#2}{#1[]~#2--#3}%
 }

\NewDocumentCommand{\defineabbreviation}{ m m m }
 {%
  \NewDocumentCommand{#1}{o}{\IfNoValueTF{##1}{#2}{#3}}%
 }

\defineabbreviation{\lines}{l.}{ll.}
\defineabbreviation{\measures}{m.}{mm.}

\begin{document}

\range{\lines}{1}

\range{\lines}{2 3}

\range{\measures}{4}

\range{\measures}{5 6}

\end{document}

答案1

支持复杂范围的宏必须充分利用expl3。以下是一个可能的解决方案:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\range}{ m m }
 {
  \cashner_range:nn { #1 } { #2 }
 }

\tl_new:N \l__cashner_range_input_tl
\seq_new:N \l__cashner_range_input_seq
\bool_new:N \l__cashner_range_multi_bool

\cs_new_protected:Npn \cashner_range:nn #1 #2
 {
  % store the second argument in a token list
  \tl_set:Nn \l__cashner_range_input_tl { #2 }
  % change all -- into -
  \tl_replace_all:Nnn \l__cashner_range_input_tl { -- } { - }
  % change all - into -- (so as to normalize them)
  \tl_replace_all:Nnn \l__cashner_range_input_tl { - } { -- }
  % split the input at spaces (or whatever the second argument tells
  \seq_set_split:NnV \l__cashner_range_input_seq { ~ } \l__cashner_range_input_tl
  % set the “multi” boolean to false
  \bool_set_false:N \l__cashner_range_multi_bool
  \int_compare:nTF { \seq_count:N \l__cashner_range_input_seq == 1 }
   {% if the sequence has just one item check if `-` is in the input
    % and, in this case, set the boolean to true
    \tl_if_in:nnT { #2 } { - } { \bool_set_true:N \l__cashner_range_multi_bool }
   }
   {% more than one item, set the boolean to true
    \bool_set_true:N \l__cashner_range_multi_bool
   }
  % if the boolean is true, use the plural version of the abbreviation
  \bool_if:NTF \l__cashner_range_multi_bool
   { #1{p} } { #1{s} }\nobreakspace
   % use the sequence (with "and" between just two items,
   % a comma between all items except the last one
   % with ", and" between the last two, if more than two)
   \seq_use:Nnnn \l__cashner_range_input_seq { ~and~ } { ,~ } { ,~and\nobreakspace }
 }
\cs_generate_variant:Nn \seq_set_split:Nnn { NnV }

\NewDocumentCommand{\defineabbreviation}{ m m m }
 {% define #1 to produce the singular version if the argument
  % is p, or singular if the argument is s
  \cs_new_protected:Npn #1 ##1
   {
    \str_case:nn{##1}{{s}{#2}{p}{#3}}
   }
 }
\ExplSyntaxOff

\defineabbreviation{\lines}{l.}{ll.}

\begin{document}

\range{\lines}{1}

\range{\lines}{1-2}

\range{\lines}{1 3}

\range{\lines}{1--2 3 4}

\range{\lines}{1 2 3-5}

\end{document}

请注意,您可以将范围输入为1--21-2,因此即使手指滑了一下也没有关系(但1---2没有好处)。

输入首先存储在一个标记列表中,其中--被归一化为-并且-被归一化回--,因此在末尾范围将具有--,与输入无关。完成此初步步骤后,输入在空格处被拆分为一个序列。

如果序列有多个元素或唯一元素包含连字符,则布尔值设置为 true。如果布尔值为 true,则使用参数 调用第一个参数中的宏p,否则使用s。此类宏应通过 定义\defineabbreviation,并且不应在其他地方使用,除非您添加合适的参数(因此\lines{p}是合法的并且会产生ll.\nobreakspace)。

打印缩写(单数或复数形式)后,使用该序列。

在此处输入图片描述

如果你喜欢这样的语法

\range{\lines}{1-2,3, 4}

这只是改变路线的问题

  \seq_set_split:NnV \l__cashner_range_input_seq { ~ } \l__cashner_range_input_tl

进入

  \seq_set_split:NnV \l__cashner_range_input_seq { , } \l__cashner_range_input_tl

如果我们想提供本地化怎么办babel? 这里就是。

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[italian,english]{babel}

\usepackage{xparse}


\ExplSyntaxOn
\NewDocumentCommand{\range}{ m m }
 {
  \cashner_range:nn { #1 } { #2 }
 }

\tl_new:N \l__cashner_range_input_tl
\tl_new:N \l_cashner_range_sep_two_tl
\tl_new:N \l_cashner_range_sep_many_tl
\tl_new:N \l_cashner_range_sep_last_tl
\seq_new:N \l__cashner_range_input_seq
\bool_new:N \l__cashner_range_multi_bool

\cs_new_protected:Npn \cashner_range:nn #1 #2
 {
  \tl_set:Nn \l__cashner_range_input_tl { #2 }
  \tl_replace_all:Nnn \l__cashner_range_input_tl { -- } { - }
  \tl_replace_all:Nnn \l__cashner_range_input_tl { - } { -- }
  \bool_set_false:N \l__cashner_range_multi_bool
  \seq_set_split:NnV \l__cashner_range_input_seq { ~ } \l__cashner_range_input_tl
  \int_compare:nTF { \seq_count:N \l__cashner_range_input_seq == 1 }
   {
    \tl_if_in:nnT { #2 } { - } { \bool_set_true:N \l__cashner_range_multi_bool }
   }
   {
    \bool_set_true:N \l__cashner_range_multi_bool
   }
  \bool_if:NTF \l__cashner_range_multi_bool
   { #1{p} } { #1{s} }\nobreakspace
   \seq_use:NVVV \l__cashner_range_input_seq
    \l_cashner_range_sep_two_tl
    \l_cashner_range_sep_many_tl
    \l_cashner_range_sep_last_tl
 }
\cs_generate_variant:Nn \seq_set_split:Nnn { NnV }
\cs_generate_variant:Nn \seq_use:Nnnn { NVVV }

\NewDocumentCommand{\defineabbreviation}{ o m m m }
 {
  \IfNoValueTF { #1 }
   {
    \cs_new_protected:Npn #2 ##1
     {
      \str_case:nn{##1}{{s}{#3}{p}{#4}}
     }
   }
   {
    \exp_args:Nc \addto { extras#1 }
     {
      \cs_set_protected:Npn #2 ##1
       {
        \str_case:nn{##1}{{s}{#3}{p}{#4}}
       }
     }
   }
 }

\NewDocumentCommand{\setrangeseparators}{ommm}
 {
  \IfNoValueTF{#1}
   {
    \tl_set:Nn \l_cashner_range_sep_two_tl  { #2 }
    \tl_set:Nn \l_cashner_range_sep_many_tl { #3 }
    \tl_set:Nn \l_cashner_range_sep_last_tl { #4 }
   }
   {
    \exp_args:Nc \addto { extras#1 }
     {
      \tl_set:Nn \l_cashner_range_sep_two_tl  { #2 }
      \tl_set:Nn \l_cashner_range_sep_many_tl { #3 }
      \tl_set:Nn \l_cashner_range_sep_last_tl { #4 }
     }
   }
 }

\ExplSyntaxOff

% no argument means the default language

\setrangeseparators{ and }{, }{, and~}
\setrangeseparators[italian]{ e }{, }{ e~}%

\defineabbreviation{\lines}{l.}{ll.}
\defineabbreviation[italian]{\lines}{r.}{rr.}%


\begin{document}

\range{\lines}{1}

\range{\lines}{1-2}

\range{\lines}{1 3}

\range{\lines}{1--2 3 4}

\range{\lines}{1 2 3-5}

\selectlanguage{italian}

\range{\lines}{1}

\range{\lines}{1-2}

\range{\lines}{1 3}

\range{\lines}{1--2 3 4}

\range{\lines}{1 2 3-5}

\end{document}

在此处输入图片描述

相关内容