![在数据工具中打印多个组行的范围](https://linux22.com/image/398986/%E5%9C%A8%E6%95%B0%E6%8D%AE%E5%B7%A5%E5%85%B7%E4%B8%AD%E6%89%93%E5%8D%B0%E5%A4%9A%E4%B8%AA%E7%BB%84%E8%A1%8C%E7%9A%84%E8%8C%83%E5%9B%B4.png)
我使用这个代码这个答案:
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{product.tex}
%Type =1,2...10
No,Type,Name,Description
1,1,A1,D1
2,1,A1,D2
3,1,A1,D3
30,1,A1,D30
31,2,A2,D31
131,2,A2,D131
132,3,A3,D132
133,3,A3,D133
134,3,A3,D134
249,4,A4,D249
1000,10,A10,D1000
\end{filecontents*}
\usepackage{datatool}
\DTLloaddb[autokeys=false]{products}{product.tex}
\newcommand{\printtype}[1]{%
\par
\section*{Type #1}
\DTLforeach*
[\DTLiseq{\Type}{#1}]% Condition
{products}% Database
{\No=No,\Type=Type,\Name=Name,\Description=Description}{%
\noindent\Name \quad \Description\par
}%
}
\begin{document}
%Here is some text.
\printtype{1}
Some breaking text here.
\printtype{3}
And then some final text.
\end{document}
我想改变一些东西,请帮帮我。
我可以使用\DTLforeach
atype=(1-3)
然后为类型范围 1、2、3 创建 pdf 吗?或者任何其他解决方案。
我不想单独调用\printtype{1}
、\printtype{2}
和printtype{3}
。
谢谢
答案1
您可以使用以下expl3
基于 的解决方案。它支持纯整数以及可能省略第一个和最后一个元素的范围:
\printtype{1}
\printtype{3}
\printtype{2-4}% all types between 2 and 4 (both inclusive)
\printtype{3-} % all types greater than or equal to 3
\printtype{-2} % all types lower than or equal to 2
\printtype{-} % all types
负数也受支持。为了不与-
范围语法的使用冲突,必须在括号内输入它们(非负数也可以,但不是必需的):
\printtype{{-1}} % only type -1
\printtype{-{-1}} % all types t for which t ≤ -1
\printtype{{-1}-2} % all types t for which -1 ≤ t ≤ 2
\printtype{{-1}-{2}} % ditto
\printtype{{-+--1}-{2}} % ditto (two minus signs cancel each other,
% because these are TeX 〈number〉s, actually)
\printtype{{-10}-{-1}} % all types t for which -10 ≤ t ≤ -1
完整代码:
\RequirePackage{filecontents}
\begin{filecontents*}{product.tex}
No,Type,Name,Description
0,-1,A-1,D-1
1,1,A1,D1
2,1,A1,D2
3,1,A1,D3
30,1,A1,D30
31,2,A2,D31
131,2,A2,D131
132,3,A3,D132
133,3,A3,D133
134,3,A3,D134
249,4,A4,D249
1000,10,A10,D1000
\end{filecontents*}
\documentclass[twocolumn]{article}
\usepackage{datatool}
\usepackage{xparse}
\ExplSyntaxOn
\msg_new:nnn { lforti } { invalid-test-expression-syntax }
{ Invalid~syntax~for~test~expression~'\exp_not:n~{#1}'. }
\regex_const:Nn \l__lforti_intexpr_regex
{ \A (?| (\d+) | \{ ([\+\-]* \d+) \} ) \Z }
\regex_const:Nn \l__lforti_rangeexpr_regex
{ \A (?| (\d*) | \{ ([\+\-]* \d*) \} ) \-
(?| (\d*) | \{ ([\+\-]* \d*) \} ) \Z }
% #1: value to test
% #2: test expression (integer or range)
\cs_new_protected:Npn \__lforti_check_match:nn #1#2
{
\regex_match:NnTF \l__lforti_rangeexpr_regex {#2}
{ \__lforti_check_range_match:nn {#1} {#2} }
{
\regex_match:NnTF \l__lforti_intexpr_regex {#2}
{ \__lforti_check_int_match:nn {#1} {#2} }
{ \msg_error:nnn { lforti } { invalid-test-expression-syntax } {#2} }
}
}
% #1: value to test
% #2: test expression (conforming to \l__lforti_intexpr_regex)
\cs_new_protected:Npn \__lforti_check_int_match:nn #1#2
{
% Extract the integer from the test expresion
\tl_set:Nn \l_tmpa_tl {#2}
\regex_replace_once:NnN \l__lforti_intexpr_regex { \1 } \l_tmpa_tl
% Compare it to #1
\int_compare:nNnTF {#1} = { \tl_use:N \l_tmpa_tl }
{ \use:c { @dtl@conditiontrue } }
{ \use:c { @dtl@conditionfalse } }
}
\tl_new:N \l__lforti_crm_first_tl % “start part“ of a range expression
\tl_new:N \l__lforti_crm_last_tl % “end part“ of a range expression
\bool_new:N \l__lforti_crm_ismatch_bool % result of the test
% #1: value to test
% #2: test expression (conforming to \l__lforti_rangeexpr_regex)
\cs_new_protected:Npn \__lforti_check_range_match:nn #1#2
{
\tl_set:Nn \l__lforti_crm_first_tl {#2}
\regex_replace_once:NnN \l__lforti_rangeexpr_regex { \1 }
\l__lforti_crm_first_tl
\tl_set:Nn \l__lforti_crm_last_tl {#2}
\regex_replace_once:NnN \l__lforti_rangeexpr_regex { \2 }
\l__lforti_crm_last_tl
\bool_set_true:N \l__lforti_crm_ismatch_bool
\tl_if_empty:NF \l__lforti_crm_first_tl
{ % the "first" part of the range is non-empty, perform the test
\int_compare:nNnT {#1} < { \tl_use:N \l__lforti_crm_first_tl }
{ \bool_set_false:N \l__lforti_crm_ismatch_bool }
}
\tl_if_empty:NF \l__lforti_crm_last_tl
{ % the "last" part of the range is non-empty, perform the test
\int_compare:nNnT {#1} > { \tl_use:N \l__lforti_crm_last_tl }
{ \bool_set_false:N \l__lforti_crm_ismatch_bool }
}
\bool_if:NTF \l__lforti_crm_ismatch_bool
{ \use:c { @dtl@conditiontrue } }
{ \use:c { @dtl@conditionfalse } }
}
\makeatletter
% Test function modeled after \DTLiseq
%
% #1: \Type or so (should expand to the integer subject to the test)
% #2: test expression (integer or range expression)
\NewExpandableDocumentCommand \lfortiIsMatch { m m }
{
\TE@throw
% #1 and #2 will be fully expanded when \DTLforeach* checks the condition
\exp_not:N \__lforti_check_match:nn {#1} {#2}
\exp_not:N \if@dtl@condition
}
% From this point on, up to \lforti@print@rbrace included: this is not needed
% for ”basic use” of my code. This allows one to print the test expression
% correctly in a title or so, without having to input it twice.
\cs_generate_variant:Nn \tl_replace_all:Nnn { Nx }
% Store a version of #2 into #1 in a form that is suitable for printing.
%
% #1: token list variable; will be defined if necessary, and assigned locally
% #2: test expression, with the standard catcodes
\cs_new_protected:Npn \__lforti_prepare_testexpr_for_print:Nn #1#2
{
\tl_clear_new:N #1
\tl_set:Nx #1 { \tl_to_str:n {#2} } % \detokenize (needed for the braces)
\tl_replace_all:Nxn #1
{ \char_generate:nn { `- } { 12 } }
{ \lforti@print@nolig@dash }
\tl_replace_all:Nxn #1
{ \char_generate:nn { `\{ } { 12 } }
{ \lforti@print@lbrace }
\tl_replace_all:Nxn #1
{ \char_generate:nn { `\} } { 12 } }
{ \lforti@print@rbrace }
}
\NewDocumentCommand \lforti@prepare@testexpr@for@print { m m }
{ \__lforti_prepare_testexpr_for_print:Nn #1 {#2} }
% Print a dash that can't participate in ligatures (definition inspired from
% LaTeX2e's \do@noligs)
\NewDocumentCommand \lforti@print@nolig@dash { }
{ \leavevmode \kern \z@ \char `- }
\NewDocumentCommand \lforti@print@lbrace { }
{ \leavevmode \char_generate:nn { `\{ } { 12 } }
\NewDocumentCommand \lforti@print@rbrace { }
{ \leavevmode \char_generate:nn { `\} } { 12 } }
\ExplSyntaxOff
% #1: test expression
\newcommand*{\printtype}[1]{%
% Save the test expression #1 in a form that is suitable for printing in the
% text---even in section titles written to the TOC. This little complication
% is only useful to allow test expressions such as {-+--1}-{2} to be printed
% correctly in a title and in the TOC without having to input them twice.
\lforti@prepare@testexpr@for@print{\lforti@testexpr@for@print}{#1}%
\section*{With test expression \texttt{%
\lforti@testexpr@for@print}}
\noindent
\begin{tabular}{@{}ll@{}}
\DTLforeach*
[\lfortiIsMatch{\Type}{#1}]% Condition
{products}% Database
{\No=No,\Type=Type,\Name=Name,\Description=Description}{%
\Name & \Description\\
}%
\end{tabular}
\par
}
\makeatother
\DTLloaddb[autokeys=false]{products}{product.tex}
\begin{document}
\raggedbottom % just for presentation of the example, because page breakpoints
% are scarce here...
\printtype{{-1}} % only type -1
\printtype{1}
\printtype{2}
\printtype{3}
\printtype{4}
\printtype{10}
\newpage
\printtype{1-3} % types between 1 and 3, both inclusive
\printtype{2-3} % types between 2 and 3, both inclusive
\printtype{3-} % all types t for which 3 ≤ t
\printtype{-2} % all types t for which t ≤ 2
\newpage
\printtype{-} % all types
\printtype{10000-} % types greated than or equal to 10000
\printtype{-{-1}} % all types t for which t ≤ -1
\printtype{{-1}-2} % all types t for which -1 ≤ t ≤ 2
\printtype{{-1}-{2}} % ditto
\printtype{{-+--1}-{2}} % ditto (two minus signs cancel each other,
% because these are TeX 〈number〉s, actually)
\printtype{{-10}-{-1}} % all types t for which -10 ≤ t ≤ -1
\end{document}
在第 1 页:
在第 2 页:
如果对于您的应用程序,您删除了在这里完成的测试表达式的特殊打印\section*
(添加它是为了为示例提供良好的输出,而不需要输入中的任何冗余),您可能会摆脱一些东西:\__lforti_prepare_testexpr_for_print:Nn
,,,和(如果您希望替换文本尽可能简短和简单,则\lforti@prepare@testexpr@for@print
可以以 开头)。\lforti@print@nolig@dash
\lforti@print@lbrace
\lforti@print@rbrace
\printtype
\noindent