我想要在数据文件 cities.txt 中找到某一行文本:
A;London
B;Berlin
C;Paris
与xstring
以及 [ xifthen
][2] 软件包:
\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}
但是如果要比较的文本行存储在宏变量中,则字符串比较不起作用,\dbline
尽管如果我打印\dbline
它,它会完美扩展。这让我很抓狂...有什么帮助吗?
编辑:根据 jfbu 的回答(谢谢!)我尝试将搜索代码放入命令中并通过参数传递搜索字符串。看来成功了!
以下是我现在使用该函数的方式。多余的空格是个问题(参见讨论)
% <-*- 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}
编辑:这是现在无需添加空格即可运行的完美版本的命令:
\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
}
编辑:现在我将通过参数传递文件名,这对我来说非常有效:
\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}
编辑/问题:除非我输入一些 LaTeX 代码,否则上述版本效果很好,例如如果我想强调文本:
\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}
编译因错误而停止:
! 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§}
有什么办法可以解决这个问题吗?
答案1
更新:已添加强制 xinttools 方法
有两个问题。第一个问题是\isin
from 包xifthen
没有展开它的第二个参数,这里是\dbline
。第二个问题是\isin
使用的 LaTeX 内核\in@
无法处理\par
标记;但 TeX 总是会\par
在通过 的文件输入末尾附加一个标记\read
,除非 \endlinechar 设置为 -1。
第一个问题可以通过定义一个\isinxp
扩展其第二个参数的包装器来解决。第二个问题(假设\endlinechar
不是 -1)通过在读取行之后和测试之前测试文件末尾来解决。
\documentclass[12pt, a4paper]{article}
\usepackage{filecontents}
\begin{filecontents*}{cities.txt}
A;London
B;Berlin
C;Paris
\end{filecontents*}
\usepackage{xstring}
\usepackage{xifthen}
% star form as anyhow \isin is declared short, and furthermore
% uses internally \in@ from the LaTeX kernel which is short
\newcommand*{\isinxp}[2]{\expandafter\isinxpp\expandafter{#2}{#1}}
\newcommand*{\isinxpp}[2]{\isin {#2}{#1}}
\begin{document}\thispagestyle{empty}
\newread\dbcities
\openin\dbcities=cities.txt
We start here:
\loop
\read\dbcities to \dbline
% (testing) \texttt{\meaning\dbline}
\unless\ifeof\dbcities
\ifthenelse{\isinxp{A}{\dbline}}
{\StrCut{\dbline}{;}{\colA}{\colB}
\colA: \colB \\}
{}
\repeat
\closein\dbcities
\end{document}
强制性新工具方法:
(我已经修正了键匹配,因为搜索BB
会返回带有B
键的数据行的误报。请注意,包含BB
键的数据行在查找时返回正值B
是预期的事情,正如 OP 所使用的那样\isin
。)
\documentclass[12pt, a4paper]{article}
\usepackage{filecontents}
\begin{filecontents*}{\jobname.dat}
A;London
B; Berlin
BB; Hamburg
C ; Paris
A ; London again
D;Roma
\end{filecontents*}
\usepackage{xinttools}
\newread\datastream
% to issue warnings if command names already in use, then one knows one
% has to change them (depens on loaded packages)
\newcommand {\onedataline}{}
\newcommand {\printdatakey}{}
\newcommand {\printdatatestkey}{}
\newcommand {\printdataprocessline}{}
\newcommand {\printdata}[2]{% #1 = file name, #2 string to test
\openin\datastream=#1\relax
% the string key will be trimmed of its leading and trailing spaces
\edef\printdatakey
{\expandafter\xintZapSpaces\expandafter{\detokenize{#2}}}%
%
\edef\printdatatestkey
{\unexpanded{\def\printdatatestkey ##1}\printdatakey
\unexpanded{##2\relax ##3\par {\ifx\relax##2\relax\else ##3\par\fi}}}
%
\printdatatestkey % sets up \printdatatestkey macro to seek the key.
% [added a ; to avoid false positives if for example the seeked key is BB
% and the actual one is B.]
\edef\printdataprocessline ##1;##2\relax
{\noexpand\printdatatestkey ##1;\printdatakey\relax
\printdatakey: \noexpand\xintZapSpaces {##2}\noexpand\par }%
%
\xintloop
\read\datastream to \onedataline
% detokenize the line for safe handling.
% \odef expands once the argument, this is enough
\odef\onedataline{\detokenize\expandafter{\onedataline}}%
\unless\ifeof\datastream
\expandafter\printdataprocessline\onedataline\relax
% j'aurais dû faire directement
% \expandafter\printdataprocessline\detokenize\expandafter{\onedataline}\relax
\repeat
\closein\datastream
}
\begin{document}\thispagestyle{empty}
Testing A:
\printdata{\jobname.dat}{ A }
\medskip
Testing B:
\printdata{\jobname.dat}{ B}
\medskip
% sans le ; faux positif sur Berlin
Testing BB:
\printdata{\jobname.dat}{BB}
\medskip
Testing D:
\printdata{\jobname.dat}{ D }
\end{document}
答案2
LaTeX3 的实现。
\begin{filecontents*}{\jobname.dat}
A;London
B;Berlin
C;Paris
\end{filecontents*}
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\printdata}{ mm }
{% #1 is the file name, #2 is the key to test
\christof_printdata:nn { #1 } { #2 }
}
\ior_new:N \g_christof_data_stream
\cs_new_protected:Npn \christof_printdata:nn #1 #2
{% do a mapping on file #1
\ior_open:Nn \g_christof_data_stream { #1 }
\ior_map_inline:Nn \g_christof_data_stream
{% every entry is of the form "key;value", ##1 stands for the whole line
\__christof_process_line:nww { #2 } ##1 \q_stop
}
}
\cs_new_protected:Npn \__christof_process_line:nww #1 #2 ; #3 \q_stop
{% #1 is the key to test, #2 is the key, #3 is the value
\tl_if_in:nnT { #2 } { #1 }
{
\tl_trim_spaces:n { #2 }: ~ \tl_trim_spaces:n { #3 } \par
}
}
\ExplSyntaxOff
\begin{document}
Testing A:
\printdata{\jobname.dat}{A}
\medskip
Testing B:
\printdata{\jobname.dat}{B}
\end{document}
以下是展示真实需求后的实现。
\begin{filecontents*}{\jobname.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*}
\documentclass{article}
\usepackage{fontspec}
\usepackage{polyglossia} % the multilingual support package
\setdefaultlanguage[spelling=new, babelshorthands=true]{german}
\usepackage{xparse}
\usepackage{xparse}
\ExplSyntaxOn
% generic command
\NewDocumentCommand{\printdata}{ mm }
{% #1 is the file name, #2 is the key to test
\christof_printdata:nn { #1 } { #2 }
}
% with fixed file name
\NewDocumentCommand{\myprintverse}{ m }
{
\printdata { \jobname.dat } { #1 } % <--- Fix the file name
}
\ior_new:N \g_christof_data_stream
\seq_new:N \l__christof_entry_seq
\cs_new_protected:Npn \christof_printdata:nn #1 #2
{
\ior_open:Nn \g_christof_data_stream { #1 }
\ior_map_inline:Nn \g_christof_data_stream
{
\tl_if_in:nnT { ##1 } { #2 }
{
\__christof_process_line:ww ##1 \q_stop
}
}
}
\group_begin:
\char_set_catcode_active:N \^^A
\char_set_lccode:nn { `\^^A } { `\~ }
\tl_to_lowercase:n
{
\group_end:
\cs_new_protected:Npn \__christof_process_line:ww §#1§ ^^A #2 \q_stop
}
{% #1 is the key, #2 is the value
(#1) \nobreakspace \tl_trim_spaces:n { #2 }
}
\ExplSyntaxOff
\begin{document}
Each line of data printed in a seperate paragraph:
\medskip
\myprintverse{§1§}
\myprintverse{§2§}
\myprintverse{§3§}
\bigskip
Two lines in one paragraph results in proper space between them
\medskip
\myprintverse{§1§} \myprintverse{§2§}
\myprintverse{§3§}\footnote{This is also a problem if I want to add a footnote.}
\end{document}
由于是一个特殊字符,因此这个\tl_to_lowercase:n
技巧是必要的。~