我使用 datatool,想在当前数据之前显示下一个数据,可以吗?我需要帮助编写代码“在此显示(AAACoding+1)、CCCCoding+1...)的数据”
我的最少编码:
\documentclass[a5paper,oneside,8pt]{article}
\usepackage[a5paper,landscape,left=1.0cm,right=0.3cm,top=0.5cm,bottom=0.5cm]{geometry}
\usepackage{datatool}
\usepackage{filecontents}
\begin{filecontents*}{fileabc.tex}
AAA|BBB|CCC|DDD|
1|100|NT|E1|
2|109|NT|EE|
3|210|AT|E|
4|340|NT|E30|
5|12|AT|E31|
6|410|AT|E44|
7|234|NT|E77|
8|012|AT|E88|
\end{filecontents*}
\usepackage{datatool}
\DTLsetseparator{|}
\DTLsetdelimiter{"}
\DTLloaddb[autokeys=false]{fileabc}{fileabc.tex}
\newcommand{\printCCCCoding}[1]{%
\par
\DTLforeach*
[\DTLiseq{\CCCCoding}{#1}]%
{fileabc}% Database
{\CCCCoding=CCC,\AAACoding=AAA, \BBBCoding=BBB,\DDDCoding=DDD}{%
Next row: diplay here data of (AAACoding+1), CCCCoding+1...)
\\
Current row: \AAACoding \\
\noindent \CCCCoding \hspace{0.1cm} 2 \AAACoding \hspace{0.1cm} 3 \BBBCoding \hspace{0.1cm} 4 \DDDCoding \par\\
-----------\\
}%
}
\begin{document}
%\DTLdisplaydb{fileabc}
%\newpage
\\
\printCCCCoding{NT}
\end{document}
答案1
这是一个使用 LaTeX3 的解决方案。它的工作原理是将最后两行保持在滑动窗口中加载datatool
。您可以将此滑动窗口视为数据库行的缓冲区。它以 LaTeX3 标记列表序列的形式实现,其中每个标记列表只包含数据库每列的一个项目。
\RequirePackage{filecontents}
\begin{filecontents*}{fileabc.tex}
AAA|BBB|CCC|DDD|
1|100|NT|E1|
2|109|NT|EE|
3|210|AT|E|
4|340|NT|E30|
5|12|AT|E31|
6|410|AT|E44|
7|234|NT|E77|
8|012|AT|E88|
\end{filecontents*}
\documentclass{article}
\usepackage{xparse}
\usepackage{datatool}
\DTLsetseparator{|}
\DTLsetdelimiter{"}
\DTLloaddb[autokeys=false]{fileabc}{fileabc.tex}
\ExplSyntaxOn
% Sliding window encoding at most two database rows. Each <item> of the seq
% corresponds to a database row and is a token list that contains as many
% subitems as there are columns in the database.
\seq_new:N \l__lforti_window_seq
\cs_new_protected:Npn \lforti_load_db_row:nnnn #1#2#3#4
{
% Append the new row as a token list containing one <item> per database
% column.
\seq_put_right:Nn \l__lforti_window_seq { {#1} {#2} {#3} {#4} }
}
\tl_new:N \l__lforti_current_row_tl
\tl_new:N \l__lforti_next_row_tl
\str_new:N \l__lforti_tested_field_str
% Process the first row loaded in the sliding window, if any. The second row
% is the next one, and is used too in case the first row is a match.
%
% #1: index (starting from 1) of the field to test
% #2: value to compare to (a string)
\cs_new_protected:Npn \lforti_process_one_db_row:nn #1#2
{
\seq_pop_left:NN \l__lforti_window_seq \l__lforti_current_row_tl
\tl_if_eq:NNF \l__lforti_current_row_tl \q_no_value
{
\str_set:Nx \l__lforti_tested_field_str
{ \tl_item:Nn \l__lforti_current_row_tl {#1} }
\str_if_eq:VnT \l__lforti_tested_field_str {#2}
{ % There is a match on the tested field, get the next row
\seq_set_eq:NN \l_tmpa_seq \l__lforti_window_seq
\seq_pop_left:NN \l_tmpa_seq \l__lforti_next_row_tl
\tl_if_eq:NNF \l__lforti_next_row_tl \q_no_value
{
\par \noindent Next~row:~
\lforti_display_row:nN { \c_false_bool } \l__lforti_next_row_tl
\\
}
\noindent Current~row:~
% Full display of the current row
\lforti_display_row:nN { \c_true_bool } \l__lforti_current_row_tl
\\[1ex]
\rule { 4cm } { 0.4pt }
\par \skip_vertical:n { 1ex }
}
}
}
% #1: boolean expression indicating whether to do full display of the row
% #2: token list variable corresponding to the row contents (one <item> per
% field)
\cs_new_protected:Npn \lforti_display_row:nN #1#2
{
\bool_if:nT {#1} % Full display?
{ \tl_item:Nn #2 { 1 } \\ }
\tl_item:Nn #2 { 3 }
\hspace{0.1cm} 2~
\tl_item:Nn #2 { 1 }
\hspace{0.1cm} 3~
\tl_item:Nn #2 { 2 }
\hspace{0.1cm} 4~
\tl_item:Nn #2 { 4 }
}
\cs_generate_variant:Nn \lforti_load_db_row:nnnn { oooo }
% #1: column number for the tested value (1 for the first column, 2 for the
% second one, 3 for the third [CCC], etc.)
% #2: value to test against
\NewDocumentCommand \printCoding { m m }
{
\par
\seq_clear:N \l__lforti_window_seq
\DTLforeach* { fileabc } % database
{\CCCCoding=CCC, \AAACoding=AAA, \BBBCoding=BBB, \DDDCoding=DDD }
{
\lforti_load_db_row:oooo
{ \AAACoding } { \BBBCoding } { \CCCCoding } { \DDDCoding }
% Process the sliding window contents here only if it's full (the
% “current row” for \lforti_process_one_db_row:nn is always the first
% item of \l__lforti_window_seq; the second item, if any, is processed
% after the \DTLforeach* loop).
\int_compare:nNnT { \seq_count:N \l__lforti_window_seq } = { 2 }
{ \lforti_process_one_db_row:nn {#1} {#2} }
}
% Process the last row, if any (it is now the first element of
% \l__lforti_window_seq).
\lforti_process_one_db_row:nn {#1} {#2}
}
% Convenience user macro
\NewDocumentCommand \printCCCCoding { m }
{
\printCoding {3} {#1}
}
\ExplSyntaxOff
\begin{document}
\printCCCCoding{NT}
\end{document}
应正确处理边缘情况(当匹配位于最后一行时不打印“下一行”等):
\begin{filecontents*}{fileabc.tex}
AAA|BBB|CCC|DDD|
1|100|NT|E1|
2|109|NT|EE|
3|210|AT|E|
4|340|NT|E30|
5|12|AT|E31|
6|410|AT|E44|
7|234|NT|E77|
8|012|AT|E88|
9|777|NT|E99|
\end{filecontents*}
空数据库或一行数据库也能正确处理。例如:
\begin{filecontents*}{fileabc.tex}
AAA|BBB|CCC|DDD|
9|777|NT|E99|
\end{filecontents*}
注意:您可以非常轻松地调整 的定义,\printCCCCoding
以便使用来自其他列的值执行行选择测试( 的第一个参数\printCoding
是用于此目的的列号,从 1 开始)。当然,您可以\printCoding
在文档中使用任意多次。