当表格对齐不能解决问题时该怎么办?

当表格对齐不能解决问题时该怎么办?

当表格对齐不能解决问题时该怎么办?

我设计了一种将数据输入到几乎类似表格的列表中的方法(可能效率不高或方法“不正确”,但使用了来自 egreg 的一些有用的 LaTeX3 答案)。

主要问题是

  • 我的“表格”可能会在表格页脚栏出现的地方中断,如示例中所示。
  • 此外,它可以在页脚栏信息之后、标题之前中断。

这样,标题或页脚和标题就会通过分页符与表格分隔开。我知道我可以用 minipages 换行,但我需要可拆分的文本,因为其中一些参数列表非常长。

标准

  1. 除最后两项外,每一项均可分页,而最后两项必须与表格的页脚和标题保持一致。
  2. 每个项目的描述应采用段落格式(如我在示例中所演示的那样)
  3. jkodescriptionlist\jkoitem具有灵活数量的参数(只有前两个参数左对齐)。

我想要的是定义jkoitem应与表的页脚栏保持在一起的最小行数。(就此而言,中断也不应该在表的标题栏之后立即发生。)如果需要在表格页脚或标题的位置进行分页,则会发生分页,但它会将其中的一些项目带到下一页。

笔记:我能够通过使用\\*对应于\vadjust{\nobreak\vskip<length>}

我还愿意接受有关如何更好地实施这整个事情的建议。我认为解决方案与胶水有关。正如 cfr 所建议的,longtable 环境可能会起作用,但我不知道如何使用 longtable 实现此布局而不会使源代码变得一团糟。更新:我忘记了之前问过一个关于表格和 LaTeX3 的问题,这可能在这里有用:https://tex.stackexchange.com/a/243627/13552^. 我记得我当时只是因为时间限制而放弃了,而且我永远无法实现长表版本。

代码

我愿意接受建议

\documentclass{article}
\usepackage{fontspec}
\usepackage{lipsum}
\usepackage{caption}
\usepackage{xparse}
\usepackage{booktabs}
\usepackage{tikz}

\newcommand{\jkotabcap}[1]{\captionof{table}{#1}\bigskip}

\ExplSyntaxOn
\DeclareDocumentEnvironment{jkodescriptionlist}{O{}O{}}%
    {%
\noindent\rule{\textwidth}{\heavyrulewidth}\\*
\noindent\textbf{\textcolor{red}{#1}}\\*
\noindent\rule[2mm]{\textwidth}{\lightrulewidth}\par
    }%
    {%
    % Some glue should probably go here that prevents the bottom of the table from being alone on a page but I am not sure how to do this.
    % Do I need \leavevmode\vadjust{\penalty 10000} or something similar?
    {\nopagebreak\noindent\rule{\textwidth}{\heavyrulewidth}\\*
     \tiny #2\par}
    }%

\DeclareDocumentCommand{\jkoitem}{O{}m}{% Optional:comma list of values; mandatory:description
\noindent\dojkoitemargs:n{#1}\vadjust{\nobreak\vskip .1ex}
\null\hspace{2em}\par\parbox{\dimexpr\textwidth-4em\relax}{\footnotesize#2}\vskip 1.7ex plus 2ex % Description Format
    }%

\clist_new:N\jkoitemargs
\cs_new_protected:Nn\dojkoitemargs:n{{%
\clist_set:Nn\jkoitemargs{#1}%
\textbf{\clist_item:Nn \jkoitemargs {1}},~\clist_item:Nn \jkoitemargs {2} \hfill
\int_step_inline:nnnn {3}{1}{\clist_count:N \jkoitemargs}
    {%
        \int_compare:nTF { ##1 = \clist_count:N \jkoitemargs }
            {\clist_item:Nn \jkoitemargs {##1}}
            {\clist_item:Nn \jkoitemargs {##1},~}
    }
}}%

\ExplSyntaxOff

\begin{document}
% Syntax
%\jkoitem[Whatever fields are needed]
%{Description}
\section{Introduction}
\subsection{This Fun Document}
\lipsum[1-2]
Hello\\ % <-- Uncomment this line to push the entire bottom of the table to another page.
\begin{jkodescriptionlist}[HL7-Path, Name \hfill R/O, Rep\#][\textbf{R/0} = Required/Optional, \textbf{R} = Required,
\textbf{O} = Optional, \textbf{RO} = Required if known,
\textbf{REP\#} = Repitition, \textbf{Y} = entry can be
taken from the list, \textbf{N} = Individual Values,
\textbf{Number} = Maximum length of the list]
\jkoitem[MSH-6-2,homeCommunityID,R]
{OID of the affinity domain where the document will be stored.}
\jkoitem[MSH-19,languageCode,R]
{Specifies the human language of the document. Format according RFC-3066.}
\jkoitem[PID-3,patientInfo.socialSecurityNumber,R]
{Social security number of the patient. Important: The social security number will be
identified within the list of patient
identifiers (PID-3) by the OID of the social security association.}
\jkoitem[PID-3,patientInfo.sourcePatientID,R]
{Patient identifier of the local CIS/RIS/PACS…Important: The Patient Identifier
will be identified within the list of patient identifiers (PID-3) by the identifier type code PI.}
\jkoitem[PID-5-1,patientInfo.familyName,R]
{Family name of the patient.}
\jkoitem[PID-5-2,patientInfo.givenName,R]
{Given name of the patient.}
\jkoitem[PID-5-3,patientInfo.secondAndFurtherNames[0],O]
{Second and further names of the patient}
\end{jkodescriptionlist}
\jkotabcap{Fun Mapping Data.}
\label{Table:Fun Mapping Data}

\end{document}

输出

在此处输入图片描述


半成功的 TeX 改造 > 来自 wipet 代码的 LaTeX

我并不完全满意,因为它的\jkoitem参数不像原始版本那样灵活。例如,我的\jkoitem可以支持任意数量的参数(直到它们变得不美观)。此代码仅支持 3 个美观的参数。另外,我不确定我是否理解发生了什么,但我读到了 TeXBook 的第 112 页,并尝试实现我学到的一些关于断行和段落形状的知识。

代码

\documentclass{article}

\usepackage{lipsum}

\newcount\jcodenum

\def\jcode[#1]#2[#3]#4\endjcode{\goodbreak\hbox{}\par
    \hrule\medskip\hbox to\hsize{\bf #1}\medskip\hrule\medskip
    {\jcodenum=0
     \def\jkoitem[##1]##2{\advance\jcodenum by1 } % Dummy function just tallies up jkoitem's as they are parsed
     \typeout{**** Value of Counter (before first call of body 4): \the\jcodenum}% Print count of jcodenum at this point to log 
     #4 % prints contents of jcode=nothing because jkoitem prints nothing, serves to increment \jcodenum (see log output)
     \typeout{**** Value of Counter (after first call of body 4): \the\jcodenum}% Print count of jcodenum at this point to log 
     \interlinepenalty=10000% value of the penalty (node) added after each line of a paragraph.
     \let\jkoitem=\jkoitemx% Reassign jkoitem to jkoitemx, passing all args properly 
     #4 %This #4 represents the jkoitems with the new definition? Commenting this out erases content
         \typeout{**** Value of Counter (after redefinition and new call of body 4): \the\jcodenum}% Print count of jcodenum at this point to log 
     \medskip\hrule\nobreak\smallskip \tiny \noindent#3\bigskip\par}
}
\def\jkoitemx[#1,#2,#3]#4{\goodbreak\par \noindent{\bf#1}, \ignorespaces#2\hfill #3\par\nobreak
    \hangindent=\parindent{\footnotesize #4\par}% This #4 represents the descriptions
    \advance\jcodenum by-1% descrease count while it is increased
    \typeout{**** Value of Counter (inside of jkoitemx): \the\jcodenum}% Print count of jcodenum at this point to log 
    \ifnum\jcodenum<2 \nobreak \fi
}

\begin{document}
\lipsum[1-2]
\jcode[HL7-Path, Name \hfill R/O, Rep\#]
      [{\bf R/0}~=~Required/Optional, {\bf R}~=~Required,
       {\bf O}~=~Optional, {\bf RO}~=~Required if known, 
       {\bf REP\#}~=~Repitition, {\bf Y}~=~entry can be taken from the list,
       {\bf N}~=~Individual Values, {\bf Number}~=~Maximum length of the list]
\jkoitem[MSH-6-2,homeCommunityID,R]
{OID of the affinity domain where the document will be stored.}
\jkoitem[MSH-19,languageCode,R]
{Specifies the human language of the document. Format according RFC-3066.}
\jkoitem[PID-3,patientInfo.socialSecurityNumber,R]
{Social security number of the patient. Important: The social security
number will be
identified within the list of patient
identifiers (PID-3) by the OID of the social security association.}
\jkoitem[PID-3,patientInfo.sourcePatientID,R]
{Patient identifier of the local CIS/RIS/PACS…Important: The Patient
Identifier
will be identified within the list of patient identifiers (PID-3) by the
identifier type code PI.}
\jkoitem[PID-5-1,patientInfo.familyName,R]
{Family name of the patient.}
\jkoitem[PID-5-2,patientInfo.givenName,R]
{Given name of the patient.}
\jkoitem[PID-5-3,patientInfo.secondAndFurtherNames{[0]},O]
{Second and further names of the patient}
\jkoitem[PID-5-3,patientInfo.secondAndFurtherNames{[0]},O]
{Second and further names of the patient}
\jkoitem[PID-5-3,patientInfo.secondAndFurtherNames{[0]},O]
{Second and further names of the patient}
\jkoitem[PID-5-3,patientInfo.secondAndFurtherNames{[0]},O]
{Second and further names of the patient}
\jkoitem[PID-5-3,patientInfo.secondAndFurtherNames{[0]},O]
{Second and further names of the patient}
\endjcode
%\bye
\lipsum[1]
\end{document}

相关日志条目:

**** Value of Counter (before first call of body 4): 0
**** Value of Counter (after first call of body 4): 11
**** Value of Counter (inside of jkoitemx): 10
**** Value of Counter (inside of jkoitemx): 9
**** Value of Counter (inside of jkoitemx): 8
**** Value of Counter (inside of jkoitemx): 7
**** Value of Counter (inside of jkoitemx): 6
**** Value of Counter (inside of jkoitemx): 5
**** Value of Counter (inside of jkoitemx): 4
**** Value of Counter (inside of jkoitemx): 3
**** Value of Counter (inside of jkoitemx): 2
**** Value of Counter (inside of jkoitemx): 1
**** Value of Counter (inside of jkoitemx): 0
**** Value of Counter (after redefinition and new call of body 4): 0

输出

在此处输入图片描述


使用 Longtable 的改进方法(对 cfr 评论的回应)

2016 年 1 月 7 日更新

问题:

  • col1 不加粗(因为我使用的是\clist_use:Nn \jkoitemargs { & }而不是\textbf{\clist_item:Nn \jkoitemargs {1}}
  • col3 未正确右对齐
  • 行和其描述之间可能会出现分页符(已修复:\\\\*
  • 表格对齐看起来根本不像原来的那么好。

代码

\documentclass{article}
\usepackage{fontspec}
\usepackage[margin=2cm]{geometry}
\usepackage{longtable}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentEnvironment{mytable}{ O{} }
  {
    \clist_set:Nn \jkotableargs { #1 }
    \begin{longtable}{llrr}
    \clist_use:Nn \jkoitemargs { & } \endhead
  }
  {
    \end{longtable}
  }

\clist_new:N\jkoitemargs
\clist_new:N\jkotableargs
\NewDocumentCommand{\myitem}{ O{} m }
  {
  \clist_set:Nn \jkoitemargs { #1 }
  \clist_use:Nn \jkoitemargs { & }\\*
  \multicolumn{ 4 } {@{}l@{}}
    {
      \hspace{\parindent}
      \parbox{\dim_eval:n { \textwidth-\parindent } } {\footnotesize #2}
    }
  \\[\normalbaselineskip]
  }
\ExplSyntaxOff


\begin{document}
\begin{mytable}[HL7-Path, Name, R/O, Rep\#]
\myitem[col1,col2,col3,col4]{description on new row}
\myitem[MSH-6-2,homeCommunityID,R/O,Rep\#]{OID of the affinity domain where the document will be stored.}
\end{mytable}
\end{document}

答案1

您可以开始尝试以下代码

\newcount\jcodenum

\def\jcode[#1]#2[#3]#4\endjcode{\par
    \hrule\medskip\hbox to\hsize{\bf #1}\medskip\hrule\medskip
    {\jcodenum=0
     \def\jkoitem[##1]##2{\advance\jcodenum by1 }#4
     \interlinepenalty=10000 \let\jkoitem=\jkoitemx #4
     \medskip\hrule\nobreak\medskip #3\par}
}
\def\jkoitemx[#1,#2,#3]#4{\par \noindent{\bf#1}, \ignorespaces#2\hfill #3\par\nobreak
    #4\par
    \advance\jcodenum by-1 \ifnum\jcodenum<2 \nobreak \fi
}

\jcode[HL7-Path, Name \hfill R/O, Rep\#]
      [{\bf R/0} = Required/Optional, {\bf R} = Required,
       {\bf O} = Optional, {\bf RO} = Required if known, 
       {\bf REP\#} = Repitition, {\bf Y} = entry can be taken from the list,
       {\bf N} = Individual Values, {\bf Number} = Maximum length of the list]
\jkoitem[MSH-6-2,homeCommunityID,R]
{OID of the affinity domain where the document will be stored.}
\jkoitem[MSH-19,languageCode,R]
{Specifies the human language of the document. Format according RFC-3066.}
\jkoitem[PID-3,patientInfo.socialSecurityNumber,R]
{Social security number of the patient. Important: The social security
number will be
identified within the list of patient
identifiers (PID-3) by the OID of the social security association.}
\jkoitem[PID-3,patientInfo.sourcePatientID,R]
{Patient identifier of the local CIS/RIS/PACS…Important: The Patient
Identifier
will be identified within the list of patient identifiers (PID-3) by the
identifier type code PI.}
\jkoitem[PID-5-1,patientInfo.familyName,R]
{Family name of the patient.}
\jkoitem[PID-5-2,patientInfo.givenName,R]
{Given name of the patient.}
\jkoitem[PID-5-3,patientInfo.secondAndFurtherNames{[0]},O]
{Second and further names of the patient}
\endjcode

\bye

您可以在纯 TeX 中尝试此操作。用 LaTeX 重写此操作很简单。我不会这样做,因为我不支持 LaTeX。

由于测试,段落在行之间不可断开,并且最后两项加页脚也不可断开\ifnum\jcodenum<2 \nobreak \fi

答案2

已解决 wipet 答案的解释

2016 年 1 月 11 日更新:

以下代码演示了计算环境内每个项目的解决方案。它还演示了哪些类型的环境支持这种技术。它不受\newenvironment宏或xparse \NewDocumentEnvironment宏的支持,因为内容无法像在 TeX 中那样访问。在 LaTeX 中执行此操作的唯一方法是使用environ包与宏的\NewEnviron组合\BODY来插入环境的内容。

诀窍是先统计\additems 的数量,然后重新定义以从存储在计数器中的 s\additem总数中减去。 if/then 语句检查环境是否到达最后一个( )。因此,当有一个项目时(换句话说,计数器达到 1),将( / ) 添加到组合中,这样可以将倒数第二个项目和最后一个项目放在下一页上。真巧妙!谢谢 wipet!\additem\additem\ifnum\counter<2 \nobreak \fi\nobreak\penalty \@M\penalty 10000

\documentclass{article}
\usepackage{environ}
\usepackage{xparse}

\newcount\texcounter
\newcounter{latexNewEnvironcounter}
\newcounter{latexcounter}
\newcounter{latexthreecounter}

% TeX Syntax
\def\texenv#1\endtexenv{
  \def\additem[##1]##2{\advance\texcounter by1 }
  \typeout{**** Value texcounter (before first call of body): \the\texcounter} % Should be 0
  #1 % Typeset body of env
  \typeout{**** Value texcounter (after first call of body): \the\texcounter} % Should be 3
  \let\additem=\additemtex
  #1 % Retypeset body of env with new definition of \additem (\additemx)
  }

% environ Package NewEnviron
\NewEnviron{NewEnvironenv}{% environ package is the only way I know how to grab the body like in TeX
  \def\additem[##1]##2{\addtocounter{latexNewEnvironcounter}{1}}
  \typeout{**** Value latexNewEnvironcounter (before first call of body): \the\value{latexNewEnvironcounter}} % Should be 0
  \BODY % Typeset body of env
  \typeout{**** Value latexNewEnvironcounter (after first call of body): \the\value{latexNewEnvironcounter}} % Should be 3
  \let\additem=\additemlatexNewEnviron
  \BODY % Retypeset body of env with new definition of \additem (\additemx)
}{}

% LaTeX2e Syntax
\newenvironment{latexenv}{% Not supported because #1 cannot contain the body of the environment like in TeX
  \def\additem[##1]##2{\addtocounter{latexcounter}{1}}
  \typeout{****  Value latexcounter (before first call of body): \the\value{latexcounter}} % Should be 0
  %#1
  \typeout{**** Value latexcounter (after first call of body): \the\value{latexcounter}} % Should be 3
  \let\additem=\additemlatex
}{}

% LaTeX3 Syntax
\NewDocumentEnvironment{latexthreeenv}{}{% Not supported because #1 cannot contain the body of the environment like in TeX
  \def\additem[##1]##2{\addtocounter{latexthreecounter}{1}}
  \typeout{****  Value latexthreecounter (before first call of body): \the\value{latexthreecounter}} % Should be 0
  %#1
  \typeout{**** Value latexthreecounter (after first call of body): \the\value{latexthreecounter}} % Should be 3
  \let\additem=\additemlatexthree
}{}

% additem redefinition for TeX
\def\additemtex[#1,#2,#3]#4{\par \noindent{\bf#1}, \ignorespaces#2\hfill
    \def\comma{\def\comma{, }}\listargs #3,,\par\nobreak%Redefine comma to use space, see \listargs
    \hangindent=\parindent{\parbox{\dimexpr\textwidth-\parindent-1cm\relax}{\footnotesize #4}\par}% This #4 represents the descriptions
    \typeout{**** Value texcounter (inside additemx): \the\texcounter}% Print count
    \advance\texcounter by-1 % descrease count while it is increased
    \ifnum\texcounter<2 \nobreak \fi
}
\def\listargs#1,{\ifx,#1,\else\comma\ignorespaces#1\expandafter\listargs\fi}% Redefine args to user spaces


% additem redefinition for NewEnviron
\def\additemlatexNewEnviron[#1,#2,#3]#4{\par \noindent{\bf#1}, \ignorespaces#2\hfill
    \def\comma{\def\comma{, }}\listargs #3,,\par\nobreak%Redefine comma to use space, see \listargs
    \hangindent=\parindent{\parbox{\dimexpr\textwidth-\parindent-1cm\relax}{\footnotesize #4}\par}% This #4 represents the descriptions
    \typeout{**** Value latexNewEnvironcounter (inside additemlatexNewEnviron): \the\value{latexNewEnvironcounter}} % Print Count
    \addtocounter{latexNewEnvironcounter}{-1} % descrease count while it is increased
    \ifnum\latexNewEnvironcounter<2 \nobreak \fi
}

% additem redefinition for LaTeX2e
\def\additemlatex[#1,#2,#3]#4{\par \noindent{\bf#1}, \ignorespaces#2\hfill
    \def\comma{\def\comma{, }}\listargs #3,,\par\nobreak%Redefine comma to use space, see \listargs
    \hangindent=\parindent{\parbox{\dimexpr\textwidth-\parindent-1cm\relax}{\footnotesize #4}\par}% This #4 represents the descriptions
    \typeout{**** Value latexcounter (inside additemlatex): \the\value{latexcounter}} % Print Count
    \addtocounter{latexcounter}{-1} % descrease count while it is increased
    \ifnum\latexcounter <2 \nobreak \fi
}


% additem redefinition for LaTeX3
\def\additemlatexthree[#1,#2,#3]#4{\par \noindent{\bf#1}, \ignorespaces#2\hfill
    \def\comma{\def\comma{, }}\listargs #3,,\par\nobreak%Redefine comma to use space, see \listargs
    \hangindent=\parindent{\parbox{\dimexpr\textwidth-\parindent-1cm\relax}{\footnotesize #4}\par}% This #4 represents the descriptions
    \typeout{**** Value latexthreecounter (inside additemlatexthree): \the\value{latexthreecounter}} % Print Count
    \addtocounter{latexthreecounter}{-1} % descrease count while it is increased
    \ifnum\latexthreecounter<2 \nobreak \fi
}


\begin{document}

\section{Supported}
\subsection{\TeX}
\texenv
\additem[arg1,arg2,arg3]{A nice description. Value texcounter: \the\texcounter}
\additem[arg1,arg2,arg3]{A nice description. Value texcounter: \the\texcounter}
\additem[arg1,arg2,arg3]{A nice description. Value texcounter: \the\texcounter}
\endtexenv
\subsection{\texttt{environ} Package}
\begin{NewEnvironenv}
\additem[arg1,arg2,arg3]{A nice description. Value latexNewEnvironmentcounter: \the\value{latexNewEnvironcounter}}
\additem[arg1,arg2,arg3]{A nice description. Value latexNewEnvironmentcounter: \the\value{latexNewEnvironcounter}}
\additem[arg1,arg2,arg3]{A nice description. Value latexNewEnvironmentcounter: \the\value{latexNewEnvironcounter}}
\end{NewEnvironenv}

\section{Unsupported}

\subsection{\LaTeX\ 2e}
\begin{latexenv} % Does not work, see definition comment
\additem[arg1,arg2,arg3]{A nice description. Value latexcounter: \the\value{latexcounter}}
\additem[arg1,arg2,arg3]{A nice description. Value latexcounter: \the\value{latexcounter}}
\additem[arg1,arg2,arg3]{A nice description. Value latexcounter: \the\value{latexcounter}}
\end{latexenv}

\subsection{\LaTeX\ 3}
Workaround maybe possible, see egreg's hack: \\http://tex.stackexchange.com/a/172426/13552
\begin{latexthreeenv} % Does not work, see definition comment
\additem[arg1,arg2,arg3]{A nice description. Value latexthreecounter: \the\value{latexthreecounter}}
\additem[arg1,arg2,arg3]{A nice description. Value latexthreecounter: \the\value{latexthreecounter}}
\additem[arg1,arg2,arg3]{A nice description. Value latexthreecounter: \the\value{latexthreecounter}}
\end{latexthreeenv}

\end{document}

输出

[![在此处输入图片描述][1]][1]

日志

这样做的目的是为了证明哪些计数器按预期工作。我们预期:0,3,3,2,1。

纯 TeX

**** Value texcounter (before first call of body): 0
**** Value texcounter (after first call of body): 3
**** Value texcounter (inside additemx): 3
**** Value texcounter (inside additemx): 2
**** Value texcounter (inside additemx): 1

Environ

**** Value latexNewEnvironcounter (before first call of body): 0
**** Value latexNewEnvironcounter (after first call of body): 3
**** Value latexNewEnvironcounter (inside additemlatexNewEnviron): 3
**** Value latexNewEnvironcounter (inside additemlatexNewEnviron): 2
**** Value latexNewEnvironcounter (inside additemlatexNewEnviron): 1

标准 LaTeX\newenvironment

**** Value latexcounter (before first call of body): 0
**** Value latexcounter (after first call of body): 0
**** Value latexcounter (inside additemlatex): 0
**** Value latexcounter (inside additemlatex): -1
**** Value latexcounter (inside additemlatex): -2

xparse\NewDocumentEnvironment

**** Value latexthreecounter (before first call of body): 0
**** Value latexthreecounter (after first call of body): 0
**** Value latexthreecounter (inside additemlatexthree): 0
**** Value latexthreecounter (inside additemlatexthree): -1
**** Value latexthreecounter (inside additemlatexthree): -2

相关内容