[cstex] Trik k vyreseni rozparsovani retezce?

Zdenek Wagner zdenek.wagner at gmail.com
Mon Aug 20 11:15:13 CEST 2007


2007/8/20, Jaroslav Hajtmar <hajtmar at gyza.cz>:
> Dobry den.
> S ohledem na supertrik, ktery mel v zasobe pan Wagner, bych se pokusil
> pozadat konferenci jeste o jednu vec, se kterou se casto potykam, nebot
> vyuzivam plainTeX a ConTeXt velmi casto ke zpracovavani a sazbe
> databazovych dat (textove databaze z Excelu ve formatu *.CSV).
> Zajima mne, zda existuje nejaky zpusob ktery by umoznil zpracovat a
> vyhodnotit  "nevhodne zadane" parametry makra, aniz by doslo k chybove
> hlasce.
> Primarne mi jde vlastne o jakesi rozparsovani retezce, ktery neni k
> rozparsovani vhodny.
>
> Ukazal bych to na prikladu :
>
> \def\parsuj#1 #2{1. - #1, 2. - #2}
>
> \def\testA{123 456}
> \def\testB{123456}
>
> \expandafter\parsuj\testA % je OK, nebot retezec ma spravny format
>
> \expandafter\parsuj\testB % Tohle da samozrejme chybu, nebot v retezci
> neni mezera oddelujici oba parametry
>
Z pohledu TeXu toto neni pravda, mezera tam je. Po provedeni
\expandafter zbyde na vstupu:
\parsuj123456<konec radku>

Za cislici 6 byl konec radku, ktery byl pri cteni input procesorem
promenen na mezeru. Makro \parsuj si tedy vezme jako prvni parametr
123456. Nasledujici radek byl nejspis prazdny, takze jej input
procesor promenil na \par. A prave tohle vadi. Makro \parsuj neni
\long, takze v parametru nesmi byt \par. To je vyznam chyby "Runaway
argument". Syntakticky nesouhlas je neco jineho. Predpokladejte, ze
parametry maji byt oddeleny dvojteckami a z nejakeho duvodu ocekavate
dvojtecku na zacatku i na konci, tj:

\def\parsuj:#1:#2:{...}

Pouziti \parsuj:123:456: projde, ale pokud vynechate prvni dvojtecku,
tj. napisete \parsuj 123:456:, pak se TeX zastavi na cislici 1 a
oznami:

Use of \parsuj does not match its definition

> Chybova hlaska je samozrejme jasna :
>
> Runaway argument?
> 123456
> ! Paragraph ended before \parsuj was complete.
> <to be read again>
>                    \par
> l.14
>
> ?
>
> Rad bych vedel, zda existuje nejaky jednoduchy trik, ktery by umoznil
> obdrzet
> jako vysledek to, ze v pripade, ze neni predavany parametr ve "vhodnem
> formatu",
> vyhodnoti to makro tak, ze vyda jako prvni parametr cely retezec a druhy
> bude prazdny retezec (nebo retezec nejak predem specifikovany napr.
> \null atp.).
>
Je to porad stejny trik. Dulezite je, abyste mel na konci "vzoru"
jednoznacny token, ktery urcite nebude v retezci pouzit, treba \null.
Pokud chcete mit dva parametry oddelene mezerou, nadefinujete si:

\def\parsuj#1 #2\null{...}

Za predpokladu. ze text k parsovani je v \testX, pouzijeme podobne
volani, jake jste mel vyse. Potiz je v tom, ze pri chybe nema TeX
zadny "fallback", ktery by sel ovladat na makro-urovni. Musime tedy
zajistit, aby vstup byl syntakticky spravny, tedy pred \null pridame
mezeru a prazdny parametr:

\expandafter\expandafter\expandafter\parsuj\expandafter\testX\space\null

Kdyz nyni makro \parsuj zjisti, ze #2 je prazdny, pak je jasne, ze v
\testX nebyla mezera a retezec tedy neni formalne spravny. Pokud #2
neni prazdny, pak ma na konci nadbytecnou mezeru, kterou bude nutno
dodatacne odstranit (opet pouzijeme koncovy token, aby se retezec
omylem neprekousl na mezere uprostred):

\def\OdstranKoncovouMezeru#1 \null{#1}

V makru \ifnotfound v odpovedi na minulou otazku jsem pouzil definici
pomocneho makra a test \ifx. Pokud vite, ze v parametrech nebude
matematika, muzete pouzit jiny trik:

\ifcat$#2$ Prazdny\else Neprazdny\fi

Primitiv \ifcat provani expanzi tak, aby mohl porovnat kategorie
(\catcode) dvou nasledujicich znaku. Pokud je #2 prazdny, pak vidi
\ifcat$$, coz je \iftrue, takze se provedou prikazy pred \else. Pokud
#2 neco obsahuje, pak z nej \ifcat odebere prvni znak (coz podle
predpokladu neni dolar ani jiny znak se stejnou kategorii). Podminka
se tedy vyhodnoti jako \iffalse. Za ni sice zbyde neukoncena
matematika, ale to nevadi, protoze vsechno az do \else vcetne bude
ignorovano.

Pokud byste jako argument makra parsuj chtel vlozit strink, ktery
obsahuje mezeru, pak byste takoy argument musel uzavrit do zavorek.

\parsuj 123 456 789\null vezme jako prvni parametr 123 a jako druhy
parametr 456 789 (s mezerou uprostred), zatimco \parsuj {123 456}
789\null vezme jako prvni parametr {123 456}.

Jeste bych si dovolil jednu poznamku. Je celkem bezne, ze v procesu
zpracovani dat se postupne pouzije nekolik nastroju. Nebranil bych se
tedy tomu, aby text byl nejprve zpracovan nejakym skriptovacim jazykem
(perl, python, ...) a nasledne podstrcen TeXu. Ve svete XML se
takovemu postupu zpracovani rika pipeline a podobne postupne
zpracovani resi make, ant a rada jinych nastroju. Zalezi vsak na
okolnostech. Pokud budu takovou vec delat jen pro sebe, pak pouziju
vse, co mam ve svem pocitaci, a pujde o to, aby se mi to snadno
programovalo. A pokud bych zpracovaval opakovane velka mnozstvi dat,
hledal bych tez efektivni reseni (tyto TeXove triky jsou nekdy
efektivnejsi nez regularni vyrazy). Pokud bych vytvarel program pro
nekoho jineho, pak by zalezelo na tom, co ma ten nekdo jiny v
pocitaci. Pokud se dokument v posledni fazi zpracovava TeXem, pak je
jiste, ze uzivatel musi TeX mit, ale bezny uzivatel Windows nemusi mit
perl ani python. V takovem pripade je ciste TeXove reseni vyhodnejsi,
i kdyby nebylo nejefektivnejsi.

>
> Takze vysledek vyhodnoceni \testA by vypada takto :
> 1. - 123, 2. - 456
>
> A vysledek vyhodnoceni  \testB by mel vypadat takto :
>
> 1. - 123456, 2. -
>
> \end
>
> Je pravda, ze ted, kdyz mam v ruce moznost testovat vyskyt podretezce v
> retezci pomoci triku, ktery vcera poslal do konfery pan Wagner (viz. makro :
>
> \hledej{jehla}{Je snad jehla v kupce sena?}), muzu samozrejme predem predavany parametr "zkontrolovat" a predat jej pak uz ve spravnem formatu. Taktez bych mohl predem zpracovat a upravit data pomoci PERLu, a pak naservirovat makrum ke zpracovani uz jen "hezky naformatovana" data.
>
> Zajimalo by mne ale, zda by se dalo nejakym vtipnym trikem tuto vec vyresit bud primo TeXem nebo pomoci plainTeXu.
>
>
> Pro ty kdo by v budoucnu narazili na tento dotaz v archivu a trik s
> kupkou sena neznali jej jeste jednou prikladam na zaver, nebot posilam
> tento mail do konfery s jinym subjectem, takze at je nejaka navaznost)
>
> Vsechny konferniky srdecne zdravim
> Jarda Hajtmar
>
>
> >> \def\nic{}
> >> \def\hledej#1#2{%
> >>   \def\ifnotfound##1#1##2\konec{\def\test{##2}\ifx\test\nic}%
> >>   \ifnotfound#2#1\konec Nenalezeno!\else Nalezeno!\fi}
> >>
> >> \hledej{jehla}{Je snad jehla v kupce sena?}
> >> \hledej{jehla}{Najdi jehlu v kupce sena!}
> >>
> >
> > To je prekrasny trik - bez cyklu, bez \expandafter a cele v cistem TeXu (ani
> > plain ani LaTeX). Proste skvele.
> >
> > Akorat ted uz nemam motivaci vymyslet vlastni reseni. Ja to tusil, ze nemam
> > otevirat slozku cstex konference do doby nez budu mit cas se nad tim zamyslet -
> > ale nedalo mi to a ted to mam :-)
> >
> > Milan Vancura
> > _______________________________________________
> > csTeX mailing list
> > csTeX at cs.felk.cvut.cz
> > http://lists.felk.cvut.cz/mailman/listinfo/cstex
> >
> >
> >
> >
>
> _______________________________________________
> csTeX mailing list
> csTeX at cs.felk.cvut.cz
> http://lists.felk.cvut.cz/mailman/listinfo/cstex
>


-- 
Zdeněk Wagner
http://hroch486.icpf.cas.cz/wagner/
http://icebearsoft.euweb.cz


More information about the csTeX mailing list