PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Jahreszahl von Datum ermittlen: Verschachtelung von Befehlen



Konstantin
09-02-2008, 14:19
Hallo Communtiy!

Ich versuche vergebens mir ein paar Commands zu erstellen, um ein Datum zu parsen (brauche Tag um Monat für die Koordination, um den Termin an der richtigen Stelle zu positionieren).

Nun hier mein Versuch:

\newcounter{numdashes}

% Eventuell Jaheszahl hinzufügen
\newcommand{\datewithyear}[1]{%
\SubStringsToCounter{numdashes}{-}{#1}
\ifthenelse{\thenumdashes = 1}
{
% Datum ohne Jahreszahl (ein Dash)
2008-#1
}
{
% Datum mit Jahreszahl
#1
}
}

\newcommand{\getyear}[1]{
\BeforeSubString{-}{\datewithyear{#1}}
}

\newcommand{\getmonth}[1]{
\BeforeSubString{-}{\AfterSubString{-}{\datewithyear{#1}}}
}

\newcommand{\getday}[1]{
\AfterSubString{-}{\AfterSubString{-}{\datewithyear{#1}}}
}



Der Aufruf

\datewithyear{02-09}
gibt wie erwartet 2008-02-09.

Wenn ich aber nun

\getyear{02-09}
aufrufe, kommt beim Übersetzen folgende Fehlermeldung:


Undefined control sequence.
\su@ExpandTwoArgs ...1}\protected@edef \su@String
{#2}\expandafter \expandaf...
l.217 \getyear{02-09}



Nun meine Frage, woran liegt's?

Zur Information: Folgende Packages werden dafür benötigt: substr, ifthen

Hoffe, jemand kann mir da weiterhelfen.

Konstantin

rais
09-02-2008, 20:52
Moin moin,
vergleiche mal:


\documentclass[ngerman]{article}
\usepackage[utf8]{inputenc}
\usepackage{babel,ifthen,substr}
\newcounter{numdashes}
\newif\ifdebugme
\debugmetrue
\newcommand\myyear{????}
\newcommand\mymonth{??}
\newcommand\myday{??}
\newcommand\mytemp{}
\newcommand{\datewithyear}[1]{%
\SubStringsToCounter{numdashes}{-}{#1}
\ifthenelse{\thenumdashes < 1}{%gar kein - drin...
\typeout{Invalid date (#1)---or \string\datewithyear\space needs some modification;-)}
\ifdebugme ist \glqq#1\grqq\ ein Datum?\fi
}{%numdashes >= 1 ...
\ifthenelse{\thenumdashes > 2}{%
\typeout{Invalid date (#1)---or \string\datewithyear\space needs some modification;-)}
\ifdebugme ist \glqq#1\grqq\ ein Datum?\fi
}{% 1 <= numdashes <=2 ...
\ifthenelse{\thenumdashes = 1}{%nur Monat-Tag...
\renewcommand\myyear{\the\year}
\myyear-#1% aktuelles Jahr davor, sofern die eingebaute Sanduhr einigermaßen richtig die Körner fallen lässt;-)
\renewcommand\mytemp{#1}%mm-dd
}{% Datum war schon komplett...
#1%
\renewcommand\myyear{\BeforeSubString{-}{#1}}
\renewcommand\mytemp{\BehindSubString{\myyear-}{#1}}%mm-dd
}%Datum komplett
\renewcommand\myday{\BehindSubString{-}{\mytemp}}
\renewcommand\mymonth{\BeforeSubString{-}{\mytemp}}
}% 1 <= numdashes <= 2
}% numdashes >=1
}%\datewithyear{[yyyy-]mm-dd}
\begin{document}
\datewithyear{02-09}

Jahr: \myyear\ Monat: \mymonth\ Tag: \myday

\bigskip falsch bzw. nicht unterstützt:

\datewithyear{bla}
\datewithyear{0815}
\datewithyear{2008-08-15-foo}

\bigskip noch mehr davon:

\datewithyear{08-15-2009}
\datewithyear{bla-blubb}
\end{document}

MfG

Konstantin
10-02-2008, 11:05
Ja, sieht ja gut aus.

Jetzt hab ich aber dazu noch 3 Probleme bzw. Fragen:

1. Wenn aus Zeile 36

\datewithyear{02-09}
folgende Zeile mache:

\datewithyear{2007-02-09}
haut der mir das mit folgender Fehlermeldung um die Ohren:

! Illegal parameter number in definition of \su@String.
<to be read again>
1
l.38 Jahr: \myyear\ Monat: \mymonth
\ Tag: \myday

Scheint also nicht zu klappen, wenn man das Jahr mit angibt. :-( Woran liegt es?

2. Des weiteren würde mich interessieren, warum meine Lösung nicht geklappt hat. Es scheint ja damit Probleme zu geben, wenn man in den Befehlen andere Befehle aufruft, oder? Schon alleine, wenn man den Aufruf von BehindSubString und BeforeSubString schachtelt, meckert LaTeX schon. Aber warum? Im Rahmen der Wiederverwendbarkeit würde ich mir schon wünschen, wenn ich Teile auslagern könnte. Hat das was man dem Unterschied zwischen \long\def und \def (bzw. \newcommand vs. \newcommand*) zu tun? Hatte da mal was drüber gelesen aber nicht so richtig verstanden.

3. Ich hab schon öfter gelesen, dass am Ende einer Zeile ein % steht (aber in meinen Augen recht unregelmäßig). Ich weiß aber nicht, wie ich danach suchen soll. Darum: Kann mir wer erklären, wann man das so macht und warum? (ein Link, wo das erklärt wird, wäre auch ok) Kommentiert man damit dem Zeilenumbruch aus?

Gruß
Konstantin

rais
11-02-2008, 09:32
Moin moin,

Ja, sieht ja gut aus.

Jetzt hab ich aber dazu noch 3 Probleme bzw. Fragen:

1. Wenn aus Zeile 36

\datewithyear{02-09}
folgende Zeile mache:

\datewithyear{2007-02-09}
haut der mir das mit folgender Fehlermeldung um die Ohren:

! Illegal parameter number in definition of \su@String.
<to be read again>
1
l.38 Jahr: \myyear\ Monat: \mymonth
\ Tag: \myday

Scheint also nicht zu klappen, wenn man das Jahr mit angibt. :-( Woran liegt es?

huch :eek:
Dabei hat es mit der falschen Reihenfolge (08-15-2009) doch noch hingehauen...


2. Des weiteren würde mich interessieren, warum meine Lösung nicht geklappt hat. Es scheint ja damit Probleme zu geben, wenn man in den Befehlen andere Befehle aufruft, oder? Schon alleine, wenn man den Aufruf von BehindSubString und BeforeSubString schachtelt, meckert LaTeX schon. Aber warum?

Da kann ich meinen Finger noch nicht drauflegen, aber ein Umweg über einfache Befehle mit/ohne Parameter funktioniert ordnungsgemäß


\newcommand\dummy{02-09}
\newcommand\dummytwo[1]{#1}
(..)
\BeforeSubString{-}{\dummy}
\BeforeSubString{-}{\dummytwo{\dummy}}

vermutlich hat es damit zu tun, was wann wie tatsächlich expandiert wird -- damit kann ich Dir (noch) nicht helfen.


3. Ich hab schon öfter gelesen, dass am Ende einer Zeile ein % steht (aber in meinen Augen recht unregelmäßig). Ich weiß aber nicht, wie ich danach suchen soll. Darum: Kann mir wer erklären, wann man das so macht und warum? (ein Link, wo das erklärt wird, wäre auch ok) Kommentiert man damit dem Zeilenumbruch aus?

Jupp, bei einem Zeilenumbruch nach aktivem Text wird daraus sonst ein Leerzeichen in der Ausgabe (vgl. unten die beiden \datewithyear mit den beiden Jahr/Monat/Tag-Angaben danach).
Was die Unregelmäßigkeit angeht: Nicht jeder Befehl erfordert ein % am Ende, um ungewollte Abstände zu unterdrücken ... und vielleicht ist mir ja auch die eine oder andere Zeile noch durch die Lappen gagangen;-)

Hier mal ein möglicher Workaround:


\documentclass[ngerman]{article}
\usepackage[utf8]{inputenc}
\usepackage{babel,ifthen,substr}
\newcounter{numdashes}
\newif\ifdebugme
\debugmetrue
\newcommand\myyear{????}
\newcommand\mymonth{??}
\newcommand\myday{??}
\newcommand\mytemp{}
\def\getfirstoftwo(#1-#2){#1}
\def\getsndoftwo(#1-#2){#2}
\def\getfirstofthree(#1-#2-#3){#1}
\def\getsndofthree(#1-#2-#3){#2}
\def\getthirdofthree(#1-#2-#3){#3}
\newcommand{\datewithyear}[1]{%
\SubStringsToCounter{numdashes}{-}{#1}
\ifthenelse{\thenumdashes < 1}{%gar kein - drin...
\typeout{Invalid date (#1)---or \string\datewithyear\space needs some modification;-)}
\ifdebugme ist \glqq#1\grqq\ ein Datum?\fi
}{%numdashes >= 1 ...
\ifthenelse{\thenumdashes > 2}{%
\typeout{Invalid date (#1)---or \string\datewithyear\space needs some modification;-)}
\ifdebugme ist \glqq#1\grqq\ ein Datum?\fi
}{% 1 <= numdashes <=2 ...
\ifthenelse{\thenumdashes = 1}{%nur Monat-Tag...
\renewcommand\myyear{\the\year}
\myyear-#1% aktuelles Jahr davor, sofern die eingebaute Sanduhr einigermaßen richtig die Körner fallen lässt;-)
\renewcommand\mymonth{\getfirstoftwo(#1)}% Monat
\renewcommand\myday{\getsndoftwo(#1)}% Tag
}{% Datum war schon komplett...
#1%
\renewcommand\myyear{\BeforeSubString{-}{#1}}%oder \getfirstofthree
\renewcommand\mymonth{\getsndofthree(#1)}% Monat
\renewcommand\myday{\getthirdofthree(#1)}% Tag
}%Datum komplett
}% 1 <= numdashes <= 2
}% numdashes >=1
}%\datewithyear{[yyyy-]mm-dd}
\begin{document}
\datewithyear{1997-01-08}
(Jahr: \myyear\ Monat: \mymonth\ Tag: \myday)

\datewithyear{02-09}%
(Jahr: \myyear\ Monat: \mymonth\ Tag: \myday)

\bigskip falsch bzw. nicht unterstützt:

\datewithyear{bla}
\datewithyear{0815}
\datewithyear{2008-08-15-foo}

\bigskip noch mehr davon:

\datewithyear{08-15-2009}
\datewithyear{bla-blubb}
\end{document}

MfG

Konstantin
20-02-2008, 10:35
Hm ... für die einfache Übergabe eines Datums klappt das ja ganz gut. Wenn ich jetzt aber folgendes mache:


\applyCSVfile{file.csv}
{
\datewithyear{\field{1}}
\myyear
\mymonth
\myday
}

gibt er mir folgende Fehlermeldung:


Runaway argument?
\field {1})
! Paragraph ended before \getsndofthree was complete.


Sehe ich das richtig, dass er bei \def\getsndofthree(#1-#2-#3){#2} versucht den String \field{1} zu parsen, statt den \field-Befehl umzusetzten und das Ergebnis zu parsen? Wie löse ich nun das Problem?


BTW: Irgendwie blicke ich da noch nicht ganz durch, wie (La)TeX da arbeitet. Gibt es gute Dokumentationen zu, die solches Verhalen erklären?

Danke schon mal im Voraus.

rais
20-02-2008, 23:22
Moin moin,

Hm ... für die einfache Übergabe eines Datums klappt das ja ganz gut. Wenn ich jetzt aber folgendes mache:


\applyCSVfile{file.csv}
{
\datewithyear{\field{1}}
\myyear
\mymonth
\myday
}

gibt er mir folgende Fehlermeldung:


Runaway argument?
\field {1})
! Paragraph ended before \getsndofthree was complete.


was wird das: `rate mal, welche(s) Paket(e) ich lade?' oder gar wie Du welchen Befehl definierst? Mach doch bitte ein nachvollziehbares Beispiel.


MfG

Konstantin
21-02-2008, 15:44
Moin moin,

was wird das: `rate mal, welche(s) Paket(e) ich lade?' oder gar wie Du welchen Befehl definierst? Mach doch bitte ein nachvollziehbares Beispiel.


MfG

'Tschuldige. Ich dachte, das ist nicht relevant und habe es deswegen weggelassen:

Ich nutze hier das csvtools (http://www.ctan.org/tex-archive/help/Catalogue/entries/csvtools.html)-Package. \applyCSVfile{file.csv} durchläuft da die Zeilen der csv-Datei und \field{1} gibt den Wert der ersten Spalte aus, welche ein Datum (entweder yyyy-mm-dd oder mm-dd) enthält.

Ich bin davon ausgegangen, das bei der Übergabe von \meintollesdatum (\newcommand{\meintollesdatum}{2008-02-21}) der Fehler ebenso auftritt. Hab es aber nicht explizit getestet. (Werde ich mal machen, wenn ich zu Hause bin.) Meinem Verständnis nach sucht LaTeX in der Zeichenkette \field {1}) den ersten Bindestrich nach der Definition von \getsndofthree, welchen er aber nicht findet.

Er müsste halt den Wert von \field {1} nehmen. Tut er aber anscheind nicht. Aber warum?

rais
24-02-2008, 13:53
Moin moin,

Meinem Verständnis nach sucht LaTeX in der Zeichenkette \field {1}) den ersten Bindestrich nach der Definition von \getsndofthree, welchen er aber nicht findet.

Nö, -- oder besser: AARGH! -- so wird dem \getsndofthree nur der erste Parameter übergeben.


Er müsste halt den Wert von \field {1} nehmen. Tut er aber anscheind nicht. Aber warum?
Weil (La)TeX nicht alles ständig expandiert ... da muß wohl ein Workaround für den Workaround her;-)


\begin{filecontents*}{test.csv}
Datum, Foo, Bar
08-15, eins, zwei
\end{filecontents*}
\documentclass[ngerman]{article}
\usepackage[utf8]{inputenc}
\usepackage{babel,ifthen,substr,csvtools}
\newcounter{numdashes}
\newif\ifdebugme
\debugmetrue
\newcommand*\myyear{????}
\newcommand*\mymonth{??}
\newcommand*\myday{??}
\newcommand*\mytemp{}
\def\getfirstofthree#1-#2-#3{#1}
\def\getsndofthree#1-#2-#3{#2}
\def\getfirstoffour#1-#2-#3-#4{#1}
\def\getsndoffour#1-#2-#3-#4{#2}
\def\getthirdoffour#1-#2-#3-#4{#3}
\newcommand{\datewithyear}[1]{%
\edef\mytemp{#1-\relax}
\SubStringsToCounter{numdashes}{-}{#1}
\ifthenelse{\thenumdashes < 1}{%gar kein - drin...
\typeout{Invalid date (#1)---or \string\datewithyear\space needs some modification;-)}
\ifdebugme ist \glqq#1\grqq\ ein Datum?\fi
}{%numdashes >= 1 ...
\ifthenelse{\thenumdashes > 2}{%
\typeout{Invalid date (#1)---or \string\datewithyear\space needs some modification;-)}
\ifdebugme ist \glqq#1\grqq\ ein Datum?\fi
}{% 1 <= numdashes <=2 ...
\ifthenelse{\thenumdashes = 1}{%nur Monat-Tag...
\renewcommand\myyear{\the\year}
\myyear-#1% aktuelles Jahr davor, sofern die eingebaute Sanduhr einigermaßen richtig die Körner fallen lässt;-)
\xdef\mymonth{\expandafter\getfirstofthree\mytemp} % Monat
\xdef\myday{\expandafter\getsndofthree\mytemp}% Tag
}{% Datum war schon komplett...
#1%
\renewcommand\myyear{\BeforeSubString{-}{#1}}%oder \getfirstoffour
\xdef\mymonth{\expandafter\getsndoffour\mytemp}% Monat
\xdef\myday{\expandafter\getthirdoffour\mytemp}% Tag
}%Datum komplett
}% 1 <= numdashes <= 2
}% numdashes >=1
}%\datewithyear{[yyyy-]mm-dd}
\newcommand\dummy{2008-02-24}
\tracingmacros=1
\begin{document}
\datewithyear{1997-01-08}
(Jahr: \myyear\ Monat: \mymonth\ Tag: \myday)

\datewithyear{02-09}%
(Jahr: \myyear\ Monat: \mymonth\ Tag: \myday)

\bigskip via Makro:

\datewithyear{\dummy}
(Jahr: \myyear\ Monat: \mymonth\ Tag: \myday)

\bigskip via CSV:

\applyCSVfile{test.csv}{%
\datewithyear{\field{1}}
(Jahr: \myyear\ Monat: \mymonth\ Tag: \myday)

bzw. mit entsprechender Spaltenüberschrift:

\datewithyear{\insertDatum}
(Jahr: \myyear\ Monat: \mymonth\ Tag: \myday)
}
\end{document}

Damit ich mit dem \expandafter klar komm' (der soll hier dafür sorgen, daß "das Argument" \mytemp _vor_ dem dazugehörigen \getxofy expandiert wird), hab' ich bei diesen \getxofy die Klammern weggelassen ... und weil ich sie weggelassen hab, wird vom letzten Parameter nur das erste Zeichen ausgewertet (es sei denn, es handelt sich hierbei um ein Token), deshalb auch der Umweg über \edef\mytemp{#1-\relax}, also ein zusätzlich angehängter Parameter, der später einfach ignoriert wird.;)

Vielleicht noch nicht ganz lupenrein, sollte aber tun.;-)

BTW: Das csvtools (http://dante.ctan.org/CTAN/help/Catalogue/entries/csvtools.html)-Paket ist inzwischen durch das datatool (http://dante.ctan.org/CTAN/help/Catalogue/entries/datatool.html)-Paket abgelöst worden.

MfG