缩略范围的宏(页面、音乐小节)

缩略范围的宏(页面、音乐小节)

我希望有一种语义化、可配置的方式来输入页码范围、诗行和音乐小节数。使用宏可以确保所有这些范围的格式一致,并允许我根据需要更改格式,例如,从“小节”更改为“小节”或(西班牙语)“compases”,或从“ll.”更改为“行”或“líneas”。

(看起来,各种软件包的作者bibleverse已经以不同的方式处理了类似的挑战。)

现在我有宏\loc\loca在下面的 MWE 中定义。我必须使用不同的宏来表示复数缩写,因为我不知道如何测试参数以查看它是否是范围。我更愿意将范围类型(​​条形图、线条、页面)作为宏包含,而不是逐字输入。

理想的情况可能是这样的:

命令:

\newcommand{\range}[2]{#1~#2} 
  % if #2 has more than one number, then do #1--#2
\newcommand{\measures}{mm.} 
   % except I would like the abbreviation to vary based on
   % whether the number is plural (m. vs. mm.)
\newcommand{\lines}{ll.}

用法:

\range{\lines}{15} --> 扩展为l.~15因为只有一个数字 \range{\measures}{3 4}--> 扩展为mm.~3--4因为有两个数字

这可能比我想象的要复杂得多,如果是这样,请随时向我指出相关的参考资料,以便我自己解决这个问题。

尽管价值不大,但我可以用 C 语言设计出一个基本算法,下面也包含该算法。

\documentclass{article}

% Ranges of measures, lines (Latin locus, place; loca, region)
\newcommand{\loc}[2]{#1.~#2}    % e.g., m.~13
\newcommand{\loca}[2]{#1#1.~#2} % e.g., mm.~13--14

% Or I could do this
\newcommand{\measure}[1]{m.~#1}
\newcommand{\measures}[1]{mm.~#1}
\newcommand{\poemline}[1]{l.~#1}
\newcommand{\poemlines}[1]{ll.~#1}

\begin{document}

At \loca{l}{13--14} in the poem, the composer puts accents on the wrong syllables (\loca{m}{44--46}). 

At \poemlines{15--16} the composer puts accents on the right syllables (\measures{47--48}).

\end{document}
/* range.c
 * Usage: range <rangetag> <start> <end>
 * Examples: 
 *  range measures 13 14 --> mm.~13--14
 *  range measures 13    --> m.~13
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MEASURETAG 'm'
#define LINETAG 'l'
#define TAGPUNCT '.'

int main(int argc, char *argv[])
{
    char rangetag;
    char tagpunct = TAGPUNCT;

    if ((argc > 4) || (argc < 3)) {
        fprintf(stderr, "Incorrect number of arguments.\n");
        exit(EXIT_FAILURE);
    }

    if (strcmp(argv[1], "measures") == 0) 
        rangetag = MEASURETAG;
    else if (strcmp(argv[1], "lines") == 0)
        rangetag = LINETAG;
    else {
        fprintf(stderr, "Unknown range label.\n");
        exit(EXIT_FAILURE);
    }

    if (argc == 4)  /* If there are start and end range arguments */
        printf("%c%c%c~%s--%s\n",
            rangetag, rangetag, tagpunct, argv[2], argv[3]);
    else /* If only one range argument */
        printf("%c%c~%s\n", rangetag, tagpunct, argv[2]);

    return(0);
}

答案1

这很容易xparse

\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}

\range命令吸收第一个参数,并在空格处分割第二个参数,返回{<before space>}{<after space>}用作#2。如果没有空格,<after space>则为“NoValue”(特殊信号)。

然后我们将控制权交给\dorange第一个检查其第三个参数是否为“NoValue”(无范围情况)并调用

#1~#2

否则它会调用

#1[]~#2

这里#1应该有一个用\defineabbreviation; 输入定义的宏

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

实际执行

\NewDocumentCommand{\lines}{o}{\IfNoValueTF{#1}{l.}{ll.}}

所以当\dorange调用时\lines~{1}结果将是

l. 1

当它调用时\lines[]~2--3结果将是

2–3

(因为空的可选参数不是“NoValue”)。

在此处输入图片描述

相关内容