经过 10 多年的 LaTeX 中断之后,我回来了,并慢慢重新掌握了宏编写。
我现在想将字符串“fisis”解析为首字母“f”和后半部分“isis”。区分大小写其实不是问题。
有效令牌遵循以下规则:
- 第一个字母必须是 {a, b, c..., g} 之一
- 标记的第二部分由 0、1 或 2 个标记“es”或“is”组成
例如,“cesis”是无效的,因为根据规则 2,“es”后面不能跟“is”。
用例是通过宏创建音乐作品调性的多语言渲染,例如:\tonality{fis}{minor} 其将以德语、法语和英语渲染如下:{Fis-moll. {\emph Fa dièse mineur.} F sharp minor.}
例如,第一个例子“fisis”将被解析为(“f”;“is”x 2),其在英语中将被呈现为“F double sharp”(使用 \tonalityEN 宏),在法语中将被呈现为“Ré double dièse”(使用 \tonalityFR 宏)。
如何实现这一点?
答案1
我不完全明白你的问题,但如果你能够描述如何处理语言切换,下面的内容可以进行一些测试,并可以作为基础。我使用了方便的xstring
它带有非常强大的字符串处理工具,如下所示。首先,我们删除第一个字符,然后测试单词的其余部分是否包含剩余部分的前两个字符。如果在删除检测到的两个字母后遗漏了某些内容,则会给出错误。之后就很简单了。
\documentclass{article}
\usepackage{xstring}
\def\parsethis#1{%
\if\relax#1\relax\else%
\StrLeft{#1}{1}[\myfirstletter]
\StrGobbleLeft{#1}{1}[\myrestofword]
\StrLeft{\myrestofword}{2}[\mysample]
\StrCount{\myrestofword}{\mysample}[\numofreps]
\StrDel{\myrestofword}{\mysample}[\remainingchars]
\if\relax\remainingchars\relax%
I found \numofreps\space copies of the string ``\mysample''.%
\else
There is a mixture of es and is.%
\fi
}
\begin{document}
\parsethis{cisis}\par
\parsethis{feseses}\par
\parsethis{dadadadad}\par
\parsethis{b}\par
\parsethis{basis}
\end{document}
答案2
您可以检查新的 LaTeX3 编程风格是否适合您:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand { \tonality } { m m }
{
\ton_tonality:nn { #1 } { #2 }
}
\tl_new:N \l_ton_key_tl
\tl_new:N \l_ton_accidents_tl
\cs_new_protected:Npn \ton_tonality:nn #1 #2
{
% Normalize to uppercase
\tl_to_uppercase:n
{
% Get the key
\tl_set:Nx \l_ton_key_tl { \tl_head:n { #1 } }
% Get the accidents
\tl_set:Nx \l_ton_accidents_tl { \tl_tail:n { #1 } }
}
% check the key
\str_case:onn { \l_ton_key_tl }
{
{A}{ \ton_print_key:n {A} }
{B}{ \ton_print_key:n {B} }
{C}{ \ton_print_key:n {C} }
{D}{ \ton_print_key:n {D} }
{E}{ \ton_print_key:n {E} }
{F}{ \ton_print_key:n {F} }
{G}{ \ton_print_key:n {G} }
}
{ \msg_error:nn { tonality } { bad-key } !! }
% check the accidents
\str_case:onn { \l_ton_accidents_tl }
{
{} { }
{ES} { \ton_print_flat: }
{ESES}{ \ton_print_doubleflat: }
{IS} { \ton_print_sharp: }
{ISIS}{ \ton_print_doublesharp: }
}
{ \msg_error:nn { tonality } { bad-accidents } !! }
\ton_print_mode:n { #2 }
}
\cs_new:Npn \ton_print_mode:n #1 { \nobreakspace #1 }
\cs_new:Npn \ton_print_key:n #1 { #1 }
\cs_new:Npn \ton_print_flat: { \nobreakspace flat }
\cs_new:Npn \ton_print_doubleflat: { \nobreakspace doubleflat }
\cs_new:Npn \ton_print_sharp: { \nobreakspace sharp }
\cs_new:Npn \ton_print_doublesharp: {\nobreakspace doublesharp }
\msg_new:nnnn { tonality } { bad-key }
{ Key~not~in~range~A--G }
{ The~first~character~is~not~good }
\msg_new:nnnn { tonality } { bad-accidents }
{ Bad~accidents~specification }
{ The~string~for~the~accidents~is~wrong }
\ExplSyntaxOff
\begin{document}
\tonality{A}{minor}
\tonality{fis}{minor}
\tonality{fesis}{major}
\tonality{qisis}{major}
\end{document}
答案3
这个例子是普通的 tex,但当然可以在乳胶中起作用。
\def\zz#1{%
\edef\tmp{\noexpand\zzformat
\zzz#1\relax\relax\relax\relax\relax\relax}%
%show\tmp
\tmp}
\def\zzz#1#2#3#4#5#6#7{%
{#1}%
\ifx\relax#2{0}{}%
\else\ifx\relax#4{1}{#2#3}%
\else{2}{#2#3}\fi\fi}
\def\zzformat#1#2#3{%
#1 + #2 ( #3 )
}
\zz{a}
\zz{aes}
\zz{fisis}
\bye
答案4
感谢您的帮助,我终于找到了解决方案。下面是记录的调试版本 - 希望它对其他人有用。
\documentclass{article}
\usepackage{xstring}
\def\flatmodifier{es}
\def\sharpmodifier{is}
\def\naturalmodifier{}
\parindent 0cm
\def\parsethis#1{%
{\bf{#1}\par}%
\if\relax#1\relax\else%
\StrLeft{#1}{1}[\myfirstletter]% \myfirstletter = root tone
\StrPosition{abcdefg}{\myfirstletter}[\mynote]
\ifnum\mynote=0%
ERROR!!! Invalid note name (\myfirstletter)\par
\else
\StrGobbleLeft{#1}{1}[\myrestofword]% Eat first letter
\StrLeft{\myrestofword}{2}[\mysample]% \mysample = 2 characters after the root tone
\ifx\mysample\naturalmodifier% (Natural)
\def\mytonemodifier{Natural}%
\else
\ifx\mysample\flatmodifier% (Flat)
\def\mytonemodifier{Flat}%
\else
\ifx\mysample\sharpmodifier% (Sharp)
\def\mytonemodifier{Sharp}%
\else
\def\mytonemodifier{\relax}% (Invalid)
\fi
\fi
\fi
\if\mytonemodifier\relax
ERROR!!! Invalid note pitch modifier (\mysample)\par
\else
Okay, we can proceed.\par
\StrCount{\myrestofword}{\mysample}[\numofreps]% \numofreps = # repetitions of \mysample
\StrDel{\myrestofword}{\mysample}[\remainingchars]% \remainingchars = remaining characters after removing \mysample from the front
\if\relax\remainingchars\relax% IF there are remaining characters
{\small I found \numofreps\space copies of the string ``\mysample''.\par}%
\ifnum\numofreps<3%
\myfirstletter\ % Display note name
\ifnum\numofreps=0% No modifier
\mytonemodifier\ % Display note modifier
\else
\ifnum\numofreps=2% Double flat/sharp
Double %
\fi
\mytonemodifier\ % Display note modifier
\fi
\else% ELSE
ERROR: Too many accidental modifiers (\numofreps).%
\fi% ENDIF
\else
ERROR: There is a mixture of es and is.%
\fi
\fi
\fi
}
\begin{document}
\parsethis{h}\par
\parsethis{b}\par
\parsethis{be}\par
\parsethis{bas}\par
\parsethis{bes}\par
\parsethis{bese}\par
\parsethis{beses}\par
\parsethis{cisis}\par
\parsethis{feseses}\par
\parsethis{fesesis}\par
\parsethis{dadadadad}\par
\parsethis{basis}\par
\parsethis{benhottentottententententoonstelling}\par
\end{document}