I want find a certain line of text in a data file cities.txt:
A;London
B;Berlin
C;Paris
with the xstring
and [xifthen
][2] packages:
\documentclass[12pt, a4paper]{article}
\usepackage{xstring}
\usepackage{xifthen}
\begin{document}
\newread\dbcities
\openin\dbcities=cities.txt
We start here:
\loop\unless\ifeof\dbcities
\read\dbcities to \dbline
\ifthenelse{\isin{A}{\dbline}} % <-- doesn't work
{\StrCut{\dbline}{;}{\colA}{\colB}
\colA: \colB \\}
{}
\repeat
\closein\dbcities
\end{document}
But the string comparison doesn't work if the line of text to be compared is stored in the macro variable \dbline
, although if I print \dbline
it expands perfectly. That makes me crazy ... Any help?
Edit: Based on jfbu's answer (thanks!) I tried to put the search code into a command and pass the searchstring by Argument. Seems it works!
Here is how I use the function now. The extra whitespace is a problem (see discussion)
% <-*- coding: utf-8 -*-
% ---------------------------------------------------
\documentclass[a4paper,12pt]{article}
\usepackage{filecontents}
\begin{filecontents*}{verses.dat}
§
§1§~{Mich respektvoll verneigend vor den Sugatas, vor dem Körper der Wahrheit, den sie besitzen, sowie vor ihren Kindern und ebenso vor allen, die der Verehrung wert sind, will ich die Ausübung der Disziplin der Sugata-Kinder entsprechend den Schriften in zusammengefasster Form darlegen.}
§
§2§~{Etwas, das es zuvor noch nicht gegeben hat, habe auch ich hier nicht zu sagen; und ich besitze nicht die Kunstfertigkeit in der Komposition von Schriften: Deshalb habe ich auch keine Absicht, anderen zu nutzen; vielmehr schreibe ich dieses, um meinen eigenen Geist daran zu gewöhnen.}
§
§3§~{Aufgrund der Gewöhnung an das Heilsame mag die Kraft meines Vertrauens durch diese Kontemplationen zeitweilig anwachsen; und wenn andere, die mir in ihren Veranlagungen ähnlich sind, diese sehen, so mag es auch für sie von Bedeutung sein.}
§
\end{filecontents*}
\usepackage{fontspec}
\defaultfontfeatures{Mapping=tex-text} %
\usepackage{polyglossia} % the multilingual support package
\setdefaultlanguage[spelling=new, babelshorthands=true]{german}
% ------ Routine für Einfügung Grundtext: ---------
% !!roots-db.txt dar keine Leerzeile am Ende haben!!
\usepackage{xstring}
\usepackage{xifthen}
\newcommand*{\isinxp}[2]{\expandafter\isinxpp\expandafter{#2}{#1}}
\newcommand*{\isinxpp}[2]{\isin {#2}{#1}}
\newread\dbroot
\newcommand{\myprintverse}[1]{%
\openin\dbroot=verses.dat
\loop
\read\dbroot to \dbline
\unless\ifeof\dbroot
\ifthenelse{\isinxp{#1}{\dbline}}
{\StrCut{\dbline}{~}{\colA}{\colB}
(\StrBetween[1,2]{\colA}{§}{§})~{\colB}}
{}
\repeat
\closein\dbroot%
}
\begin{document}
Each line of data printed in a seperate paragraph:
\medskip{}
\myprintverse{§1§} \par
\myprintverse{§2§} \par
\myprintverse{§3§} \par
\bigskip{}
Two lines in one paragraph results in ugly whitespace in between, and I don't know how to get rid of it:
\medskip{}
\myprintverse{§1§} \myprintverse{§2§} \par
\myprintverse{§3§}\footnote{This is also a problem if I want to add a footnote.} \par
\end{document}
Edit: This is now the flawless version of the command that works without adding space:
\newcommand{\myprintverse}[1]{%
\openin\dbroot=verses.dat
\begingroup
\loop
\endlinechar=-1
\read\dbroot to \dbline
\unless\ifeof\dbroot
\ifthenelse{\isinxp{#1}{\dbline}}
{\StrCut{\dbline}{~}{\colA}{\colB}
(\StrBetween[1,2]{\colA}{§}{§})~{\colB}}%
{}%
\repeat
\endgroup
\closein\dbroot
}
Edit: Now I will pass the filename by argument, and it works perfectly for me:
\documentclass[a4paper,12pt]{article}
\usepackage{filecontents}
\begin{filecontents*}{verses.dat}
§
§1§~{Mich respektvoll verneigend vor den Sugatas, vor dem Körper der Wahrheit, den sie besitzen, sowie vor ihren Kindern und ebenso vor allen, die der Verehrung wert sind, will ich die Ausübung der Disziplin der Sugata-Kinder entsprechend den Schriften in zusammengefasster Form darlegen.}
§
§2§~{Etwas, das es zuvor noch nicht gegeben hat, habe auch ich hier nicht zu sagen; und ich besitze nicht die Kunstfertigkeit in der Komposition von Schriften: Deshalb habe ich auch keine Absicht, anderen zu nutzen; vielmehr schreibe ich dieses, um meinen eigenen Geist daran zu gewöhnen.}
§
§3§~{Aufgrund der Gewöhnung an das Heilsame mag die Kraft meines Vertrauens durch diese Kontemplationen zeitweilig anwachsen; und wenn andere, die mir in ihren Veranlagungen ähnlich sind, diese sehen, so mag es auch für sie von Bedeutung sein.}
§
\end{filecontents*}
\usepackage{fontspec}
\defaultfontfeatures{Mapping=tex-text} %
\usepackage{polyglossia}
\setdefaultlanguage[spelling=new, babelshorthands=true]{german}
\usepackage{xstring}
\usepackage{xifthen}
\newcommand*{\isinxp}[2]{\expandafter\isinxpp\expandafter{#2}{#1}}
\newcommand*{\isinxpp}[2]{\isin {#2}{#1}}
\newread\dbroot
\newcommand{\myprintverse}[2]{%
\openin\dbroot=#1
\begingroup
\loop
\endlinechar=-1
\read\dbroot to \dbline
\unless\ifeof\dbroot
\ifthenelse{\isinxp{#2}{\dbline}}
{\StrCut{\dbline}{~}{\colA}{\colB}
(\StrBetween[1,2]{\colA}{§}{§})~{\colB}}%
{}%
\repeat
\endgroup
\closein\dbroot
}
\begin{document}
\myprintverse{verses.dat}{§1§} \par
\end{document}
Edit / Question: The above version works great unless I enter some LaTeX-Code, e.g. if I want to emphasize text:
\documentclass[a4paper,12pt]{article}
\usepackage{filecontents}
\begin{filecontents*}{verses.dat}
§
§1§~{Mich respektvoll verneigend vor den \emph{Sugatas}, vor dem Körper der Wahrheit, den sie besitzen, sowie vor ihren Kindern und ebenso vor allen, die der Verehrung wert sind, will ich die Ausübung der Disziplin der Sugata-Kinder entsprechend den Schriften in zusammengefasster Form darlegen.}
§
\end{filecontents*}
\usepackage{fontspec}
\defaultfontfeatures{Mapping=tex-text} %
\usepackage{polyglossia}
\setdefaultlanguage[spelling=new, babelshorthands=true]{german}
\usepackage{xstring}
\usepackage{xifthen}
\newcommand*{\isinxp}[2]{\expandafter\isinxpp\expandafter{#2}{#1}}
\newcommand*{\isinxpp}[2]{\isin {#2}{#1}}
\newread\dbroot
\newcommand{\myprintverse}[2]{%
\openin\dbroot=#1
\begingroup
\loop
\endlinechar=-1
\read\dbroot to \dbline
\unless\ifeof\dbroot
\ifthenelse{\isinxp{#2}{\dbline}}
{\StrCut{\dbline}{~}{\colA}{\colB}
(\StrBetween[1,2]{\colA}{§}{§})~{\colB}}%
{}%
\repeat
\endgroup
\closein\dbroot
}
\begin{document}
\myprintverse{verses.dat}{§1§} \par
\end{document}
Compilation stops with an error:
! Use of \@xs@StrCut@@ doesn't match its definition.
\text@command #1->\def \reserved@a {#1
}\ifx \reserved@a \@empty \let \check@...
l.43 \myprintverse{verses.dat}{§1§}
Any idea how this could be solved?
%
after{\colB}}
(and the next line with{}
is useless and adds another space. Next, you need to remove the trailing space due to the end-of-lines inverses.dat
. The easiest way is to enclose the loop in a group where you set\endlinechar=-1
\repeat }%
should not create a space. Recall that line endings in TeX get converted into a space. But if the last thing on the line is a control sequence like\endgroup
then this space disappears. And again: removing the{}
from the\ifthenelse
was faulty; the initial{}
should really be there, naturally as{}%
to avoid the space from the eol. The current code works, but by luck. It would fail with some other loop constructs ending in\repeat
, other than\LaTeX
's own\loop
.\verses.dat
but the control sequence\verses
is left undefined. Either use simplyverses.dat
or define\verses
:\newcommand*{\verses}{verses}
.