From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- macros/generic/olsak-misc/scancsv.tex | 242 ++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 macros/generic/olsak-misc/scancsv.tex (limited to 'macros/generic/olsak-misc/scancsv.tex') diff --git a/macros/generic/olsak-misc/scancsv.tex b/macros/generic/olsak-misc/scancsv.tex new file mode 100644 index 0000000000..aa1ce26825 --- /dev/null +++ b/macros/generic/olsak-misc/scancsv.tex @@ -0,0 +1,242 @@ +% scancsv. tex +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% 26. 2. 2005 Petr Olsak + +% This is a macro for processing the CSV format in plain TeX. +% +% The input file is assumed in the form: +% +% "header1";"header2";"header3"; ... "header-n" +% "text 1,1";"text 1,2";"text 1,3"; ... "text 1,n" +% "text 2,1";"text 2,2";"text 2,3"; ... "text 2,n" +% "text 3,1";"text 3,2";"text 3,3"; ... "text 3,n" +% ... +% +% You can process such a file by +% +% \input scancsv.tex +% \def\lineaction{...} +% \scanbase soubor +% +% The separator " can be omited in a arbitrary header or item text. +% I.e. the following format is scanned without problems: +% +% "firstname";"lastname";number;RC +% "Ferdinand";"Mravenec";1;000111/2244 +% "Josef";"Vykutal";2;444333/2211 +% +% The macro reads the headers and then reads next lines repeatedly. +% The full expanable macro \e is ready after the line is read. +% More exactly \e[header] expands to the appropriate item body. +% The \lineaction macro is processed after each line is read. +% It is supposed that \lineaction is defined by user. +% +% Next line of the table is read after \lineaction, the \e macros have +% a new meaning (items from this next line) and the \lineaction is executed +% again. This is repeated until last line of the input table is reached. +% Moreower, the \linenum register is available, where the number of the +% last scanned line is stored. + +% Example: +% +% \input scancsv +% +% \newcount \mylines +% \def\bb #1 #2/{\hbox to#1{#2\hss}} +% +% \def\printaction{\global\advance\mylines by1 %% \scanabase works +% \hbox{% %% in the TeX group +% \bb 2em \the\numline./ +% \bb 26em \e[subject]/ +% \bb 10em \e[lastname] \e[firstname]/ +% \bb 3em \hfill\e[pay2002]/ +% \bb 3em \hfill\e[pay2001]/} +% } +% \def\lineaction{\if K\e[member_type]% Institutional members +% \printaction +% \else \if G\e[member_type]% High school +% \printaction +% \fi\fi % I am printing Institutional mambers and high schools only +% } +% \scanbase database1 +% \scanbase database2 +% {\it Number of printed lines: \the\mylines}. +% \end +% +% If the \lineaction macro isn't defined by user then scanbase used +% its own (default) macro which prints all items from one line +% into the one paragraph in comprimend form (you can try this). +% +% The \scanbase macro opens the TeX group then runs \beginhook +% then reads headers, then reads the lines ans processes \linecation +% repeatedly, then runs \endhook and finally closes the group. +% Default values for \beginhook and \endhook is \relax but user +% can define something else. +% +% The user can redefine the \separator and \obklopeni (surrounding char) +% after \input scanbase if there are used another characters than semicolon +% and " in the input file. + +\def\separator{;} % separator mezi polozkami +\def\obklopeni{"} % nepovinne "obklopeni" polozky + +\newcount\colnum \newcount\numline + +\catcode`\^^X=13 \def^^X{} + +\def\scanheader{\futurelet \nextchar \doheader} + +\def\doheader {\expandafter\ifx \obklopeni\nextchar \expandafter \maskheader + \else \expandafter \nomaskheader \fi} + +\def\runheader{\advance\colnum by1 + \expandafter \ifx \csname e:\itemdata\endcsname \relax + \expandafter \edef \csname c:\the\colnum\endcsname{\itemdata}% + \expandafter \def \csname e:\itemdata\endcsname {}% + \else + \expandafter \edef \csname c:\the\colnum\endcsname{\itemdata:\the\colnum}% + \fi + \futurelet \nextchar \testnextchar +} +\def\testnextchar{\ifx\nextchar^^X\let\next=\ignorethirdline + \else \let\next=\scanheader + \fi \next +} + +\def\ignorethirdline ^^X{\edef\maxcolumn{\the\colnum}\runfirstitem} + +\def\runfirstitem #1^^X{\def\tmp{#1}% + \ifx\tmp\empty \expandafter\endinput \fi + \ifx\tmp\stopmark + \else \colnum=0 + \edef\tmp{\noexpand\scanitem #1\separator\noexpand^^X}\expandafter\tmp + \fi} +\def\scanitem {\futurelet \nextchar \doitem} + +\def\doitem {\expandafter \ifx \obklopeni\nextchar \expandafter \maskitem + \else \expandafter \nomaskitem \fi} + +\def\runitem {\advance\colnum by1 + \expandafter\edef\csname e:\csname c:\the\colnum\endcsname\endcsname{\itemdata}% + \futurelet \nextchar \testnextitem +} +\def\testnextitem{\ifx\nextchar^^X\let\next=\runline + \else \let\next=\scanitem + \fi \next +} +\def\runline ^^X{\advance\numline by1 + \lineaction + \futurelet \nextchar \runfirstitem +} +\def\e [#1]{\expandafter\ifx \csname e:#1\endcsname \relax + \message{Warning: the #1 column is not defined in header.}% + \else \csname e:#1\endcsname \fi +} + +\def\printall{\colnum = 0 + \noindent \hangindent=\parindent \raggedright + \loop + \advance\colnum by1 + {\seventt \ignorespaces \csname c:\the\colnum\endcsname:}\penalty0 + \csname e:\csname c:\the\colnum\endcsname\endcsname + \ifnum\colnum < \maxcolumn , \repeat + .\par +} +\let\lineaction=\printall + +\def\scanbase #1 {\begingroup \endlinechar=`\^^X + \edef\maskauvo{\obklopeni####1\obklopeni\separator} + \edef\maskaneuvo{####1\separator} + \expandafter\def \expandafter\maskheader \maskauvo {\def\itemdata{##1}\runheader} + \expandafter\def \expandafter\nomaskheader \maskaneuvo {\def\itemdata{##1}\runheader} + \expandafter\def \expandafter\maskitem \maskauvo {\def\itemdata{##1}\runitem} + \expandafter\def \expandafter\nomaskitem \maskaneuvo {\def\itemdata{##1}\runitem} + \edef\scanfirstline ##1^^X{\noexpand\scanheader##1\separator\noexpand^^X} + \def\do##1{\catcode`##1=12 }\dospecials + \catcode`\ =10 \beginhook + \expandafter \scanfirstline \input #1 \relax^^X\endhook \endgroup} +\def\stopmark{\relax} + +\let\beginhook=\relax \let\endhook=\relax + +\endinput + +% Makro na zpracovani databasovych vystupu ve formatu CSV pro plain. +% +% Srovnejte tez makro scanbase.tex +% +% Nacitane soubory se predpokladaji ve tvaru: +% +% "zahlavi1";"zahlavi2";"zahlavi3"; ... "zahlavi-n" +% "text 1,1";"text 1,2";"text 1,3"; ... "text 1,n" +% "text 2,1";"text 2,2";"text 2,3"; ... "text 2,n" +% "text 3,1";"text 3,2";"text 3,3"; ... "text 3,n" +% ... +% +% Na takovy soubor je mozno po +% +% \input scancsv.tex +% +% aplikovat makro \scanbase takto: +% +% \scanbase soubor +% +% Obklopujici znak " muze u libovolneho zahlavi nebo polozky +% chybet. Tj. je korektni treba i takovy zapis dat: +% +% "jmeno";"prijmeni";cislo;RC +% "Ferdinand";"Mravenec";1;000111/2244 +% "Josef";"Vykutal";2;444333/2211 +% +% Makro nacte zahlavi a zacne cist jednotlive radky. Po precteni +% kazdeho radku je obsah polozky pripraven v expanznim makru +% \e. Presneji \e[zahlavi] expanduje na text odpovidajici polozky. +% V teto situaci \scanbase spusti makro \lineaction, ktere si muze +% uzivatel definovat jak chce. +% +% Po ukonceni makra \lineaction cte scanbase dalsi radek tabulky, naplni +% znovu expanzni makra \e texty polozek z tohoto radku a spusti znovu +% \lineaction. To se opakuje tak dlouho, dokud neni ukonceno cteni +% tabulky. Navic je makru \lineaction k dispozici registr \numline +% obsahujici cislo prave precteneho radku. +% +% Priklad pouziti: +% +% \input scancsv +% +% \newcount \mylines +% \def\bb #1 #2/{\hbox to#1{#2\hss}} +% +% \def\printaction{\global\advance\mylines by1 %% \scanabase pracuje +% \hbox{% %% uvnitr skupiny! +% \bb 2em \the\numline./ +% \bb 26em \e[nazev]/ +% \bb 10em \e[prijmeni] \e[jmeno]/ +% \bb 3em \hfill\e[kc2002]/ +% \bb 3em \hfill\e[kc2001]/} +% } +% \def\lineaction{\if K\e[typ_clenstvi]% Kolektivni clenove +% \printaction +% \else \if G\e[typ_clenstvi]% Gymnazia +% \printaction +% \fi\fi % tisknu jen kolektivni cleny a gymnazia +% } +% \scanbase database1 +% \scanbase database2 +% {\it Number of printed lines: \the\mylines}. +% \end +% +% Pokud neni uzivatelem definovano makro \lineaction, pouzije +% scanbase sve vlastni (defaultni) makro, ktere vytiskne vsechny polozky +% jednoho radku do odstavce ve velmi zhustenem tvaru (vyzkousejte si). +% +% Kazde \scanbase vstupuje do skupiny, pak spusti \beginhook, +% pak cte hlavicku a jednotlive radky, jak bylo receno vyse, +% pak spusti \endhook a nakonec vyleze ze skupiny. +% Sekvence \beginhook a \endhook muze predefinovat uzivatel, defaltne maji +% hodnotu \relax +% +% Uzivatel muze po nacteni \input scanbase predefinovat makra \separator +% a \obklopeni (viz nize), pokud jsou v datech polozky a zahlavi +% oddeleny jinymi znaky nez strednik a symbol palce. + -- cgit v1.2.3