如何最好地运行一系列元素 {a,1,i}、{b,2,ii} 等

如何最好地运行一系列元素 {a,1,i}、{b,2,ii} 等

我正在重写我为 XeLaTeX 编写的一个包来处理 unicode 块。这意味着要处理从代码点 1234 开始到代码点 5678 结束的块“BlockName”中的所有字符的字符类设置。

现在我有一个宏,它接受三个输入,并将它们转换为:

\newcounter{glyphcounter}
\newcommand{\@defineUnicodeClass}[3]{
 \newXeTeXintercharclass#1
 \forloop{glyphcounter}{#2}{\value{glyphcounter}<#3}\XeTeXcharclass\value{glyphcounter}=#1}
 \XeTeXcharclass#3=#1}

然后它会被调用很多次:

\@defineUnicodeClass{\AegeanNumbersClass}{65792}{65855}
\@defineUnicodeClass{\AlphabeticPresentationFormsClass}{64256}{64335}
\@defineUnicodeClass{\AncientGreekMusicalNotationClass}{119296}{119375}
...

我希望以这样一种方式来压缩它,以便我可以简单地定义块列表,然后{{AegeanNumbers,65792,65855},{AlphabeticPresentationForms,64256,64335},{AncientGreekMusicalNotation,119296,119375},...}运行此列表来为每个块生成所有内容。

我正在考虑将数据定义写为{AegeanNumbers,65792,65855,AlphabeticPresentationForms,64256,64335,AncientGreekMusicalNotation,119296,119375,...},因此只是一个连接的字符串,其中每个第一个 %3 项都是一个新的块定义,然后有一个宏检查输入是否为空,如果不是,则取该列表中的前三个项,处理它们,然后使用列表“尾部”进行递归,但我在 TeX 中实现这一点很难。

如果这是最好的方法,我该怎么做?如果不是,有什么更好的方法来处理这类数据?

我看了http://maraist.org/comma-separated-lists-in-latex_08-2009弄清楚如何实现头部/尾部分离,但我在 XeLaTeX 中没有成功。我尝试过

\def\myTestCommand#1,#2{#1}

只是想看看它是否会做些什么,但是用“\myTestCommand{a,b,c,d}”调用它只会导致“失控参数?”错误。

我还查看了\forcsvlist来自电子工具箱包,但据我所知,它只能理解逗号分隔的列表,其中每个元素都是同一类东西,并且没有元组的概念。我可以编写一个带有两个状态变量宏的切换宏来实现“如果状态为空,则填充第一个变量,如果一个已填充,则填充第二个变量,如果两个都已填充,则调用以下宏并清空两个变量”,但如果有人有更简洁的方法,那就更好了。

答案1

这里有两种方法可以处理命令的定义以及迭代。两者都需要定义一个可以定义命令的宏:

\def\CommandFactory#1#2#3{%
      \expandafter\gdef\csname#1\endcsname{#1 class}
      \expandafter\gdef\csname#1start\endcsname{#2}
      \expandafter\gdef\csname#1end\endcsname{#3}
 }

这可以看作是定义objects或 的实用程序struct。在上面三个命令中,例如aegeanaegeanstartaegeanend。如果使用点或 ,@结构会更明显,aegean@startaegean@end

现在回到迭代,第一个方法使用\@elt,它是元素的缩写,以及Lisp 遗迹在 LaTeX 中发现。

\def\@elt#1,#2,#3,{\CommandFactory{#1}{#2}{#3}} 
\def\unicoderange{\@elt test,1,2,\@elt testi,2,3,\@elt testii,4,5,}

这是 Knuth 处理列表的方式(他使用\\而不是\@elt)。

处理迭代的第二种方法是使用 LaTeX,@for下面显示了一个极简示例。我曾经用\i它来使它更直观,因此请注意通过组运行代码或保存并恢复其定义,否则无点 i 将消失!

\documentclass{article}
\begin{document}

\def\CommandFactory#1#2#3{%
  \expandafter\gdef\csname#1\endcsname{#1 class}
  \expandafter\gdef\csname#1start\endcsname{#2}
  \expandafter\gdef\csname#1end\endcsname{#3}
}

\def\unicodeClasses{aegean,musical,alphabetic}

\CommandFactory{aegean}{65792}{65855}
\CommandFactory{musical}{119296}{119375}
\CommandFactory{alphabetic}{64256}{64335}

\makeatletter
\@for \i:=\unicodeClasses \do{
   \csname\i\endcsname, 
   \csname\i start\endcsname-% 
   \csname\i end\endcsname, 
}


%% another way to iterate using @elt
\def\@elt#1,#2,#3,{\CommandFactory{#1}{#2}{#3}} 
\def\unicoderange{\@elt test,1,2,\@elt testi,2,3,\@elt testii,4,5,}

\unicoderange

\testi
\makeatother

\end{document}

答案2

我不知道 LaTeX 的循环宏,但这是在 ConTeXt 中处理嵌套逗号列表的方法

\def\definecharacterlist
    {\dosingleargument\dodefinecharacterlist}

\def\dodefinecharacterlist[#1]%
    {\processcommalist[#1]\defineUnicodeCharacter}

\def\defineUnicodeCharacter#1%
    {\dostartdefineUnicodeCharacter#1\dostopdefineUnicodeCharacter}

\def\dostartdefineUnicodeCharacter#1,#2,#3\dostopdefineUnicodeCharacter
    {\writestatus{DEBUG}{1: #1; 2: #2; 3: #3}}

\definecharacterlist[{AegeanNumbers,65792,65855},{AlphabeticPresentationForms,64256,64335},{AncientGreekMusicalNotation,119296,119375}]

\dosingleargument只是 ConTeXt 处理可选参数的方式。您可以\processcommalist用等效的 LaTeX 循环宏替换,也可以\writestatus用您想要的任何宏替换。

答案3

语法如下

\@defineUnicodeclasses{AegeanNumbers/65792/65855,
  AlphabeticPresentationForms/64256/64335,
  AncientGreekMusicalNotation/119296/119375}

是好的吗?我想是的。那么

\def\@defineUnicodeclasses#1{%
  \def\@Unicodeclasseslist{#1}%
  \@for\next:=\@Unicodeclasseslist\do
    {\expandafter\do@Unicodeclasslist\next\@nil}}
\def\do@Unicodeclasslist#1/#2/#3\@nil{%
  \count@=\numexpr#2-1\relax
  \expandafter\newXeTeXintercharclass\csname#1\endcsname
  \loop\ifnum\count@<#3\relax
    \advance\count@\@ne
    \XeTeXcharclass\count@=\csname#1\endcsname
  \repeat}

应该是您所需要的。但我看不出比多个\@defineUnicodeclass声明有什么优势。

相关内容