我确实喜欢 readarray 包的简单性,但是有没有办法设置/更改 readarray 生成的数据结构中的值?
\documentclass{standalone}
\usepackage{readarray}
\def\data{%
1 15 14 4
10 11 8 5
7 6 9 12
16 2 3 13
}
\readarray\data\dataA[4,4]
\begin{document}
value at (2,1) = \dataA[2,1]
%what i'm searching for:
%\set\dataA[2,1]{42}
\end{document}
答案1
\documentclass{standalone}
\usepackage{readarray}
\def\data{%
1 15 14 4
10 11 8 5
7 6 9 12
16 2 3 13
}
\readarray\data\dataA[4,4]
\begin{document}
value at (2,1) = \dataA[2,1]
\expandafter\def\csname dataA[2,1]\endcsname{42}
value at (2,1) = \dataA[2,1]
\end{document}
虽然这看起来像是“作弊”,但实际上这是包定义数组元素名称的方式:
\def\arg@name{\csname#3[\the@row,\the@col]\endcsname}%
如果你想要一个好看的宏,我在这里定义\setvalue
。这里没有完成,但可以将边界检查作为宏的一部分。
\documentclass{standalone}
\usepackage{readarray}
\makeatletter
\def\setvalue#1[#2]#3{%
\expandafter\def\csname
\expandafter\@gobble\string#1[#2]\endcsname{#3}%
}
\makeatother
\def\data{%
1 15 14 4
10 11 8 5
7 6 9 12
16 2 3 13
}
\readarray\data\dataA[4,4]
\begin{document}
value at (2,1) = \dataA[2,1]
\setvalue\dataA[2,1]{42}
value at (2,1) = \dataA[2,1]
\end{document}
姗姗来迟的补充
两年前,我向楼主承诺最终对包进行修改readarray
以初始化和扩展数组。最近我再次被提醒我还没有这样做。
我不能说接下来的内容将是进入软件包修订的最终版本,但是它呈现了我心中的想法(当然,一些内部宏的命名将不那么通用)。
首先,我有一个文件readarrayhotmod.tex
,可以将其\input
放入他们的文档中:
\RequirePackage{pgffor}
\newcount\readarrayendlinechar
% INITIALIATIONS
% ON \readdef, SEP CHAR INSERTED AFTER EACH RECORD;
% ON \readarray, SEP CHAR SERVES AS DATA-FIELD SEPARATOR
\readarraysepchar{ }
% ON \readdef, IGNORE END-LINE CHARS BY DEFAULT (NORMAL LaTeX MODE = 5)
\readarrayendlinechar=9
% DEFAULT CELL DATA FOR \initarray
\def\readarrayinitvalue{-}
% DEFAULT FIELD SEPARATORS FOR \typesetarray
\def\readarrayplanesep{\\---\\}
\def\readarrayrowsep{\\}
\def\readarraycolsep{,}
% DEFAULT CELL FORMATTING ON \typesetarray
\def\readarraycellset#1{#1}
%
\makeatletter
% FIXES ON EXISTING MACROS
\def\define@rootmacro#1{%
\expandafter\def\csname#1\endcsname[##1]{\rootmacro@aux{#1}{##1}}%
}
%
\def\nocheckbounds{\def\rootmacro@aux##1##2{\csname##1[##2]\endcsname%
}\typeout{readarray: bounds checking OFF}%
}
%
\def\checkbounds{\def\rootmacro@aux##1##2{%
\ifcsname##1[##2]\endcsname\csname##1[##2]\endcsname\else%
\readarrayboundfailmsg%
\typeout{readarray Warning: \RAbackslash##1[##2] undefined.}%
\fi%
}\typeout{readarray: bounds checking ON}%
}
%
\def\hypercheckbounds{\def\rootmacro@aux##1##2{%
\ifcsname##1[##2]\endcsname\csname##1[##2]\endcsname\else
\readarrayboundfailmsg%
\typeout{readarray Warning: \RAbackslash##1[##2] undefined:}%
\setcounter{index@count}{0}%
\parse@index##2,\relax%
\foreach\i in{1,...,\theindex@count}{%
\ifnum\parsed@index[\i]<1%
\relax\typeout{\nonposmessage{##1}{##2}}\fi%
}%
\ifnum \value{index@count}=1\relax%
\ifnum\parsed@index[1]>\csname##1CELLS\endcsname\relax
\typeout{\recordmessage{##1}{##2}}\fi%
\fi
\ifnum \value{index@count}=2\relax%
\ifnum\parsed@index[1]>\csname##1ROWS\endcsname\relax
\typeout{\rowmessage{##1}{\parsed@index[1]}}\fi%
\ifnum\parsed@index[2]>\csname##1COLS\endcsname\relax
\typeout{\colmessage{##1}{\parsed@index[2]}}\fi%
\fi
\ifnum \value{index@count}=3\relax%
\ifnum\parsed@index[1]>\csname##1PLANES\endcsname\relax
\typeout{\planemessage{##1}{\parsed@index[1]}}\fi%
\ifnum\parsed@index[2]>\csname##1ROWS\endcsname\relax
\typeout{\rowmessage{##1}{\parsed@index[2]}}\fi%
\ifnum\parsed@index[3]>\csname##1COLS\endcsname\relax
\typeout{\colmessage{##1}{\parsed@index[3]}}\fi%
\fi%
\fi%
}\typeout{readarray: bounds hyperchecking ON}%
}
%
\def\@readdef#1#2#3{%
\clear@array{#3}%
\edef\former@recordcount{\csname #3CELLS\endcsname}%
\def\first@row{T}%
\def\first@plane{T}%
\catcode\endlinechar=\readarrayendlinechar\relax %
\def#2{}%
\setcounter{@record}{0}%
\openin\rdar@file=#1%
\loop\unless\ifeof\rdar@file%
\read\rdar@file to\rdar@fileline % Reads a line of the file into \rdar@fileline%
\addtocounter{@record}{1}%
\expandafter\g@addto@macro\expandafter#2\expandafter{\rdar@fileline}%
\ifthenelse{\equal{\rdar@fileline}{}}{}{\expandafter\g@addto@macro%
\expandafter#2\expandafter{\read@array@sepchar}}%
\if T\first@row\read@array{#2}\setcounter{@col}{\numexpr(\Arg@listlen-1)}%
\edef\ncols{\arabic{@col}}\def\first@row{F}\setcounter{@row}{1}%
\else%
\if T\first@plane%
\ifthenelse{\equal{\rdar@fileline}{}}{%
\edef\nrows{\arabic{@row}}\def\first@plane{F}%
}{%
\addtocounter{@row}{1}%
}%
\fi%
\fi%
\def\record@name{\csname #3[\the@record]\endcsname}%
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter%
\expandafter\def\expandafter\record@name\expandafter{\rdar@fileline}%
\repeat%
\edef\nrecords{\arabic{@record}}%
\expandafter\edef\csname #3PLANES\endcsname{0}%
\expandafter\edef\csname #3ROWS\endcsname{\nrecords}%
\expandafter\edef\csname #3COLS\endcsname{0}%
\expandafter\edef\csname #3CELLS\endcsname{\nrecords}%
\closein\rdar@file%
\catcode\endlinechar=5 %
\define@rootmacro{#3}%
}
%
\def\clear@array#1{%
\ifcsname #1\endcsname%
\setcounter{@row}{0}%
\whiledo{\value{@row}<\csname #1ROWS\endcsname}{%
\stepcounter{@row}%
\ifnum\csname #1COLS\endcsname=0\relax%
\expandafter\let\csname #1[\the@row]\endcsname\undefined%
\else
\setcounter{@col}{0}%
\whiledo{\value{@col}<\csname #1COLS\endcsname}{%
\stepcounter{@col}%
\ifnum\csname #1PLANES\endcsname=0\relax%
\expandafter\let\csname #1[\the@row,\the@col]\endcsname
\undefined%
\else
\setcounter{@plane}{0}%
\whiledo{\value{@plane}<\csname #1PLANES\endcsname}{%
\stepcounter{@plane}%
\expandafter%
\let\csname #1[\the@plane,\the@row,\the@col]\endcsname
\undefined%
}%
\fi%
}%
\fi%
}%
\expandafter\let\csname #1PLANES\endcsname\undefined
\expandafter\let\csname #1ROWS\endcsname\undefined
\expandafter\let\csname #1PLANES\endcsname\undefined
\expandafter\let\csname #1\endcsname\undefined
\fi%
}
%
\def\nonposmessage#1#2{Positive indices [#2] required for #1.}
%%% END FIXES
%
\def\parsed@index[#1]{\csname parsed@index[#1]\endcsname}
%
\edef\RAbackslash{\expandafter\@firstoftwo\string\\}
%
\def\setvalue#1[#2]#3{%
\ifcsname\rdar@macroname#1[#2]\endcsname
\expandafter\gdef\csname\rdar@macroname#1[#2]\endcsname{#3}%
\else
\typeout{readarray Warning (setvalue = #3):
\RAbackslash\rdar@macroname#1[#2] undefined.}%
\fi%
}
\def\RAinitializedata#1[#2]#3{%
\expandafter\gdef\csname
\rdar@macroname#1[#2]\expandafter\endcsname\expandafter{#3}%
}
%
\def\initarray#1[#2]{%
\clear@array{\rdar@macroname#1}%
\expandafter\define@rootmacro\expandafter{\rdar@macroname#1}%
\setcounter{index@count}{0}%
\parse@index#2,\relax
\ifnum\value{index@count}=2\relax
\setcounter{use@args}{\numexpr\parsed@index[1]*\parsed@index[2]}
\expandafter\def\csname\rdar@macroname
#1PLANES\endcsname{0}
\expandafter\edef\csname\rdar@macroname
#1ROWS\endcsname{\parsed@index[1]}
\expandafter\edef\csname\rdar@macroname
#1COLS\endcsname{\parsed@index[2]}
\expandafter\edef\csname\rdar@macroname
#1CELLS\endcsname{\theuse@args}
\foreach\Z in{1,...,\parsed@index[1]}{%
\foreach\ZZ in{1,...,\parsed@index[2]}{%
\RAinitializedata#1[\Z,\ZZ]{\readarrayinitvalue}}}
\else
\ifnum\value{index@count}=3\relax
\setcounter{use@args}{\numexpr\parsed@index[1]*
\parsed@index[2]*\parsed@index[3]}
\expandafter\edef\csname\rdar@macroname
#1PLANES\endcsname{\parsed@index[1]}
\expandafter\edef\csname\rdar@macroname
#1ROWS\endcsname{\parsed@index[2]}
\expandafter\edef\csname\rdar@macroname
#1COLS\endcsname{\parsed@index[3]}
\expandafter\edef\csname\rdar@macroname
#1CELLS\endcsname{\theuse@args}
\foreach\Z in{1,...,\parsed@index[1]}{%
\foreach\ZZ in{1,...,\parsed@index[2]}{%
\foreach\ZZZ in{1,...,\parsed@index[3]}{%
\RAinitializedata#1[\Z,\ZZ,\ZZZ]{\readarrayinitvalue}}}}
\else
[initarray ERROR: 2-D or 3-D arrays only]
\fi
\fi
}
%
\def\mergearray#1#2[#3]{%
\setcounter{index@count}{0}%
\parse@index#3,\relax
\ifnum\value{index@count}=2\relax
\foreach\Z in{1,...,\csname\rdar@macroname#1ROWS\endcsname}{%
\foreach\ZZ in{1,...,\csname\rdar@macroname#1COLS\endcsname}{%
\edef\tmpA{\the\numexpr\Z+\parsed@index[1]-1,%
\the\numexpr\ZZ+\parsed@index[2]-1 }%
\edef\tmpB{\csname\rdar@macroname#1[\Z,\ZZ]\endcsname}%
\def\tmpC{\setvalue#2[\tmpA]}%
\expandafter\tmpC\expandafter{\tmpB}}}%
\else
\ifnum\value{index@count}=3\relax
\foreach\Z in{1,...,\csname\rdar@macroname#1PLANES\endcsname}{%
\foreach\ZZ in{1,...,\csname\rdar@macroname#1ROWS\endcsname}{%
\foreach\ZZZ in{1,...,\csname\rdar@macroname#1COLS\endcsname}{%
\edef\tmpA{\the\numexpr\Z+\parsed@index[1]-1,%
\the\numexpr\ZZ+\parsed@index[2]-1,%
\the\numexpr\ZZZ+\parsed@index[3]-1 }%
\edef\tmpB{\csname\rdar@macroname#1[\Z,\ZZ,\ZZZ]\endcsname}%
\def\tmpC{\setvalue#2[\tmpA]}%
\expandafter\tmpC\expandafter{\tmpB}}}}%
\else
[mergearray ERROR: 2-D or 3-D arrays only]
\fi
\fi
}
%
\def\addtoArg@toks#1{\global\Arg@toks\expandafter{\the\Arg@toks#1}}
\def\xaddtoArg@toks#1{\expandafter\addtoArg@toks\expandafter{#1}}
\def\xxaddtoArg@toks#1{\expandafter\xaddtoArg@toks\expandafter{#1}}
%
\def\typesetarray#1{\noindent\Arg@toks{}%
\ifnum\csname\rdar@macroname#1PLANES\endcsname>0\relax
\foreach\Z in{1,...,\csname\rdar@macroname#1PLANES\endcsname}{%
\ifnum\Z=1 \else\xaddtoArg@toks{\readarrayplanesep}\fi%
\foreach\ZZ in{1,...,\csname\rdar@macroname#1ROWS\endcsname}{%
\ifnum\ZZ=1 \else\xaddtoArg@toks{\readarrayrowsep}\fi%
\foreach\ZZZ in{1,...,\csname\rdar@macroname#1COLS\endcsname}{%
\ifnum\ZZZ=1 \else\xaddtoArg@toks{\readarraycolsep}\fi%
\xxaddtoArg@toks{\expandafter\readarraycellset\expandafter
{\csname\rdar@macroname#1[\Z,\ZZ,\ZZZ]\endcsname}}}%
}%
}%
\else
\foreach\Z in{1,...,\csname\rdar@macroname#1ROWS\endcsname}{%
\ifnum\Z=1 \else\xaddtoArg@toks{\readarrayrowsep}\fi%
\foreach\ZZ in{1,...,\csname\rdar@macroname#1COLS\endcsname}{%
\ifnum\ZZ=1 \else\xaddtoArg@toks{\readarraycolsep}\fi%
\xxaddtoArg@toks{\expandafter\readarraycellset\expandafter
{\csname\rdar@macroname#1[\Z,\ZZ]\endcsname}}%
}%
}%
\fi
\the\Arg@toks
}
\makeatother
除了提供\setvalue
上述答案中提供的错误检查之外,它还引入了 3 个新命令:
\initarray\<arrayname>[<2-D or 3-D size>]
\mergearray\<from-array>\<to-array>[<insert point]
\typeset\<arrayname>
示例包括\initarray\AB[6,6]
初始化一个 6x6 数组,每个单元格包含 的替换文本\arrayinitvalue
。合并示例是\mergearray\dataA\AB[3,2]
将dataA
数组合并到 数组中,从中的\AB
单元格开始。因此,如果是 4x4,它将跨越-- 。如果合并超出数组边界,则会在日志文件(目前是文档本身)中打印警告。该命令将输出数组,采用以下默认但可更改的设置:[3,2]
\AB
\dataA
\AB[3,2]
\AB[6,5]
\AB
\typesetarray\AB
\AB
\def\arrayplnsep{\\---\\}
\def\arrayrowsep{\\}
\def\arraycolsep{,}
\def\arrayset#1{#1}
这些设置说明在平面、行、列之间排版的内容以及如何排版单元格本身。例如,更改\arraycolsep
为&
将使排版适合环境。如果您希望直接排版,则将允许为每个单元格的排版分配固定空间。tabular
\def\arrayset#1{\makebox[5ex][r]{#1}}
\documentclass{article}
\usepackage{readarray}
\input readarrayhotmod.tex
% DEFAULTS
%% INITIALIATIONS
%% ON \readdef, SEP CHAR INSERTED AFTER EACH RECORD;
%% ON \readarray, SEP CHAR SERVES AS DATA-FIELD SEPARATOR
% \readarraysepchar{ }
%% ON \readdef, IGNORE END-LINE CHARS BY DEFAULT (NORMAL LaTeX MODE = 5)
% \readarrayendlinechar=9
%% DEFAULT CELL DATA FOR \initarray
% \def\readarrayinitvalue{-}
%% DEFAULT FIELD SEPARATORS FOR \typesetarray
% \def\readarrayplanesep{\\---\\}
% \def\readarrayrowsep{\\}
% \def\readarraycolsep{,}
%% DEFAULT CELL FORMATTING ON \typesetarray
% \def\readarraycellset#1{#1}
%%
\begin{filecontents*}[overwrite]{mydata.txt}
1,15,14,4
10,11,8,5
7,6,9,12
16,2,3,13
\end{filecontents*}
\begin{document}
\sbox0{\begin{tabular}{|c|}\hline x\end{tabular}}% LOADS cmex FONTS
\hypercheckbounds
\readarraysepchar{,}
\readdef{mydata.txt}\data
1. Set value in bounds and out of bounds\hrulefill
\readarray\data\dataA[-,\ncols]
value at (2,1) = \dataA[2,1]
\setvalue\dataA[2,1]{42}
value at (2,1) = \dataA[2,1]
\setvalue\dataA[2,7]{42}
2. Initialize 6x6 array, specify in and out of bound cells\hrulefill
\initarray\AB[6,6]
AB[2,1] = \AB[2,1]
AB[2,2] = \AB[2,2]
AB[3,7] = \AB[3,7]
3. Merge 4x4 array into 6x6, typeset as text and in tabular\hrulefill
\mergearray\dataA\AB[3,2]
\def\readarrayrowsep{\\}
\def\readarraycolsep{,}
\def\readarraycellset#1{\makebox[5ex][r]{#1}}
\typesetarray\AB
\def\readarrayrowsep{\\}
\def\readarraycolsep{&}
\def\readarraycellset#1{#1}
tabular: \begin{tabular}{cc|cccc}
\hline
\typesetarray\AB
\\\hline
\end{tabular}
4. Initialize 3x5x4 (3-D) array, set value\hrulefill
\renewcommand\readarrayinitvalue{Q}
\initarray\Q[3,5,4]
\Q[3,4,2]
\setvalue\Q[3,4,2]{SV}
\Q[3,4,2]
5. Merge initialized 2x2x2 AND read-in 2x2x4 arrays into 3x5x4 array\hrulefill
\renewcommand\readarrayinitvalue{R}
\initarray\R[2,2,2]
\readarray\data\dataB[-,2,4]
\mergearray\dataB\Q[1,4,1]
\mergearray\R\Q[2,2,1]
\def\readarrayplanesep{\\\hline}
\def\readarrayrowsep{\\}
\def\readarraycolsep{&}
\def\readarraycellset#1{#1}
\begin{tabular}{rrrrr}
\hline
\typesetarray\Q
\\\hline
\end{tabular}
6. Error checking when existing array is reinitialized\hrulefill
\initarray\Q[2,2]
\Q[0,2,2] \Q[1,2,2] \QPLANES
\end{document}
此代码在日志文件中产生以下警告
readarray: bounds hyperchecking ON
readarray Warning (setvalue = 42): \dataA[2,7] undefined.
readarray Warning: \AB[3,7] undefined:
COL=7 exceeds bounds(=6) for AB.
readarray Warning: \Q[0,2,2] undefined:
Positive indices [0,2,2] required for Q.
readarray Warning: \Q[1,2,2] undefined:
PLANE=1 exceeds bounds(=0) for Q.
和这个输出