我的 LaTeX3 代码的质量和效率如何?

我的 LaTeX3 代码的质量和效率如何?

作为学习 LaTeX3 的练习,我想替换以下 7 个函数,它们来自xepersian.sty它们在包中完成同样的工作 xepersian,但只有单一功能。

208 \DeclareDocumentCommand \setlatintextfont { O{} m O{} }
209   {
210     \__xepersian_main_setlatintextfont:nn {#1,#3} {#2}
211     \ignorespaces
212   }
213 \cs_new:Nn \__xepersian_main_setlatintextfont:nn
214  {
215   \fontspec_set_family:Nnn \l__xepersian_latinfont_family_tl {Ligatures=TeX,#1} {#2}
216   \use:x { \exp_not:n { \DeclareRobustCommand \latinfont }
217    {
218     \exp_not:N \fontencoding { \g__fontspec_nfss_enc_tl }
219     \exp_not:N \fontfamily { \l__xepersian_latinfont_family_tl }
220     \exp_not:N \selectfont
221    }
222   }
223   \str_if_eq_x:nnT {\familydefault} {\rmdefault}
224     { \tl_set_eq:NN \encodingdefault \g__fontspec_nfss_enc_tl }
225   \__xepersian_setlatintextfont_hook:nn {#1} {#2}
226   \normalfont
227  }
228 
229 \cs_set_eq:NN \__xepersian_setlatintextfont_hook:nn   \use_none:nn


313 \DeclareDocumentCommand \setpersiansansfont { O{} m O{} }
314   {
315     \__xepersian_main_setpersiansansfont:nn {#1,#3} {#2}
316     \ignorespaces
317   }
318 \cs_new:Nn \__xepersian_main_setpersiansansfont:nn
319  {
320   \fontspec_set_family:Nnn \l__xepersian_persiansffamily_family_tl {Script=Persian,Ligatures=PersianTeX,#1} {#2}
321   \tl_set_eq:NN \persiansfdefault \l__xepersian_persiansffamily_family_tl
322   \use:x { \exp_not:n { \DeclareRobustCommand \persiansffamily }
323    {
324     \exp_not:N \fontencoding { \g__fontspec_nfss_enc_tl }
325     \exp_not:N \fontfamily { \l__xepersian_persiansffamily_family_tl }
326     \exp_not:N \selectfont
327    }
328   }
329   \str_if_eq_x:nnT {\familydefault} {\persiansfdefault}
330     { \tl_set_eq:NN \encodingdefault \g__fontspec_nfss_enc_tl }
331   \__xepersian_setpersiansansfont_hook:nn {#1} {#2}
332   \normalfont
333  }
334 
335 \cs_set_eq:NN \__xepersian_setpersiansansfont_hook:nn   \use_none:nn
336 


337 \DeclareDocumentCommand \setpersianmonofont { O{} m O{} }
338   {
339     \__xepersian_main_setpersianmonofont:nn {#1,#3} {#2}
340     \ignorespaces
341   }
342 \cs_new:Nn \__xepersian_main_setpersianmonofont:nn
343  {
344   \fontspec_set_family:Nnn \l__xepersian_persianttfamily_family_tl {Script=Persian,Ligatures=PersianTeX,#1} {#2}
345   \tl_set_eq:NN \persianttdefault \l__xepersian_persianttfamily_family_tl
346   \use:x { \exp_not:n { \DeclareRobustCommand \persianttfamily }
347    {
348     \exp_not:N \fontencoding { \g__fontspec_nfss_enc_tl }
349     \exp_not:N \fontfamily { \l__xepersian_persianttfamily_family_tl }
350     \exp_not:N \selectfont
351    }
352   }
353   \str_if_eq_x:nnT {\familydefault} {\persianttdefault}
354     { \tl_set_eq:NN \encodingdefault \g__fontspec_nfss_enc_tl }
355   \__xepersian_setpersianmonofont_hook:nn {#1} {#2}
356   \normalfont
357  }
358 
359 \cs_set_eq:NN \__xepersian_setpersianmonofont_hook:nn   \use_none:nn
360 


361 \DeclareDocumentCommand \setnavarfont { O{} m O{} }
362   {
363     \__xepersian_main_setnavarfont:nn {#1,#3} {#2}
364     \ignorespaces
365   }
366 \cs_new:Nn \__xepersian_main_setnavarfont:nn
367  {
368   \fontspec_set_family:Nnn \l__xepersian_navarfamily_family_tl {Script=Persian,Ligatures=PersianTeX,#1} {#2}
369   \tl_set_eq:NN \navardefault \l__xepersian_navarfamily_family_tl
370   \use:x { \exp_not:n { \DeclareRobustCommand \navarfamily }
371    {
372     \exp_not:N \fontencoding { \g__fontspec_nfss_enc_tl }
373     \exp_not:N \fontfamily { \l__xepersian_navarfamily_family_tl }
374     \exp_not:N \selectfont
375    }
376   }
377   \str_if_eq_x:nnT {\familydefault} {\navardefault}
378     { \tl_set_eq:NN \encodingdefault \g__fontspec_nfss_enc_tl }
379   \__xepersian_setnavarfont_hook:nn {#1} {#2}
380   \normalfont
381  }
382 
383 \cs_set_eq:NN \__xepersian_setnavarfont_hook:nn   \use_none:nn
384 


385 \DeclareDocumentCommand \setpookfont { O{} m O{} }
386   {
387     \__xepersian_main_setpookfont:nn {#1,#3} {#2}
388     \ignorespaces
389   }
390 \cs_new:Nn \__xepersian_main_setpookfont:nn
391  {
392   \fontspec_set_family:Nnn \l__xepersian_pookfamily_family_tl {Script=Persian,Ligatures=PersianTeX,#1} {#2}
393   \tl_set_eq:NN \pookdefault \l__xepersian_pookfamily_family_tl
394   \use:x { \exp_not:n { \DeclareRobustCommand \pookfamily }
395    {
396     \exp_not:N \fontencoding { \g__fontspec_nfss_enc_tl }
397     \exp_not:N \fontfamily { \l__xepersian_pookfamily_family_tl }
398     \exp_not:N \selectfont
399    }
400   }
401   \str_if_eq_x:nnT {\familydefault} {\pookdefault}
402     { \tl_set_eq:NN \encodingdefault \g__fontspec_nfss_enc_tl }
403   \__xepersian_setpookfont_hook:nn {#1} {#2}
404   \normalfont
405  }
406 
407 \cs_set_eq:NN \__xepersian_setpookfont_hook:nn   \use_none:nn
408 


409 \DeclareDocumentCommand \setsayehfont { O{} m O{} }
410   {
411     \__xepersian_main_setsayehfont:nn {#1,#3} {#2}
412     \ignorespaces
413   }
414 \cs_new:Nn \__xepersian_main_setsayehfont:nn
415  {
416   \fontspec_set_family:Nnn \l__xepersian_sayehfamily_family_tl {Script=Persian,Ligatures=PersianTeX,#1} {#2}
417   \tl_set_eq:NN \sayehdefault \l__xepersian_sayehfamily_family_tl
418   \use:x { \exp_not:n { \DeclareRobustCommand \sayehfamily }
419    {
420     \exp_not:N \fontencoding { \g__fontspec_nfss_enc_tl }
421     \exp_not:N \fontfamily { \l__xepersian_sayehfamily_family_tl }
422     \exp_not:N \selectfont
423    }
424   }
425   \str_if_eq_x:nnT {\familydefault} {\sayehdefault}
426     { \tl_set_eq:NN \encodingdefault \g__fontspec_nfss_enc_tl }
427   \__xepersian_setsayehfont_hook:nn {#1} {#2}
428   \normalfont
429  }
430 
431 \cs_set_eq:NN \__xepersian_setsayehfont_hook:nn   \use_none:nn
432 


433 \DeclareDocumentCommand \setiranicfont { O{} m O{} }
434   {
435     \__xepersian_main_setiranicfont:nn {#1,#3} {#2}
436     \ignorespaces
437   }
438 \cs_new:Nn \__xepersian_main_setiranicfont:nn
439  {
440   \fontspec_set_family:Nnn \l__xepersian_iranicfamily_family_tl {Script=Persian,Ligatures=PersianTeX,#1} {#2}
441   \tl_set_eq:NN \iranicdefault \l__xepersian_iranicfamily_family_tl
442   \use:x { \exp_not:n { \DeclareRobustCommand \iranicfamily }
443    {
444     \exp_not:N \fontencoding { \g__fontspec_nfss_enc_tl }
445     \exp_not:N \fontfamily { \l__xepersian_iranicfamily_family_tl }
446     \exp_not:N \selectfont
447    }
448   }
449   \str_if_eq_x:nnT {\familydefault} {\iranicdefault}
450     { \tl_set_eq:NN \encodingdefault \g__fontspec_nfss_enc_tl }
451   \__xepersian_setiranicfont_hook:nn {#1} {#2}
452   \normalfont
453  }
454 
455 \cs_set_eq:NN \__xepersian_setiranicfont_hook:nn   \use_none:nn

以下是我已将以上所有内容替换的代码xepersian.sty

\cs_set:Nn \__xepersian_declare_set_fonts:nnnnn
  {
  \exp_args:Nc \DeclareDocumentCommand { set #1 font } { O{} m O{} }
    {
      \cs:w __xepersian_main_set #1 font :nn \cs_end: {##1,##3} {##2}
      \ignorespaces
    }
  \exp_args:Nc \cs_new:Nn { __xepersian_main_set #1 font :nn }
    {
      \exp_args:Ncnx \fontspec_set_family:Nnn { l__xepersian_ #2 #3 _family_tl } {#5,##1} {##2}
      \exp_args:Ncc \tl_set_eq:NN { #2 default } { l__xepersian_ #2 #3 _family_tl }
      \use:x { \exp_not:n { \exp_args:Nc \DeclareRobustCommand { #2 #3 } }
        {
          \exp_not:N \fontencoding { \g__fontspec_nfss_enc_tl }
          \exp_not:N \fontfamily { \cs:w l__xepersian_ #2 #3 _family_tl \cs_end: }
          \exp_not:N \selectfont
        }
      }
      \str_if_eq_x:nnT {\familydefault} { \cs:w #4 default \cs_end: }
        { \tl_set_eq:NN \encodingdefault \g__fontspec_nfss_enc_tl }
      \cs:w __xepersian_set #1 font_hook :nn \cs_end: {##1} {##2}
      \normalfont
    }
  \exp_args:Nc \cs_set_eq:NN { __xepersian_set #1 font_hook :nn }   \use_none:nn
  }

\__xepersian_declare_set_fonts:nnnnn { latintext } { latin } { font } { rm } { Ligatures=TeX }

\seq_new:N \l__my_xepersian_styles_seq
\seq_set_split:Nnn \l__my_xepersian_styles_seq { , }
  { 
    % { { latintext }   { latin }     { font }   { rm }        { Ligatures=TeX } } ,
    { { persiansans } { persiansf } { family } { persiansf } { Script=Persian,Ligatures=PersianTeX } } ,
    { { persianmono } { persiantt } { family } { persiantt } { Script=Persian,Ligatures=PersianTeX } } ,
    { { iranic }      { iranic }    { family } { iranic }    { Script=Persian,Ligatures=PersianTeX } } ,
    { { navar }       { navar }     { family } { navar }     { Script=Persian,Ligatures=PersianTeX } } ,
    { { pook }        { pook }      { family } { pook }      { Script=Persian,Ligatures=PersianTeX } } ,
    { { sayeh }       { sayeh }     { family } { sayeh }     { Script=Persian,Ligatures=PersianTeX } }
  }

\seq_map_inline:Nn \l__my_xepersian_styles_seq
  {
    \__xepersian_declare_set_fonts:nnnnn  #1 
  }

由于我是 LaTeX3 的初学者,我想知道是否可以提高代码的质量和效率,或者简化它。我的 MWE 是:

\documentclass{article}
\usepackage{xepersian}
\settextfont{Amiri}
\setlatintextfont[Scale=1.44]{Times New Roman}
\setpersianmonofont[Scale=1.44]{Amiri}
\setpersiansansfont[Scale=1.44]{Amiri}
\setiranicfont[Scale=1.44]{Amiri}
\setnavarfont[Scale=1.44]{Amiri}
\setpookfont[Scale=1.44]{Amiri}
\setsayehfont[Scale=1.44]{Amiri}
\pagestyle{empty}
\begin{document}
\lr{This is a test for numbers: 0 1 2 3 4 5 6 7 8 9.} \\
این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹. \\
\persianttfamily \textpersiantt{این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹.} \\
\persiansffamily \textpersiansf{این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹.} \\
\iranicfamily \textiranic{این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹.} \\
\navarfamily \textnavar{این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹.} \\
\pookfamily \textpook{این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹.} \\
\sayehfamily \textsayeh{این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹.}
\end{document}

我修改过的文件xepersian.sty可以从以下网址下载粘贴箱

编辑于 2018-12-28:应用建议的更正

\__xepersian_declare_set_fonts:nnnnn特别感谢 TeXnician 和 Joseph 的帮助,我应用了他们建议的所有更正的函数新版本如下:

\cs_generate_variant:Nn \fontspec_set_family:Nnn { c }
\prg_generate_conditional_variant:Nnn  \str_if_eq:nn { Vv } { T, F, TF }
\cs_set:Nn \__xepersian_declare_set_fonts:nnnnn
  {
  \exp_args:Nc \DeclareDocumentCommand { set #1 font } { O{} m O{} }
    {
      \use:c { __xepersian_main_set #1 font:nn }  {##1,##3} {##2}
      \ignorespaces
    }
  \exp_args:Nc \cs_new:Nn { __xepersian_main_set #1 font :nn }
    {
      \fontspec_set_family:cnn { l__xepersian_ #2 #3 _family_tl } {#5,##1} {##2}
      \tl_set_eq:cc { #2 default } { l__xepersian_ #2 #3 _family_tl }
      \use:x { \exp_not:n { \exp_args:Nc \DeclareRobustCommand { #2 #3 } }
        {
          \exp_not:N \fontencoding { \g__fontspec_nfss_enc_tl }
          \exp_not:N \fontfamily { \use:c { l__xepersian_ #2 #3 _family_tl } }
          \exp_not:N \selectfont
        }
      }
      \str_if_eq:VvT {\familydefault} { #4 default }
        { \tl_set_eq:NN \encodingdefault \g__fontspec_nfss_enc_tl }
      \use:c { __xepersian_set #1 font_hook:nn } {##1} {##2}
      \normalfont
    }
  \cs_set_eq:cN { __xepersian_set #1 font_hook :nn }   \use_none:nn
  }

修改后xepersian.sty重命名为hmxepersian.sty。文件名中的前缀hm表示现在可以加载HM名称中带有的字体。

另外,我的新工作示例如下:

% Tested with: xepersian-22.5, Revision 49428 on TeXLive
\documentclass{article}
\usepackage{hmxepersian}
\settextfont[Scale=1.2]{HM XKayhan}
\setlatintextfont[Scale=1.2]{Psychedelia HM}
\setpersianmonofont[Scale=1.2]{DejaVu Sans Mono}
\setpersiansansfont[Scale=1.2]{DejaVu Sans}
\setiranicfont[Scale=1.2]{HM XKayhanOb Oblique}
\setnavarfont[Scale=1.2]{HM XKayhan Navaar}
\setpookfont[Scale=1.2]{HM XKayhan Pook}
\setsayehfont[Scale=1.2]{HM XKayhan Sayeh}
\pagestyle{empty}
\begin{document}
\lr{This is a test for numbers: 0 1 2 3 4 5 6 7 8 9.} \\
این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹. \\
\persianttfamily \textpersiantt{این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹.} \\
\persiansffamily \textpersiansf{این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹.} \\
\iranicfamily \textiranic{این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹.} \\
\navarfamily \textnavar{این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹.} \\
\pookfamily \textpook{این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹.} \\
\sayehfamily \textsayeh{این یک آزمایش اعداد است: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹.}
\end{document}

答案1

由于您的示例不可编译,因此不易测试,我仅提供一些说明:

  • 您正在使用将一个类型参数\exp_args转换为类型,例如Nc

    \exp_args:Ncnx \fontspec_set_family:Nnn { l__xepersian_ #2 #3 _family_tl } {#5,##1} {##2}
    

    相反,您应该生成一个\fontspec_set_family可以为您完成此扩展技巧的变体。

    \cs_generate_variant:Nn \fontspec_set_family:Nnn { c }
    

    这可以用作\fontspec_set_family:cnn { l__xepersian_ #2 #3 _family_tl } {#5,##1} {##2}

  • 关于变体的另一件事:有预定义的变体。因此,当您使用时,\exp_args:Ncc \tl_set_eq:NN您实际上是在请求预定义的变体\tl_set_eq:cc,您可以使用

    \tl_set_eq:cc { #2 default } { l__xepersian_ #2 #3 _family_tl }
    

    这也适用于\cs_set_eq

    \cs_set_eq:cN { __xepersian_set #1 font_hook :nn } \use_none:nn
    
  • 您正在使用cs:w … \cs_end:作为\csname\endcsname构造,尽管您可以\use:c { __xepersian_main_set #1 font:nn }在那时使用。

  • \str_if_eq_x已弃用。似乎您想要比较两个命令序列作为参数所持有的值(每个参数一次展开,然后比较两个参数)。为此,您可以\prg_generate_conditional_variant使用\str_if_eq:VvT或,\tl_if_eq:VvT这将更符合惯用方式,例如

    \prg_generate_conditional_variant:Nnn  \str_if_eq:nn { Vv } { T, F, TF }
    \str_if_eq:VvT \familydefault { #4 default } { … }
    

    或者你可以\str_if_eq:ee改为

    \str_if_eq_x:nnT {\familydefault} { \cs:w #4 default \cs_end: }
      { \tl_set_eq:NN \encodingdefault \g__fontspec_nfss_enc_tl }
    \cs:w __xepersian_set #1 font_hook :nn \cs_end: {##1} {##2}
    

    进入

    \str_if_eq:eeT {\familydefault} { \use:c { #4 default } }
      { \tl_set_eq:NN \encodingdefault \g__fontspec_nfss_enc_tl }
    \use:c { __xepersian_set #1 font_hook:nn } {##1} {##2}
    

请注意,我这里没有考虑速度。这些只是从第一眼看到你的代码(整洁性和可读性)得出的一些要点。

相关内容