我有一系列值需要按行打印在多列中。(这些值作为\def
变量保存,由程序生成,其中一些可以是空字符串。)
问题是如何避免出现空单元格,并让下一个单元格自动取代前一个单元格的位置(如果前一个单元格是空的)。例如,我有以下非空值:,,,,,,排列成Author
3列,如下所示:Composer
Publisher
Year
Author Composer Publisher
Year
那是两行。如果我们再添加一个条目,它应该进入下一个单元格Year
。
但是,如果出版商为空,则年份应自动出现在第一行:
Author Composer Year
我有\Author
、\Composer
、\Publisher
等\Year
需要按此方式排列的变量列表。我只想写类似这样的内容:
\SomeEnvironment{\Author, \Composer, \Publisher, \Year, \something so on}
并让环境自动找出删除空的并让下一个流动。
如何实现这一点?
PS:对于那些好奇的人来说,这是卡姆蒂:卡纳提克音乐排版环境项目。
答案1
不确定你想要的是纯文本还是乳胶文本,虽然这是一个纯文本文档,但宏应该可以与两者配合使用
\def\SomeEnvironment#1{%
\par\noindent
\xSomeEnvironment #1\relax}
\def\xSomeEnvironment#1{%
\ifx\relax#1%
\hfill
\else
\ifx\empty#1%
\else
\hbox to 0.3333\hsize{#1\hfill}\hfil
\fi
\expandafter\xSomeEnvironment
\fi}
\def\Author{Author}
\def\Composer{Composer}
\def\Publisher{}
\def\Year{Year}
\def\something{something}
\def\somethingelse{somethingelse}
\SomeEnvironment{\Author \Composer \Publisher \Year \something \somethingelse}
\bye
这个循环会检查每个标记,如果是,则\relax
停止;如果定义相同,则\empty
跳过该标记;否则,它会将内容设置在文本宽度为 1/3(0.333330)的框中。因此,不需要明确的换行或对齐点,当段落以通常的方式分成几行时,唯一可能发生换行的地方是每三个条目一次,因为框永远不会换行。要获得更多列,只需更改 0.33333,例如 0.25 会给您四列。
编辑:
您的实际情况有点复杂,因为您不只是一个标记,您要么想要一个大括号组,要么\var
后面跟着一个大括号组,而且您的定义不是空的,而是由于\relax
怪异而定义的\csname
。
\documentclass{article}
\newcommand{\var}[1]{\csname #1\endcsname}
\newcommand{\DefVar}[2]{\expandafter\newcommand\csname #1\endcsname{#2}}
\newcommand{\SetVar}[2]{\ifcsname #1\endcsname
\expandafter\renewcommand\csname #1\endcsname{#2}
\else \DefVar{#1}{#2} \fi}
\newcommand{\Var}{\var}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\def\SomeEnvironment#1{%
\par\noindent
\xSomeEnvironment #1\relax}
\def\xSomeEnvironment#1{%
\ifx\var#1\relax
\expandafter\xxxSomeEnvironment
\else
\ifx\relax#1\relax
\hfill
\else
\def\tempa{#1}%
\expandafter\expandafter\expandafter\xxSomeEnvironment
\expandafter\expandafter\expandafter\tempa
\fi
\fi}
\def\xxSomeEnvironment#1{%
\hbox to 0.3333\hsize{#1\hfill}\hfil
\expandafter\xSomeEnvironment
}
\def\xxxSomeEnvironment#1{%
\expandafter\let\expandafter\tempa\csname#1\endcsname
\ifx\relax\tempa
\expandafter\xSomeEnvironment
\else
\expandafter\xxSomeEnvironment\csname#1\expandafter\endcsname
\fi}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}
\def\index[#1]#2{}
% Below attributes are programatically set by user in the CarMusTy Document
%
% Note that these could be unicode values in real documents, hence we need these as \csname in the \var{} definitions
%
% Als note that if a variable is not set any value, such as Song2Composer below, it will not be defined (which is fine because the \var{} allows it to be \relax)
% For testing these are commented out below, making them undefined.
%
\DefVar{BookTOC}{Book Title}
\DefVar{BookTitle}{Book Title}
\DefVar{BookSubTitle}{Sub Title}
\DefVar{BookAuthor}{Book Author}
\DefVar{BookPublisher}{Book Publisher}
\DefVar{BookYear}{Book Year}
\DefVar{Song1Title}{Song Title1}
\DefVar{Song1Author}{Author1\index[Author]{Author1!\var{SongTitle}}}
\DefVar{Song1Composer}{Composer1\index[Composer]{Composer1!\var{SongTitle}}}
\DefVar{Song1Singers}{Singers1\index[Singers]{Singers1!\var{SongTitle}}}
\DefVar{Song1Movie}{Movie1\index[Movie]{Movie1!\var{SongTitle}}}
\DefVar{Song1Year}{Year1}
\DefVar{Song1Raga}{RAGAVARDHINI\index[Raga]{RAGAVARDHINI!\var{SongTitle}}}
\DefVar{Song1Tala}{tripuTa\index[Tala]{tripuTa!\var{SongTitle}}}
\DefVar{Song1Verse1Title}{Verse}
\DefVar{Song1Verse2Title}{Verse}
\DefVar{Song2Title}{Song Title2}
\DefVar{Song2Author}{Author2\index[Author]{Author2!\var{SongTitle}}}
%\DefVar{Song2Composer}{Composer1\index[Composer]{Composer1!\var{SongTitle}}}
\DefVar{Song2Singers}{Singers1\index[Singers]{Singers1!\var{SongTitle}}}
\DefVar{Song2Movie}{Movie2\index[Movie]{Movie2!\var{SongTitle}}}
\DefVar{Song2Year}{Year2}
\DefVar{Song2Raga}{Raga2\index[Raga]{Raga2!\var{SongTitle}}}
%\DefVar{Song2Tala}{Tala2\index[Tala]{Tala2!\var{SongTitle}}}
\DefVar{Song2Verse1Title}{Verse}
\DefVar{Song2Verse2Title}{Verse}
%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% Lets Print them
\section*{}
{\huge{Song Title}}
\SomeEnvironment{{Author} {Composer} {Singers} {Movie} {Year} }
% Uncomment the below lines to see the error
\section*{}
{\huge\var{Song1Title}}
\SomeEnvironment{\var{Song1Author} \var{Song1Composer} \var{Song1Singers} \var{Song1Movie} \var{Song1Year}} % << - Uncomment this line to see the error
\section*{}
{\huge\var{Song2Title}}
\SomeEnvironment{\var{Song1Author} \var{Song1Composer} \var{Song1Singers} \var{Song1Movie} \var{Song1Year}} % << - Uncomment this line to see the error
\end{document}
答案2
好吧,我违抗了键值系统专利持有者大卫卡莱尔的命令,决定采用键值语法。
\documentclass{article}
\usepackage{keyreader}[2012/01/14]
\usepackage{catoptions}[2011/12/17]
% Load geometry to enlarge the print area:
\usepackage[left=2cm,right=2cm]{geometry}
\makeatletter
\new@def*\var#1{\usename{carm@#1}}
\newletcs\Var\var
\def\Arrange#1{\par\noindent\xArrange#1\@nnil}
\def\xArrange#1{%
\expandafter\ifcseqTF\@car#1\@nil\var{%
\xxArrange
}{%
\expandafter\ifcseqTF\@car#1\@nil\@nnil{%
\hfill
}{%
\hb@xt@\dimexpr\carm@alignment{#1\hfill}\hfil
\xArrange
}%
}%
}
\def\xxArrange#1{%
\ifcsndefFT{carm@\cpttrimspaces{#1}}{}{%
\hb@xt@\dimexpr\carm@alignment{\@nameuse{carm@\cpttrimspaces{#1}}\hfill}\hfil
}%
\xArrange
}
% I don't want us to redefine \index, which is a LaTeX command. Hence
% I use \iindex instead. I assume that \iindex has one optional argument.
\new@def*\iindex{\cpt@testopt\iindex@a{}} % no \robust@def here!
\new@def*\iindex@a[#1]#2{}
\robust@def*\carm@getcallback#1#2{%
\def\@tempa##1#1##2\carm@nil{%
\edef\call@back{\cpttrimspaces{##2}}%
\carm@split##1==\carm@nil
}%
\@tempa#2\carm@nil
}
\robust@def*\carm@split#1=#2=#3\carm@nil{%
\edef\@tempa{\cpttrimspaces{#1}}%
\edef\@tempb{\cpttrimspaces{#2}}%
\edef\key@values{\csliststack,\key@values
\expandcsonce\@tempa=\expandcsonce\@tempb}%
\ifcsndefFT{CARM@carmusty@\@tempa}{}{%
\if@carmst
\@latex@error{CarMusty key '\@tempa' redefined}\@ehc
\else
\@latex@warning@no@line{CarMusty key '\@tempa' redefined}%
\fi
}%
\cptexpandsecond{\define@cmdkey[CARM]{carmusty}[carm@]}%
{{\expandcsonce\@tempa}[{\expandcsonce\@tempb}]%
{\expandcsonce\call@back}}%
}
\robust@def*\carmustykeys{\cpt@teststopt\carmustykeys@a{define}}
\robust@def*\carmustykeys@a[#1]{%
\let\if@carmst\ifcpt@st
\begingroup
\endlinechar\m@ne
\xifstrcmpTF{\cpttrimspaces{#1}}{define}{%
\definecarmustykeys
}{%
\xifstrcmpTF{\cpttrimspaces{#1}}{set}{%
\setcarmustykeys
}{%
\@latex@error{Unknown carmusty action '\detokenize{#1}'}\@ehc
}%
}%
}
\robust@def*\definecarmustykeys#1{%
\endgroup
\def\key@values{}%
\cptdocommalist{#1}{%
\ifinsetTF{.code=}{##1}{%
\carm@getcallback{.code=}{##1}%
}{%
\ifinsetTF{.code =}{##1}{%
\carm@getcallback{.code =}{##1}%
}{%
\carm@getcallback{.code=}{##1.code=}%
}%
}%
}%
\cptexpandargonce{\krdsetkeys[CARM]{carmusty}}\key@values
}
\robust@def*\setcarmustykeys#1{%
\endgroup
\cptexpandsecond\krdsetkeys{\if@carmst*\fi}[CARM]{carmusty}{#1}%
}
% When defining keys, the star (*) variant of \carmustykeys will
% raise an error when an existing key is being redefined.
% When setting keys, the star (*) variant of \carmustykeys will use
% the star variant of \setkeys. See the documentation of 'keyreader'
% or 'xkeyval' to see the meaning of the starred form of \setkeys.
% Actually, we don't use \setkeys but the more robust \krdsetkeys.
% Examples:
\carmustykeys*[define]{%
keya = .3333\hsize .code = \def\x##1{#1##1},
% Uncomment the following line to get an error (keya is being redefined):
% keya = default of keya .code = \def\result{generate error}
}
\carmustykeys*[set]{%
keya = valuea
}
% Real business:
\carmustykeys{%
alignment = .3333\hsize,
BookTOC = Book Title,
BookTOC = Book Title, % redefined - see log file for warning
BookTitle = Book Title,
BookSubTitle = Sub Title,
BookAuthor = Book Author,
BookPublisher = Book Publisher,
BookYear = Book Year,
Song1Title = Song Title1,
Song1Author = Author1\iindex[Author]{Author1!\var{SongTitle}},
Song1Composer = Composer1\iindex[Composer]{Composer1!\var{SongTitle}},
Song1Singers = Singers1\iindex[Singers]{Singers1!\var{SongTitle}},
Song1Movie = Movie1\iindex[Movie]{Movie1!\var{SongTitle}},
Song1Year = Year1,
Song1Raga = RAGAVARDHINI\iindex[Raga]{RAGAVARDHINI!\var{SongTitle}},
Song1Tala = tripuTa\iindex[Tala]{tripuTa!\var{SongTitle}},
Song1Verse1Title = Verse,
Song1Verse2Title = Verse,
Song2Title = Song Title2,
Song2Author = Author2\iindex[Author]{Author2!\var{SongTitle}},
Song2Composer = Composer1\iindex[Composer]{Composer1!\var{SongTitle}},
Song2Singers = Singers1\iindex[Singers]{Singers1!\var{SongTitle}},
Song2Movie = Movie2\iindex[Movie]{Movie2!\var{SongTitle}},
Song2Year = Year2,
Song2Raga = Raga2\iindex[Raga]{Raga2!\var{SongTitle}},
Song2Tala = Tala2\iindex[Tala]{Tala2!\var{SongTitle}},
Song2Verse1Title = Verse,
Song2Verse2Title = Verse,
}
\makeatother
% If needed, you can add new keys by doing:
% \carmustykeys[define]{key1=value1,<...>,key2=value2}
% To change the alignment, you can do:
% \carmustykeys[set]{alignment=<some value>}
% Let's print them:
\begin{document}
\parindent0pt
\carmustykeys[set]{alignment=.1333\hsize}
\textbf{Song Title}
\Arrange{{Author} {Composer} {Singers} {Movie} {Year} }
\par\medskip
\textbf{\var{Song1Title}}
\Arrange{\var{Song1Author} \var{Song1Composer} \var{Song1Singers}
\var{Song1Movie} \var{Song1Year} \var{Song1Verse2Title}}
\par\medskip
\textbf{\var{Song2Title}}
\Arrange{\var{Song1Author} \var{Song1Composer} \var{Song1Singers}
\var{Song1Movie} \var{Song1Year}}
\end{document}