我有数千条经过特别编号的特殊文本行。
001001=aaaaaaaa
001002=bbbbbbbb
001003=cccccccc
002001=dddddddd
002002=mmmmmmmm
002003=jjjjjjjj
003001=uuuuuuuu
003002=iiiiiiii
003003=vvvvvvvv
ETC。
在我的 Latex 文件中,我想插入带有简单数字条目(例如001001
或 )的特定指定文本\001001
,这些文本将在编译后显示aaaaaaaa
。我该怎么做?
请注意,我已经研究了以下问答,但仍然无法得出好的结果,我不能使用\catcode
。我使用xetex
,polyglossia
如果这有区别的话。
答案1
不使用外部包的方法如下:
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{\jobname.dat}
001001=aaaaaaaa
001002=bbbbbbbb
001002=cccccccc
002001=dddddddd
002002=mmmmmmmm
002003=jjjjjjjj
003001=uuuuuuuu
003002=iiiiiiii
003003=vvvvvvvv
\end{filecontents*}
\makeatletter
\newread\nina@read
\newcommand{\grabdata}[1]{%
\begingroup\endlinechar=\m@ne
\openin\nina@read=#1\relax
\loop\ifeof\nina@read\else
\read\nina@read to \@tempa
\nina@convert
\repeat
\closein\nina@read
\endgroup}
\def\nina@convert{%
\if\relax\detokenize\expandafter{\@tempa}\relax\else
\expandafter\nina@convert@i\@tempa\relax
\fi}
\def\nina@convert@i#1=#2\relax{%
\global\@namedef{nina@data@#1}{#2}}
\newcommand{\numentry}[1]{\@nameuse{nina@data@#1}}
\makeatother
\grabdata{\jobname.dat}
\begin{document}
\numentry{001001}
\numentry{001002}
\numentry{001003}
\numentry{002001}
\numentry{002002}
\numentry{002003}
\numentry{003001}
\numentry{003002}
\numentry{003003}
\end{document}
我使用它\jobname.dat
作为文件名只是为了不破坏我现有的文件。
如果数据文件被命名,foo.xyz
你将使用
\grabdata{foo.xyz}
然后数据将以以下形式提供
\numentry{001001}
数据文件逐行读取,每行在=
token 处拆分以获取键和值。因此,如果该行是
001001=aaaaaaaa
我们本质上
\@namedef{nina@data@001001}{aaaaaaaa}
(全局而言,我们用它\endlinechar=-1
来避免虚假空格并删除空行)。
答案2
一种方法是使用包裹datatool
。尝试打印002003
、001002
和的值,999999
结果如下:
笔记:
- 我用的
\IfStrEq
是包裹xstring
包,我更喜欢它的语法,但是如果需要的话,可能不用那个包也可以做到这一点。 - 包裹
filecontents
仅用于创建 MWE 来生成数据文件foo.dat
。否则就不需要了。
代码:
\documentclass{article}
\usepackage{datatool}
\usepackage{xstring}
\usepackage{filecontents}
\begin{filecontents*}{foo.dat}
001001=aaaaaaaa
001002=bbbbbbbb
001002=cccccccc
002001=dddddddd
002002=mmmmmmmm
002003=jjjjjjjj
003001=uuuuuuuu
003002=iiiiiiii
003003=vvvvvvvv
\end{filecontents*}
\newcommand{\LocateDataRow}[3]{%
% #1 = csname in which to store the required data
% #2 = database to search
% #3 = word to search for
%
\global\expandafter\def\csname#1\endcsname{UNDEFINED}% Default in case it is not found
%
\DTLforeach{#2}{%
\NumValue=NumValue,%
\DataValue=DataValue%
}{%
\IfStrEq{#3}{\NumValue}{%
% Found an exact match!! Yeah
\global\expandafter\def\csname#1\endcsname{\DataValue}%
\dtlbreak% Break out of for loop
}{%
% Did not find match -- continue searching
}%
}%
}%
\begin{document}
\DTLsetseparator{=}% Define separator of the data
\DTLloaddb[noheader,keys={NumValue,DataValue}]{myDB}{foo.dat}
\LocateDataRow{RequiredData}{myDB}{002003}\RequiredData
\LocateDataRow{RequiredData}{myDB}{001002}\RequiredData
\LocateDataRow{RequiredData}{myDB}{999999}\RequiredData
\end{document}
答案3
这是一个用于expl3
解析数据文件的解决方案。它使用属性列表将数据保存在内存中。用法意味着在此属性列表中查找键并显示其存储的值。
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{foo.dat}
001001=aaaaaaaa
001002=bbbbbbbb
001002=cccccccc
002001=dddddddd
002002=mmmmmmmm
002003=jjjjjjjj
foo bar
003001=uuuuuuuu
003002=iiiiiiii
003003=vvvvvvvv
\end{filecontents*}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\tl_new:N \l_ndata_line_tl
\tl_new:N \l_ndata_key_tl
\tl_new:N \l_ndata_value_tl
\prop_new:N \g_ndata_prop
% loading and parsing the data file
\cs_new:Npn \ndata_load_file:n #1 {
% opening a read stream
\ior_open:Nn \l_ndata_ior {#1}
% loop until we see "eof"
\bool_until_do:nn { \ior_if_eof_p:N \l_ndata_ior }
{
% read one line of data into a variable
\ior_to:NN \l_ndata_ior \l_ndata_line_tl
% if the line has no "=" we skip it
\tl_if_in:NnTF \l_ndata_line_tl {=}
{
% if it has we parse (low-level, strange input is usually strange
\exp_after:wN \ndata_parse:w \l_ndata_line_tl \q_stop
\typeout {line~ processed~ (\l_ndata_line_tl)}
}
{ \typeout {line~ without~ =~ ignored~ (\l_ndata_line_tl)} }
}
% close the stream as it is no longer needed
\ior_close:N \l_ndata_ior
% showing the resulting property list (comment out in real use)
\prop_show:N \g_ndata_prop
}
\cs_new:Npn \ndata_parse:w #1=#2\q_stop {
\tl_set:Nn \l_ndata_key_tl {#1}
\tl_set:Nn \l_ndata_value_tl {#2}
% remove any space to the left and right of key and value
\tl_trim_spaces:N \l_ndata_key_tl
\tl_trim_spaces:N \l_ndata_value_tl
% put the data into the property list
\prop_gput:Noo \g_ndata_prop \l_ndata_key_tl \l_ndata_value_tl
}
% using the data (instead of error handling for nonexistent keys I just used typeout)
\cs_new:Npn \ndata_use:n #1 {
\prop_get:NnNTF \g_ndata_prop {#1} \l_ndata_value_tl
{ \l_ndata_value_tl }
{ ???
\typeout{Warning:~ key~`#1`~ not~ known}
}
}
% document level commands:
\DeclareDocumentCommand \ndataload {m} { \ndata_load_file:n {#1} }
\DeclareDocumentCommand \ndata {m} { \ndata_use:n {#1} }
\ExplSyntaxOff
\begin{document}
\ndataload{foo.dat}
\ndata{002003}
\ndata{001002}
\ndata{999999}
\end{document}