Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have some thousands of special text lines specifically numbered.

001001=aaaaaaaa
001002=bbbbbbbb
001003=cccccccc

002001=dddddddd
002002=mmmmmmmm
002003=jjjjjjjj

003001=uuuuuuuu
003002=iiiiiiii
003003=vvvvvvvv

etc.

In my Latex file I want to insert that specific assigned text with a simple number entry such as 001001 or perhaps \001001 , which in return will show aaaaaaaa once compiled. How can I do this?

Please note that I've already studied following Q&A's but still couldn't come up with a good result, not could I use \catcode. I use xetex and polyglossia if that makes difference.

share|improve this question
1  
You would not be able to easily use \001001 for a command. Would something like \numentry{001001} (that returns aaaaaaaa) be a possibility? –  Werner Jun 15 '12 at 4:01
    
Yes, that would work. Please provide me with MWE. –  Nina Jun 15 '12 at 4:06
    
Welcome to TeX.SE. –  Peter Grill Jun 15 '12 at 7:54
    
Welcome to TeX.sx! Usually, we don't put a greeting or a "thank you" in our posts. While this might seem strange at first, it is not a sign of lack of politeness, but rather part of our trying to keep everything very concise. Upvoting is the preferred way here to say "thank you" to users who helped you. –  Stephen Jun 15 '12 at 9:10

3 Answers 3

up vote 7 down vote accepted

An approach without external packages can be as follows:

\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}

I've used \jobname.dat as the file name just not to clobber my existing files.

If the data file is named foo.xyz you'll use

\grabdata{foo.xyz}

and then the data will be available in the form

\numentry{001001}

The data file is read line by line and each line is split at the = token to get the key and the value. So if the line is

001001=aaaaaaaa

we essentially do

\@namedef{nina@data@001001}{aaaaaaaa}

(globally, as we use \endlinechar=-1 to avoid spurious spaces and get rid of empty lines).

share|improve this answer
    
Thank you egreg for your valuable help! –  Nina Jun 15 '12 at 20:01

Here is a solution using expl3 for parsing the data file. It uses a property list to keep the data in memory. Usage then means looking up the the key in this property list and displaying its stored value.

\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}
share|improve this answer
    
Is there a specific reason for loading both xparse and expl3 explicitly? If not, then \usepackage{xparse} should be sufficient as it loads expl3 for you I believe. –  Scott H. Jun 15 '12 at 18:57
2  
@ScottH. There is no technical reason. However, I like to load it as I want to emphasis that I use the programming layer of LaTeX3 AND (one of) its document user layers. In fact, given such a trivial user interface I could have shortened everything considerably by calling \ndata_load_file:n directly \ndataload thereby avoiding xparse altogether. But I wanted to show the general principle (and best practice) keeping the layers completely separate. –  Frank Mittelbach Jun 15 '12 at 19:29
1  
10-4, I just wanted to make sure I wasn't missing anything. Thanks. –  Scott H. Jun 15 '12 at 19:33
    
Thank you Frank for your valuable help! –  Nina Jun 15 '12 at 20:01

One way is to use the datatool package. An attempt to print the values of 002003, 001002, and 999999 yields:

enter image description here

Notes:

  • I used \IfStrEq from the the xstring package package as I prefer it's syntax, but this can probably be done without that pacakge if desired.
  • The filecontents package was used only to create a MWE to generate the data file foo.dat. It is not needed otherwise.

Code:

\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}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.