Erste Methode

Erste Methode

Nachverfolgungdiese Antwort, wie kann ich ein optionales Argument des Befehls haben \getValue, das die Spalte angibt, in der ich den Zellenwert nachschlage, sodass es die folgende Syntax hat?

\getValue\<macro name>%
[<optional column number with default of 2, and the counting starts with 1 at the very first column>]%
{<search phrase>}%
{<data of the csv file>}

Beispielsweise \getValue\SndParThrd[4]{Second Parameter}{mydata}sollte (nach dem Optimieren des folgenden Codes) 44in gespeichert werden \SndParThrd.

Sollte außerdem in \getValue\SndParFrst{Second Parameter}{mydata}gespeichert werden .3\SndParFrst

\begin{filecontents*}{test.csv}
Third Parameter  , 7 , 9  , 
First Parameter  , 5 , 10 ,
Second Parameter , 3 , 6  , 44
\end{filecontents*}

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
% Step 1: reading the file
\ior_new:N \l__diaa_csv_ior
\ior_new:N \l__diaa_csv_str_bool
\NewDocumentCommand \ReadCSV { s m >{ \SplitArgument {1} {,} }O{ 1,2 } m }
  {
    \IfBooleanTF {#1}
      { \bool_set_true:N \l__diaa_csv_str_bool }
      { \bool_set_false:N \l__diaa_csv_str_bool }
    \diaa_csv_read:nnnn {#2} #3 {#4}
  }
\cs_new_protected:Npn \diaa_csv_read:nnnn #1 #2 #3 #4
  {
    \prop_new:c { g__diaa_csv_#1_prop }
    \ior_open:NnTF \l__diaa_csv_ior {#4}
      { \__diaa_csv_read:cnn { g__diaa_csv_#1_prop } {#2} {#3} }
      { \msg_error:nnn { diaa } { file-not-found } {#4} }
  }
\msg_new:nnn { diaa } { file-not-found }
  { File~`#1'~not~found. }
\cs_new_protected:Npn \__diaa_csv_read:Nnn #1 #2 #3
  {
    \bool_if:NTF \l__diaa_csv_str_bool
      { \ior_str_map_inline:Nn }
      { \ior_map_inline:Nn }
        \l__diaa_csv_ior
        {
          \prop_put:Nxx #1
            { \clist_item:nn {##1} {#2} }
            { \clist_item:nn {##1} {#3} }
        }
  }
\cs_generate_variant:Nn \__diaa_csv_read:Nnn { c }
%
% Step 2: getting the values
\NewDocumentCommand \getValue { m m m }
  { \tl_set:Nx #1 { \diaa_csv_item:nn {#2} {#3} } }
\NewExpandableDocumentCommand \CSVItem { m m }
  { \diaa_csv_item:nn {#1} {#2} }
\cs_new:Npn \diaa_csv_item:nn #1 #2
  { \prop_item:cn { g__diaa_csv_#2_prop } {#1} }
\ExplSyntaxOff

\begin{document}

\ReadCSV{mydata}{test.csv}

\getValue\rdPar{Third Parameter}{mydata}
\rdPar

\edef\stPar{\CSVItem{First Parameter}{mydata}}%
\stPar

\end{document}

Antwort1

Dies ist eine modifizierte Version vonPhelype Oleiniks Antwortauf die du in der Frage verwiesen hast. Die erste Methode ist kürzer, die zweite ist besser. :-)

Erste Methode

Die Spaltennummern in der CSV-Datei beginnen bei 1. Die neuen Befehle haben die folgende Syntax:

\ReadCSV[*] {label} [key column] {value columns} {file}

WoSchlüsselspalteDer Standardwert ist 1 undWertespaltenist eine durch Kommas getrennte Liste von Spaltennummern (nur Werte aus diesen Spalten werden gespeichert, \ReadCSVum ein späteres Abrufen durch \getValueund zu ermöglichen \CSVItem).

\getValue {\macro} [value column] {key} {label}

Dies ist, was Sie in der Frage gefragt haben.WertespalteDer Standardwert ist 2. Der Inhalt vonWertespalteentsprechend der angegebenenSchlüsselgespeichert ist (was eine Token-Listenvariable \macrosein könnte ).expl3

\CSVItem {key} [value column] {label}

Dieser Befehl ist vollständig erweiterbar. Er erweitert rekursiv den Inhalt vonWertespalteentsprechend der angegebenenSchlüssel.WertespalteDer Standardwert ist 2, wie in \getValue.

\begin{filecontents*}{test.csv}
Third Parameter  , 7 , 9  ,
First Parameter  , 5 , 10 ,
Second Parameter , 3 , 6  , 44
\end{filecontents*}

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
% Step 1: reading the file
\ior_new:N \l__diaa_csv_ior
\bool_new:N \l__diaa_csv_str_bool
\seq_new:N \l__diaa_csv_tmp_seq

% str mode (bool/star), label, key column, value columns, file
\NewDocumentCommand \ReadCSV { s m O{1} m m }
  {
    \IfBooleanTF {#1}
      { \bool_set_true:N \l__diaa_csv_str_bool }
      { \bool_set_false:N \l__diaa_csv_str_bool }
    \diaa_csv_read:nnnn {#2} {#3} {#4} {#5}
  }

% label, key column, value columns, file
\cs_new_protected:Npn \diaa_csv_read:nnnn #1 #2 #3 #4
  {
    \seq_set_split:Nnn \l__diaa_csv_tmp_seq { , } {#3}
    \seq_map_inline:Nn \l__diaa_csv_tmp_seq
      { \prop_new:c { g__diaa_csv_#1_##1_prop } }

    \ior_open:NnTF \l__diaa_csv_ior {#4}
      {
        \__diaa_csv_read:nn {#1} {#2}
        \ior_close:N \l__diaa_csv_ior
      }
      { \msg_error:nnn { diaa } { file-not-found } {#4} }
  }

\msg_new:nnn { diaa } { file-not-found }
  { File~`#1'~not~found. }

% label, key column
\cs_new_protected:Npn \__diaa_csv_read:nn #1 #2
  {
    \bool_if:NTF \l__diaa_csv_str_bool
      { \ior_str_map_inline:Nn }
      { \ior_map_inline:Nn }
        \l__diaa_csv_ior
        {
           \seq_map_inline:Nn \l__diaa_csv_tmp_seq
             {
               \prop_put:cxx { g__diaa_csv_#1_####1_prop }
                 { \clist_item:nn {##1} {#2} }
                 { \clist_item:nn {##1} {####1} }
             }
        }
  }

% Step 2: getting the values
% macro or tl var, value column, key, label
\NewDocumentCommand \getValue { m O{2} m m }
  { \tl_set:Nx #1 { \diaa_csv_item:nnn {#3} {#2} {#4} } }

% key, column containing the desired value, label
\NewExpandableDocumentCommand \CSVItem { m O{2} m }
  { \diaa_csv_item:nnn {#1} {#2} {#3} }

% key, column containing the desired value, label
\cs_new:Npn \diaa_csv_item:nnn #1 #2 #3
  { \prop_item:cn { g__diaa_csv_#3_#2_prop } {#1} }
\ExplSyntaxOff

\begin{document}

% Use default column for the key (1)
\ReadCSV{mydata}{2,4}{test.csv} % discard the third column

\getValue\rdPar[4]{Second Parameter}{mydata}
\rdPar                         % 44

\getValue\rdPar{Second Parameter}{mydata}
\rdPar                         % 3

\getValue\rdPar{Third Parameter}{mydata}
\rdPar                         % 7

\edef\rdPar{\CSVItem{First Parameter}{mydata}}%
\rdPar                         % 5

\edef\rdPar{\CSVItem{First Parameter}[4]{mydata}}%
\ifx\rdPar\empty
  \textlangle empty\textrangle
\else
  \rdPar
\fi

\end{document}

Bildbeschreibung hier eingeben

Zweite Methode

Dies basiert auf dem vorherigen Code, aber:

  • Das Parsen der CSV-Zeilen erfolgt jetzt mit \seq_set_split:Nnnstatt mit clistFunktionen, um leere Zellen nicht zu ignorieren;

  • es ist speichereffizienter (nur eine l3propwird zum Speichern aller ausgewählten Spalten verwendet);

  • Die Spaltenadressierung ist unterschiedlich: Beim Abrufen von Werten mit \getValueoder \CSVItemist Spalte 1 die erste ausgewählte Spalte, Spalte 2 die zweite ausgewählte Spalte usw. Dementsprechend ist die Standard-Spaltennummer beim Abrufen von Werten mit diesen Funktionen 1 (statt 2).

  • \getValueverfügt jetzt über eine Star-Version, die eine globale Zuweisung durchführt.

Da Sie eine automatische Erkennung der Spaltenanzahl wünschen, musste ich die Syntax wie \ReadCSVfolgt ändern:

\ReadCSV[*] [key column] {label} [value columns] {file}

Schlüsselspalteist standardmäßig 1 wie oben. Wenn jedochWertespaltenist leer, die erste Zeile vonDateiwird gelesen, um die Zahl zu bestimmenNvon Spalten, und Wertspalten sind definiert als alle Spalten von 2 bisN(beide inklusive).

Beim Lesen der Datei werden Leerzeichen auf beiden Seiten der Spaltentrennzeichen-Kommas ignoriert und ein Satz äußerer Klammern um jeden Zelleninhalt wird (sofern vorhanden) entfernt (dies wird durch die Zelle foo, barin der folgenden CSV-Beispieldatei veranschaulicht).

\begin{filecontents*}{test.csv}
Third Parameter  , 7 , 9          ,
First Parameter  , 5 , {foo, bar} ,
Second Parameter , 3 , 6          , 44
\end{filecontents*}

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
% Step 1: reading the file
\ior_new:N \l__diaa_csv_ior
\bool_new:N \l__diaa_csv_str_bool
\seq_new:N \l__diaa_csv_tmp_seq

% str mode (bool/star), key column, label, value columns, file
\NewDocumentCommand \ReadCSV { s O{1} m O{} m }
  {
    \IfBooleanTF {#1}
      { \bool_set_true:N \l__diaa_csv_str_bool }
      { \bool_set_false:N \l__diaa_csv_str_bool }
    \diaa_csv_read:nnnn {#3} {#2} {#4} {#5}
  }

% label, key column, value columns, file
\cs_new_protected:Npn \diaa_csv_read:nnnn #1 #2 #3 #4
  {
    \tl_if_blank:nTF {#3}       % Detect number of columns and use 2 to last
      {
        \ior_open:NnTF \l__diaa_csv_ior {#4}
          {
            \bool_if:NTF \l__diaa_csv_str_bool
              { \ior_str_get:NN }
              { \ior_get:NN }
              \l__diaa_csv_ior \l_tmpa_tl

            \ior_close:N \l__diaa_csv_ior
            \seq_set_split:NnV \l_tmpa_seq { , } \l_tmpa_tl
            \seq_clear:N \l__diaa_csv_tmp_seq
            \int_step_inline:nnn { 2 } { \seq_count:N \l_tmpa_seq }
              { \seq_put_right:Nn \l__diaa_csv_tmp_seq {##1} }
          }
          { \msg_error:nnn { diaa } { file-not-found } {#4} }
      }
      { \seq_set_split:Nnn \l__diaa_csv_tmp_seq { , } {#3} } % explicit columns

    \ior_open:NnTF \l__diaa_csv_ior {#4}
      {
        \prop_new:c { g__diaa_csv_#1_prop }
        \__diaa_csv_read:nn {#1} {#2}
        \ior_close:N \l__diaa_csv_ior
      }
      { \msg_error:nnn { diaa } { file-not-found } {#4} }
  }

\msg_new:nnn { diaa } { file-not-found }
  { File~`#1'~not~found. }

\cs_generate_variant:Nn \prop_put:Nnn { cxV }

% label, key column
\cs_new_protected:Npn \__diaa_csv_read:nn #1 #2
  {
    \bool_if:NTF \l__diaa_csv_str_bool
      { \ior_str_map_inline:Nn }
      { \ior_map_inline:Nn }
        \l__diaa_csv_ior
        {
          \seq_set_split:Nnn \l_tmpa_seq { , } {##1} % split one CSV row
          \tl_clear:N \l_tmpa_tl
          \seq_map_inline:Nn \l__diaa_csv_tmp_seq
            {
              \tl_put_right:Nx \l_tmpa_tl { { \seq_item:Nn \l_tmpa_seq {####1} } }
            }

          \prop_put:cxV { g__diaa_csv_#1_prop }
            { \seq_item:Nn \l_tmpa_seq {#2} }
            \l_tmpa_tl
        }
  }

% Step 2: getting the values
% star → global assignment, macro or tl var, value column, key, label
\NewDocumentCommand \getValue { s m O{1} m m }
  {
    \IfBooleanTF {#1} { \tl_gset:Nx } { \tl_set:Nx }
      #2 { \diaa_csv_item:nnn {#4} {#3} {#5} }
  }

% key, value column, label
\NewExpandableDocumentCommand \CSVItem { m O{1} m }
  { \diaa_csv_item:nnn {#1} {#2} {#3} }

\cs_generate_variant:Nn \tl_item:nn { f }

% key, value column, label
\cs_new:Npn \diaa_csv_item:nnn #1 #2 #3
  {
    \tl_item:fn { \prop_item:cn { g__diaa_csv_#3_prop } {#1} } {#2}
  }
\ExplSyntaxOff

\begin{document}

% Use default column for the key (1). The second empty optional argument (list
% of value columns) means we want to autodetect the value columns; then, the
% first column is for keys and all other columns are used as value columns.
\ReadCSV{mydata}{test.csv}

\getValue\rdPar{Second Parameter}{mydata}
\rdPar                         % 3

\getValue\rdPar[2]{Second Parameter}{mydata}
\rdPar                         % 6

\getValue\rdPar[3]{Second Parameter}{mydata}
\rdPar                         % 44

\getValue\rdPar{Third Parameter}{mydata}
\rdPar                         % 7

\edef\rdPar{\CSVItem{First Parameter}{mydata}}%
\rdPar                         % 5

\edef\rdPar{\CSVItem{First Parameter}[2]{mydata}}%
\rdPar                         % foo, bar

\edef\rdPar{\CSVItem{First Parameter}[3]{mydata}}%
\ifx\rdPar\empty
  \textlangle empty\textrangle
\else
  \rdPar
\fi

\end{document}

Bildbeschreibung hier eingeben

Antwort2

Mit dem readarrayPaket...

\begin{filecontents*}{test.csv}
Third Parameter  , 7 , 9  , 
First Parameter  , 5 , 10 ,
Second Parameter , 3 , 6  , 44
\end{filecontents*}

\documentclass{article}
\usepackage{readarray,pgffor}
\newcommand\getValue[3][2]{%
  \def\tmpA{#2}%
  \foreach\z in{1,...,\nrows}{%
    \arraytomacro#3[\z,1]\tmpB
    \ifx\tmpA\tmpB #3[\z,#1]\fi
  }%
}

\begin{document}
\readarraysepchar{,}
\readdef{test.csv}\mydata
\readarray\mydata\myarray[-,\ncols]
\nrows{} rows in data

Cell(2,2): \myarray[2,2]

Cell(3,4): \myarray[3,4]

\getValue{Third Parameter }{\myarray}
and
\getValue[4]{Second Parameter }{\myarray}
\end{document}

Bildbeschreibung hier eingeben

Beachten Sie, dass die führenden/nachgestellten Leerzeichen in den Eingabedaten standardmäßig beibehalten werden. Die Verwendung von \readarray*anstelle von \readarrayentfernt jedoch führende/nachgestellte Leerzeichen (in diesem Fall müssen diese Leerzeichen auch aus den Suchfeldspezifikationen entfernt werden).

\begin{filecontents*}{test.csv}
Third Parameter  , 7 , 9  , 
First Parameter  , 5 , 10 ,
Second Parameter , 3 , 6  , 44
\end{filecontents*}

\documentclass{article}
\usepackage{readarray,pgffor}
\newcommand\getValue[3][2]{%
  \def\tmpA{#2}%
  \foreach\z in{1,...,\nrows}{%
    \arraytomacro#3[\z,1]\tmpB
    \ifx\tmpA\tmpB #3[\z,#1]\fi
  }%
}

\begin{document}
\readarraysepchar{,}
\readdef{test.csv}\mydata
\readarray*\mydata\myarray[-,\ncols]
\nrows{} rows in data

Cell(2,2): \myarray[2,2]

Cell(3,4): \myarray[3,4]

\getValue{Third Parameter}{\myarray}
and
\getValue[4]{Second Parameter}{\myarray}
\end{document}

verwandte Informationen