Re: testing for endofline
- From: "Ulrich Diez" <eu_angelion@xxxxxxxxxxxxxx>
- Date: Thu, 18 Dec 2008 19:41:51 +0100
Ulrike Fischer wrote:
Am Fri, 28 Nov 2008 12:41:41 +0100 schrieb Ulrich Diez:
Depending on what you do with these spaces (will they also serve
as macro-delimiters/terminators for \numbers etc or are they just
some sort of "word-separator" in the output-text?)
There are move separators in the input: "Ke4 Re5".
Hello!
I've just completed defining some expandable iteration and I
thought, you might be interested.
You can consider your input a list of Elements, separated by
"move separators". If you don't allow line-breaks, "move
separators" are space-tokens. If you allow line-breaks, "move
separators" can also be \par-tokens.
In this case you could probably use the iterators described below
for first iterating your input as a list of \par-token-separated-
elements and generating a new list, where \par-separators are
replaced by space-tokens. This way all move-separators would be
turned into spaces. Afterwards that list could be iterated as a
list of space-token-separated elements and be transformed into a
list where each Element is surrounded by braces for further
processing.
You could allow more kinds of move-separators, e.g., commas, and
replace them by spaces in the same way like \par-tokens...
The pattern of iteration is:
\<Prefix>iterator{%
{<action>}%
{<action if list is empty>}%
{first/second}%
{<additional arguments for action>}%
}%
{<ElementN><Separator><ElementN+1><Separator>...}
If list is not empty, at some stage expands to:
<action>{<ElementN>}<Additional arguments for action>
\<Prefix>iterator{%
{<action>}%
{<action if list is empty>}%
{first/second}%
{<additional arguments for action>}%
}%
{<ElementN+1><Separator>...}
You can define <action> to also gobble up \<Prefix>iterator and
\<Prefix>iterator's first argument in order to spit out a call
to \<Prefix>iterator where \<Prefix>iterator's first argument --
which holds <action>, <action if list is empty>, first/second
and <additional arguments for action> for the next iteration-
round -- is modified depending on the results of processing
values passed as current <ElementN> and current
<additional arguments for action>.
If list is empty, at some stage expands to:
<action if list is empty>
By either supplying "first" or "second" as value for the
"first/second"-argument, you can influence brace-handling when
passing <Element N> from the list to <action>.
With the value "first", one brace-level will - if present - be
stripped from <ElementN>. Afterwards <ElementN> will get wrapped
into braces and be passed to <action>. This way things like
<ElementN>={\@macro} and <ElementN>=\@macro will both be passed
as <action>{\@macro}<Prefixes>.
With the value "second", no brace-level will be stripped from
<ElementN>. <ElementN> will be wrapped into braces and be passed
to <action>. This way braces are untouched and
<ElementN>={\@macro} will be passed as
<action>{{\@macro}}<Prefixes> , while <ElementN>=\@macro will be
passed as <action>{\@macro}<Prefixes>.
I wrote "the pattern of iteration is" and I did not specify
<separator> as actually I wrote a set of macros for defining the
iteration-mechanism depending on what you wish to use as
<separator>.
The definer-macro for the iterator-mechanisms is:
\defineiterator{<Prefix>}{<Separator>}
This defines a set of macros, with an iterator whose name is
\<Prefix>iterator and which iterates in the way described above
on lists whose Elements are separated by <separator>. "Emptiness"
between consecutive <separators> will not be considered an
Element. "Emptiness" between consecutive <separators> will not be
considered an "empty"-Element. In case <Separator> is not a
space-token, space-tokens will be considered (parts of) elements.
If you leave <Separator> empty, iteration will take place token-/
argumentwise, and what was said above about the "first/second"-
argument still almost applies. Space-tokens still will also be
considered elements of the list. I wrote "almost" as if in this
case the value "second" is specified, and if braces/a pair of
catcode1/2-characters surround <ElementN>, there will be a subtle
difference:
In case A and B have catcode 1 / 2, an Element A\@macroB
will also be passed as
<action>{{\@macro}}<Prefixes>
, while with non-empty-separator that would be passed as
<action>{A\@macroB}<Prefixes> .
The iterator-macros defined by \defineiterator can be used in
expandable contexts and the end of the list is detected depending
on the emptiness of the iterator-macro's second argument which
holds the list. This way you don't need a "sentinel"- or
"bizarre"-token/element for marking the end of the list.
Ulrich
Here comes the coding:
%%
%% Copyright (C) 2008 by Ulrich Diez (eu_angelion@xxxxxx)
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public Licence (LPPL), either
%% version 1.3 of this license or (at your option) any later
%% version. (The latest version of this license is in:
%% http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status 'not maintained'.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty - neither for probably included
%% documentation nor for any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%%
\errorcontextlines=10000
\documentclass{article}
\makeatletter
%%---------------------------------------------------------------
%% Stopper for \romannumeral-Expansion:
%%...............................................................
\newcommand\@rmstop{0 }
%%---------------------------------------------------------------
%% Check if argument is blank / is null:
%%...............................................................
\newcommand\@ifnull[1]{%
\romannumeral\expandafter\@firstofone\expandafter{\expandafter
\expandafter\expandafter\@rmstop\csname @\expandafter\@gobble
\string{\expandafter\@secondoftwo\expandafter{\expandafter{%
\string#1}{}\expandafter\expandafter\expandafter\@gobble
\expandafter\@gobble\string}{}\expandafter\expandafter
\expandafter\@firstoftwo\expandafter\expandafter\expandafter{%
\expandafter\@gobble\string}second}{first}oftwo\endcsname}%
}
\newcommand\@ifblank[1]{%
\romannumeral\expandafter\expandafter\expandafter\@gobble
\expandafter\@ifnull\expandafter{\@gobble#1.}%
}
%%---------------------------------------------------------------
%% Check if brace-balanced argument starts with a bgroup-char:
%%...............................................................
\newcommand\@ifbrace[1]{%
\romannumeral\expandafter\@firstofone\expandafter{%
\expandafter\expandafter\expandafter\@rmstop
\csname @%
\expandafter\@gobble\string{%
\expandafter\@gobble
\expandafter{%
\expandafter{%
\string#1}%
\expandafter\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter\expandafter\expandafter
\@firstoftwo\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter\@gobble\expandafter
\expandafter\expandafter\@gobble\expandafter\expandafter
\expandafter{%
\expandafter\string
\expandafter}%
\string}%
\expandafter\@gobble\string}%
\@secondoftwo
{first}{second}oftwo\endcsname
}%
}
%%---------------------------------------------------------------
%% Check if brace-balanced argument starts with a space-char:
%%...............................................................
\newcommand\@iffirstspace[1]{%
\romannumeral\expandafter\expandafter
\expandafter\@rmstop
\csname @\@ifnull{#1}{second}{%
\iffalse{\fi\@@iffirstspace.#1 something}%
}oftwo\endcsname
}
\@ifdefinable\@@iffirstspace{%
\long\def\@@iffirstspace#1 #2{%
\expandafter\@ifnull\expandafter{\@gobble#1}{%
first\expandafter\@gobble\expandafter{\iffalse}\fi
}{%
second\expandafter\@gobble\expandafter{\iffalse}\fi
}%
}%
}%
%%---------------------------------------------------------------
%% \defineiterator{<Prefix>}{<Separator>}
%%...............................................................
%%
%% defines
%%
%% \<Prefix>iterator{%
%% {<action>}%
%% {<action if list is empty>}%
%% {first/second}%
%% {<additional arguments for action>}%
%% }%
%% {<ElementN><Separator><ElementN+1><Separator>...}
%%
%% to at some stage expand to either:
%%
%% <action>{<ElementN>}<Additional arguments for action>
%% \<Prefix>iterator{%
%% {<action>}%
%% {<action if list is empty>}%
%% {first/second}%
%% {<additional arguments for action>}%
%% }%
%% {<ElementN+1><Separator>...}
%%
%% or:
%%
%% <action if list is empty>
%%
%%...............................................................
\newcommand\PassFirstToSecond[2]{#2{#1}}
\newcommand*\@rmspace[1]{\long\def\@rmspace#1{}}\@rmspace{ }%
\newcommand\@remothertlstelts[7]{%
\expandafter\@ifnull\expandafter{%
\romannumeral
\csname @\@ifnull{#4}{}{#5}remfirstlstelt\endcsname{#1}#1}%
{%
\expandafter\expandafter
\expandafter\@ifeltnull
\expandafter\expandafter
\expandafter{%
\expandafter\@gobble
\romannumeral
\csname @\@ifnull{#4}{}{#5}striptrailsep%
\endcsname{ #1}{#3}{.}#1}{#6}{#4}{#5}{#3}#7{#2}%
}{%
\expandafter\expandafter
\expandafter\@remothertlstelts
\expandafter\expandafter
\expandafter{%
\expandafter\@gobble
\romannumeral
\csname @\@ifnull{#4}{}{#5}remmoretlstelts%
\endcsname{#1}{.}#1}{#2}{#3}{#4}{#5}{#6}{#7}%
}%
}
\newcommand\@ifeltnull[6]{%
\@ifnull{#1}{\endcsname{}}{%
\expandafter\expandafter
\expandafter\endcsname
\expandafter\PassFirstToSecond
\expandafter{%
\romannumeral
\csname @\@ifnull{#3}{}{#4}striptrailsep%
\endcsname{#1}{#5}#1#3}{{#2}}#6%
}%
}%
\newcommand\getfirstlstelt[8]{%
\csname @firstofone%
\@ifnull{#8}%
{\endcsname{#4}}%
{%
\expandafter\expandafter
\expandafter \@remothertlstelts
\expandafter\PassFirstToSecond
\expandafter{%
\romannumeral
\csname @\@ifnull{#2}{}{#1}remfirstlstelt%
\endcsname{#8}#8}{{#8{}\@nil#2}}{#5}{#2}{#1}{#3}{{#6}#7}%
}%
}%
\@ifdefinable\@remmoretlstelts{%
\long\def\@remmoretlstelts#1#2#3#4\@nil{%
\@iffirstspace{#1}{\@rmstop{} }{%
\@ifbrace{#1}{\@rmstop{}{#3}}{\@rmstop{}#3}%
}%
}%
}%
\newcommand\@remfirstlstelt[1]{%
\@iffirstspace{#1}{\expandafter\@rmstop\@rmspace}%
{\expandafter\@rmstop\@gobble}%
}%
\newcommand\@striptrailsep[2]{%
\csname @#2oftwo\endcsname
{\@iffirstspace{#1}%
{\@rmstop}%
{\expandafter\@rmstop\@firstofone}}%
{\@rmstop}%
}%
\newcommand\defineiterator[2]{%
\expandafter\newcommand\csname #1iterator\endcsname[2]{%
\renewcommand##1[2]{%
##2{####1}{####2#2}%
}%
\newcommand##2[2]{%
\getfirstlstelt{#1}{#2}####1%
{##2{####1}%
}{####2}%
}%
}%
\csname #1iterator\expandafter\endcsname
\csname #1iterator\expandafter\endcsname
\csname @#1iterator\endcsname
%
\@ifnull{#2}{}{%
\expandafter\@ifdefinable
\csname @#1remmoretlstelts\endcsname{%
\expandafter\long
\expandafter\def
\csname @#1remmoretlstelts%
\endcsname##1##2#2##3\@nil#2{\@rmstop##2#2}%
}%
\expandafter\@ifdefinable
\csname @#1remfirstlstelt\endcsname{%
\expandafter\long
\expandafter\def
\csname @#1remfirstlstelt\endcsname##1##2#2{\@rmstop}%
}%
\expandafter\@ifdefinable
\csname @#1striptrailsep\endcsname{%
\expandafter\long
\expandafter\def
\csname @#1striptrailsep\endcsname##1##2##3#2{%
\csname @##2oftwo\endcsname
{\@rmstop##3}%
{\@ifbrace{##1}{\@rmstop##1}{\@rmstop##3}}%
}%
}%
}%
}%
\defineiterator{}{}%
%%---------------------------------------------------------------
\makeatother
\defineiterator{Space}{ }%
\defineiterator{Par}{\par}%
\newcommand\parbyspacereplace[4]{%
\Pariterator{{\parbyspacereplace}{%
\Spaceiterator{{\spacebybracereplace}{%
\iterator{{\Printmessage}{\message{^^JFinito.}}{first}{}}{}%
}{second}{{}}}{#2 #1}%
}{second}{{#2 #1}}}%
}%
\newcommand\spacebybracereplace[4]{%
\Spaceiterator{{\spacebybracereplace}{%
\iterator{{\Printmessage}{\message{^^JFinito.}}{first}{}}{#2{#1}}%
}{second}{{#2{#1}}}}%
}%
\newcommand\Printmessage[1]{\message{^^J#1}}%
\newcommand\GothroughList{%
\Pariterator{{\parbyspacereplace}{%
\Spaceiterator{{\spacebybracereplace}{%
\iterator{{\Printmessage}{\message{^^JFinito.}}{first}{}}{}%
}{second}{{}}}{}%
}{second}{{}}}%
}%
\makeatother
\begin{document}
\GothroughList{{Element1} \par {Element2} {{ Element 3}} {Element4} Element5}%
\GothroughList{{Element1} \par
{Element2}
{{ Element 3}} {Element4}
Element5
}%
\GothroughList{{Element1}{Element2}{{ Element 3}}{Element4}Element5 }%
\GothroughList{{Element1}{Element2}{{ Element 3}}{Element4}Element5}%
\GothroughList{\par \par}%
\end{document}
.
- Follow-Ups:
- Re: testing for endofline
- From: Ulrike Fischer
- Re: testing for endofline
- Prev by Date: Re: Unwanted extra spacing at top of page after \vspace*
- Next by Date: Re: Searchable PDFs with cmap and Charter font
- Previous by thread: Searchable PDFs with cmap and Charter font
- Next by thread: Re: testing for endofline
- Index(es):
Relevant Pages
|