Re: Umlaut in kvoptions parameter

2 views
Skip to first unread message

Ulrike Fischer

unread,
May 8, 2022, 3:37:48 PMMay 8
to
Am Sun, 8 May 2022 15:43:30 +0100 schrieb Klaus Ethgen:


> Ein \show\lb@Buchstabe (im Hauptdokument) ergibt:
>> \lb@Buchstabe=macro:
> ->j, \unhbox \voidb@x \bgroup \let \unhbox \voidb@x \setbox \@tempboxa \hbox {o
> \global \mathchardef \accent@spacefactor \spacefactor }\let \begingroup \let \t
> ypeout \protect \begingroup \def \MessageBreak {
> (Font) }\let \protect \immediate\write \m@ne {LaTeX Font Info:
> on input line 5.}\endgroup \endgroup \relax \let \ignorespaces \relax \accent
> 127 o\egroup \spacefactor \accent@spacefactor .
> l.168 \show\lb@Buchstabe
>
> Mit dem folgenden Dokument bekomme ich das ausgelöst:
> \documentclass[fontsize=1cm, DIV=18]{scrartcl}
>
> \usepackage[latin1]{inputenc}
> \usepackage[Buchstabe={j, ö}]{Leseblatt}
> \begin{document}
> bla
> \end{document}
>
> Ich habe versucht, das ö anders zu kodieren. Ein "o ergibt genau das,
> ein "o. Und ein \"o ergibt den selben Fehler wie mit einem ö.
>
> Wenn ich \rohead* im Hauptdokument nur mit ö verwende, geht es. Der
> Fehler taucht hier also im Paket kvoptions auf.
>
> Irgendwer eine Idee, weshalb das ö als Parameter eine solch seltsame
> Expansion ergibt?

Weil das nun mal rauskommt, wenn ein Umlaut expandiert wird.

Kodiere deine Dateien nach utf8 um, entferne
\usepackage[latin1]{inputenc} und verwende ein aktuelles LaTeX. Dann
sind die Umlaute geschützt und sollten nicht mehr explodieren.

(mangels vollständigen Beispiels ungetestet).

Unabhändig davon, wäre es auch eine gute Idee
\usepackage[T1]{fontenc} zu benützen.


--
Ulrike Fischer
https://www.troubleshooting-tex.de/

Ulrike Fischer

unread,
May 8, 2022, 6:15:35 PMMay 8
to
Am Sun, 8 May 2022 21:21:25 +0100 schrieb Klaus Ethgen:

>> Weil das nun mal rauskommt, wenn ein Umlaut expandiert wird.
>
> Ok, aber kann ich das etwas eindämmen? Ein `\protect` nützt
> offensichtlich nix. Ich habe auch versucht, das mal mit nem \expandafter
> in geeignete Bahnen zu lenken, was jedoch auch nicht hilfreich war.

Vielleicht. Aber wie ich schon sagte: du hast kein Beispiel
geliefert und rumraten will ich nicht.

>
>> Kodiere deine Dateien nach utf8 um, entferne
>> \usepackage[latin1]{inputenc} und verwende ein aktuelles LaTeX. Dann
>> sind die Umlaute geschützt und sollten nicht mehr explodieren.
>
> Mit utf8 auf das Problem zu schießen ist sicher wie die bekannten
> Spatzen auf Kanonen...
>
> Dafür hat dan ein "aktuelles LaTeX" andere Probleme; gerade mit
> seltsamen Schriften, die ich in dem Fall zwingend nutzen muß.
>
> Wir hatten die Diskussion, glaube ich, schon mehrfach. UTF8 ist nicht
> die Lösung aller Probleme aber die Ursache neuer. Um so mehr, wenn man
> dadurch plötzlich gemischte Eingabedateien hat. Das hatte ich versucht
> und bin danach reumütig wieder zu latin1 zurückgekehrt.

Solange du latin 1 benützt, sind Umlaute an diversen Stellen keine
gute Idee.

Ulrich D i e z

unread,
May 17, 2022, 9:48:23 AMMay 17
to
Klaus Ethgen schrieb:

> Hi,
>
> ich habe ein schräges Problem mit kvoptions.
>
> Ich habe ein Paket, das folgendes verwendet:
> \RequirePackage{kvoptions}
> \RequirePackage{etoolbox}
> \SetupKeyvalOptions{%
> prefix=lb@,
> }
>
> \DeclareStringOption{Buchstabe}
> ...
> \rohead*{\lb@Buchstabe\hspace{\lb@r}}
>
> Im LaTeX-File nutze ich das üblicherweise so:
> \usepackage[Buchstabe={a}]{Leseblatt}
>
> Das klappt soweit eigentlich gut. Jetzt will ich jedoch ein "ö"
> übergeben, da meine Klasse nun an die Umlaute kommt. Damit schlägt mit
> pdflatex das ganze dann um die Ohren und der Kompile-Vorgang explodiert
> mit tausenden unterschiedlichen, aber nicht hilfreichen Fehlermeldungen.
>
> Ein \show\lb@Buchstabe (im Hauptdokument) ergibt:
>> \lb@Buchstabe=macro:
> ->j, \unhbox \voidb@x \bgroup \let \unhbox \voidb@x \setbox \@tempboxa \hbox {o
> \global \mathchardef \accent@spacefactor \spacefactor }\let \begingroup \let \t
> ypeout \protect \begingroup \def \MessageBreak {
> (Font) }\let \protect \immediate\write \m@ne {LaTeX Font Info:
> on input line 5.}\endgroup \endgroup \relax \let \ignorespaces \relax \accent
> 127 o\egroup \spacefactor \accent@spacefactor .
> l.168 \show\lb@Buchstabe
>
> Mit dem folgenden Dokument bekomme ich das ausgelöst:
> \documentclass[fontsize=1cm, DIV=18]{scrartcl}
>
> \usepackage[latin1]{inputenc}
> \usepackage[Buchstabe={j, ö}]{Leseblatt}
> \begin{document}
> bla
> \end{document}
>
> Ich habe versucht, das ö anders zu kodieren. Ein "o ergibt genau das,
> ein "o. Und ein \"o ergibt den selben Fehler wie mit einem ö.
>
> Wenn ich \rohead* im Hauptdokument nur mit ö verwende, geht es. Der
> Fehler taucht hier also im Paket kvoptions auf.
>
> Irgendwer eine Idee, weshalb das ö als Parameter eine solch seltsame
> Expansion ergibt?

Habe ich, aber die Erklärung ist langatmig.

Wenn das folgende Beispiel tatsächlich in Latin1/ISO-8859-1 codiert ist, dann
läuft es bei mir unter Verwendung einer 8-Bit-Engine, d.h. latex oder pdflatex,
ohne Fehlermeldungen durch:


\begin{filecontents*}{Leseblatt_UD_2022_05_17.sty}
\ProvidesPackage{Leseblatt_UD_2022_05_17}[2022/05/17 package Leseblatt]
\RequirePackage{kvoptions}
\RequirePackage{etoolbox}
\SetupKeyvalOptions{prefix=lb@,}
\DeclareStringOption{Buchstabe}
\ProcessKeyvalOptions*
\end{filecontents*}

\documentclass{scrartcl}
\usepackage[latin1]{inputenc}
\usepackage[Buchstabe={j, \unexpanded{\unexpanded{ö}}}]{Leseblatt_UD_2022_05_17}
\begin{document}
bla
\makeatletter\show\lb@Buchstabe
\end{document}



Warnungen:

1. Dieses Beispiel schreibt eine Datei "Leseblatt_UD_2022_05_17.sty".
Je nach der verwendeten LaTeX-Distribution kann es sein, dass eine bereits
existierende Datei "Leseblatt_UD_2022_05_17.sty" überschrieben/zerstört wird.

2. Dieses Posting ist UTF-8-codiert. Wenn man das Beispiel per Copy/Paste
aus diesem Posting herauskopiert, muss man sicherstellen, dass beim
Abspeichern der Textdatei die Zeichen, die man sieht, im
Latin1/ISO-8859-1-Encoding abgespeichert werden und nicht im UTF-8-Encoding.

Im Gegensatz zum gesamten Posting, welches ausser dem Beispiel noch weiteren
Text enthält, enthält das Beispiel keine Zeichen, die im
Latin1/ISO-8859-1-Encoding nicht direkt codierbar sind.
Ein guter Text-Editor, unter Linux zB Leafpad, sollte also in der Lage sein,
das Beispiel direkt im Latin1/ISO-8859-1-Encoding abzuspeichern.

Erläuterungen:

Wenn ein Schlüssel/Key per \DeclareStringOption definiert ist, wird der
Wert/Value erst voll expandiert, bevor das Makro, das zu diesem Wert
expandieren soll, definiert wird. Offenbar wird das Expandieren nicht nur
einmal getriggert.

Ich habe zwei \unexpanded verwendet, um \ProcessKeyvalOptions* zweimal am
Expandieren des Buchstaben "ö" zu hindern.

Sofern das Encoding der Shell, die ich verwende, ebenfalls auf Latin1/ISO-8859-1
eingestellt ist, sodass Latin1/ISO-8859-1-codierte Zeichen richtig angezeigt
werden, bekomme ich an der Konsole unter anderem folgende Ausgabe:

> \lb@Buchstabe=macro:
->j, ö.


Das heißt: \ProcessLocalKeyvalOptions expandiert den Buchstaben "ö" nicht
wenn er zweimal in \unexpanded eingeschachtelt wird.

Statt

\unexpanded{\unexpanded{ö}}

kann man im Latin1/ISO-8859-1-Encoding auch schreiben:

\noexpand\noexpand\noexpand ö

Wenn man eine 8-Bit-Engine verwendet, um mittels inputenc eine UTF-8-codierte
Eingabedatei zu verarbeiten, dann klappt die \noexpand\noexpand\noexpand-
Variante aber nicht unbedingt:

In UTF-8 wird das Zeichen "ö" durch eine Sequenz aus mehreren Bytes codiert,
von denen die 8-Bit-Engine aber jedes für sich genommen als (aktives)
Character-Token tokenizen wird. In 8-Bit Engines werden die einzelnen Bytes
eines Multi-Byte-UTF-8-Character einzeln auf (aktive) Character-Token
abgebildet. Der Multi-Byte-Character wird also durch eine Sequenz an (aktiven)
Character-Token repräsentiert. Davor gestelltes \noexpand\noexpand\noexpand
verhindert nur das Expandieren des ersten Character-Token einer solchen
Sequenz, sodass Versuche stattfinden können, nachfolgende Character-Token einer
solchen Sequenz zu expandieren, wobei alles mögliche Seltsame passieren kann.

--------------------------------------------------------------------------------

Wenn das Encoding der Shell auf UTF-8 eingestellt ist, bekomme ich statt dessen
übrigens

> \lb@Buchstabe=macro:
->j, �.

, d.h., statt eines Buchstabens "ö" wird das Zeichen "�" angezeigt.

Das ist kein Grund zur Beunruhigung. sondern liegt daran, dass das einzelne
Byte, das in 8-Bit-Engines unter Verwendung von inputenc in Latin1/ISO-8859-1
den Buchstaben "ö" repräsentiert, im UTF-8-Encoding nicht allein auftauchen
darf, weil dieses Byte im UTF-8-encoding, wenn es allein auftaucht, kein Zeichen
codiert. Wenn die auf UTF-8 eingestellte Shell auf ein Byte stößt, welches nicht
zu einer Byte-Sequenz gehört, die ein UTF-8-Zeichen codiert, dann behilft sie
sich, indem sie das Zeichen "�" anzeigt.

Bei "�" handelt es sich um ein Zeichen aus dem Unicode-Block "specials":

U+FFFD � REPLACEMENT CHARACTER used to replace an unknown, unrecognized, or unrepresentable character

(Für Interessierte gibt es mehr Info über den Replacement Character unter
<https://de.wikipedia.org/wiki/Ersetzungszeichen> )

--------------------------------------------------------------------------------

Was es damit auf sich hat, am "Expandieren eines Buchstaben" zu hindern:

Wenn man inputenc werwendet, wird davon ausgegangen, dass eine 8-Bit-Engine
verwendet wird. Also nichts, was auf Engines wie LuaTeX oder XeTeX beruht,
die von sich aus davon ausgehen, dass Eingabedateien UFT-8-codiert sind.

8-Bit-Engines wiederum gehen erstmal davon aus, dass in Eingabedateien jedes
Zeichen durch genau ein Byte (8 Bit) codiert ist. Also durch eine Sequenz
aus acht Nullen oder Einsen, die eine Zahl im Stellenwertsystem zur Basis 2
(auch Binärsystem genannt) darstellt. Sodass 2^8 verschiedene Zeichen,
nummeriert von 0 bis 255, codiert werden können.

8-Bit-Engines verarbeiten also Bytes, mittels derer sich (zB) nicht-negative
ganze Zahlen im Bereich von 0 bis 255 darstellen lassen.

Wenn 8-Bit-TeX Bytes verarbeitet, geht es darum, die durch die Bytes
dargestellten Zahlen auf Zeichen/Character abzubilden.
ZB Zeichen/Character, die auf den Bildschirm oder in Textdateien geschrieben
werden können. ZB Zeichen/Character, die dazu führen, dass bestimmte Glyphen
eines bestimmten Schriftschnitts in die pdf-Datei eingebettet werden.

8-Bit-TeX geht erstmal davon aus, dass es sich bei den durch die Bytes
dargestellten Zahlen um die Nummern handelt, die bestimmten Zeichen/Characters
im American Standard Code for Information Interchange (ASCII) zugewiesen sind.

Es sind im ursprünglichen/nicht-erweiterten ASCII aber nicht 256 Zeichen
durch nicht-negative ganze Zahlen im Bereich von 0 bis 255 codiert, sondern
nur 128 Zeichen durch nicht-negative ganze Zahlen im Bereich von 0 bis 127.

Anders gesagt: 8-Bit-Engines verarbeiten Bytes. Es wird aber davon ausgegangen,
dass keine Bytes vorkommen, die Zahlen im Bereich von 128 bis 255 darstellen.

Wenn man aber doch Bytes verwenden möchte, die Zahlen im Bereich von 128 bis
255 darstellen, was zB beim latin1/ISO-8859-1-Encoding der Fall ist, kann man
das Paket inputenc verwenden, um TeX beizubringen, was für Zeichen mittels
dieser Zahlen codiert sein sollen, und die entsprechenden Zeichen darzustellen,
bzw, was TeX tun soll wenn TeX ein Byte begegnet, das eine solche Zahl darstellt.

Das inputenc-Paket wendet folgenden Trick an: Bytes/Eingabezeichen, die in
ASCII gar kein Zeichen codieren würden, weil die Nummer, die das Byte
repräsentiert, nicht im Bereich 0 - 127 sondern im Bereich 128 - 255 liegt,
bekommen den Kategorie-Code 13 (Aktiv) zugewiesen und werden als expandierbare
Makros definiert, die dasjenige Zeichen liefern, das sie in der Eingabedatei
codieren.
Bei dem Multi-Byte-Encoding UTF-8 handelt es sich bei den aktiv gemachten
Zeichen/Bytes um Makros, die "nachschauen" was für Zeichen/Bytes noch
folgen und dann erst dementsprechend Zeichen liefern.

Mit "liefern" ist Unterschiedliches gemeint, je nach dem, was TeX gerade
tut. Das könnte sein zB das Schreiben auf die Konsole oder in eine externe
Textdatei, oder zB das Einbetten von Glyphen eines Schriftschnittes in
eine pdf-Datei.

Man hat beim Verwenden von inputenc also Aktive Zeichen/Bytes, die sich
wie Makros verhalten und deren Expandieren man manchmal verhindern muss.

( Der Umstand, dass aktiv gemachte Zeichen beim Einlesen und Tokenizen einer
Eingabedatei nicht Teil des Namens eines Kontrollsequenz-Tokens sein können,
TeX aber zB beim Laden des inputenc-Pakets die .sty-Datei richtig in
Kontroll-Sequenz-Token und Character-Token aufdröseln muss, impliziert
unter anderem folgendes:

1. Im Gegensatz zu LuaTeX- oder XeTeX-basierten Engines, die von sich aus
davon ausgehen, dass Eingabedateien UTF-8-codiert sind, kann man bei
8-Bit-Engines allenfalls solche Zeichen als Komponenten von Namen von
Kontroll-Sequenz-Token verwenden, die im ASCII-Encoding kodierbar sind.
Bei LuaTeX- oder XeTeX-basierten Engines gilt diese Einschränkung nicht.

2. Inputenc kann Encoding-Optionen nur für Encodings bereitstellen, die
den ASCII als Teilmenge enthalten. Wenn zB in der Eingabedatei das
Zeichen "a" durch ein anderes Byte dargestellt würde als man in ASCII
dafür verwendet, könnte zB die Zeichenfolge "\", "r", "e", "l", "a", "x"
der Eingabedatei nicht mehr als Kontrollsequenz-Token \relax getokenized
werden. Denn:
Entweder das Zeichen/Byte, das in der Eingabedatei das Zeichen "a"
codiert, wäre durch inputenc aktiv gemacht und würde somit nicht
als Teil des Namens eines Kontrollsequenz-Token angesehen.
Oder das Zeichen/Byte, das in der Eingabedatei das Zeichen "a"
codiert, wäre durch inputenc nicht aktiv gemacht. In diesem Fall würde
ein Byte vorliegen, welches eine andere Zahl darstellt als diejeinige,
mittels derer in ASCII das Zeichen "a" codiert wird. Diese andere Zahl
würde von TeX als ASCII-Nummer und folglich als Codierung eines von "a"
verschiedenen Zeichens interpretiert werden. )

Mit freundlichem Gruß

Ulrich

Ulrich D i e z

unread,
May 19, 2022, 5:14:29 PMMay 19
to
Klaus Ethgen schrieb:

> Ulrich D i e z <ud.usenetco...@web.de> schrieb:

>> \usepackage[Buchstabe={j, \unexpanded{\unexpanded{ö}}}]{Leseblatt_UD_2022_05_17}
>
> Selbst ein `\unexpanded` reicht bei mir und \lb@Buchstabe enthält das
> native ö (in dem Fall).

Ich habe jetzt nicht näher erforscht, wie bzw wie oft kvoptions die Werte/
Values von String-Optionen expandiert. Mein Beispiel läuft nur mit zwei
\unexpanded durch.


> Ich habe das nur versucht, mit `\expandafter` in den Griff zu bekommen,
> bin dabei jedoch gescheitert. `\unexpanded` kannte ich bisher garnicht.
>
>> \unexpanded{\unexpanded{ö}}
>>
>> kann man im Latin1/ISO-8859-1-Encoding auch schreiben:
>>
>> \noexpand\noexpand\noexpand ö
>
> Was ist der Unterschied zwischen `\unexpanded` und `\noexpand`? Und hast
> Du eine Erklärung, weshalb letzteres dreimal benötigt wird?

\noexpand selbst ist expandibel und verschwindet beim Expandieren. Sofern
das auf \noexpand nachfolgende Token expandierbar ist, verhindert \noexpand,
dass es durch den momentan laufenden Expansions-Trigger expandiert wird.
Stattdessen wird es durch den momentan laufenden Expansions-Trigger wie
das nicht expandierbare \relax-Primitive behandelt.

\unexpanded selbst ist expandibel. \unexpanded und die geschweiften Klammern
des Balanced Text, die sein "Argument" ausmachen, verschwinden beim
Expandieren. Bei allem, was zwischen den geschweiften Klammern steht, wird
verhindert, dass es durch den momentan laufenden Expansions-Trigger expandiert
wird.

Mit \noexpand kann man also das Expandieren nur eines einzigen Token
verhindern, nämlich des nachfolgenden Token.

Mit \unexpanded kann man das Expandieren vieler Token verhindern, nämlich
all derjenigen Token, die im Token-Stream zwischen den geschweiften Klammern
stehen.

Schauen wir uns mal \noexpand\noexpand\noexpand ö an und gehen dabei von
einem Encoding aus, bei dem das "ö" durch genau ein (aktives) Character-Token
repräsentiert wird. Weiter angenommen, es läuft als Expansions-Trigger eine
\edef-Expansion oder so etwas.

Das erste \noexpand verschwindet, verhindert aber, dass das zweite \noexpand
expandiert wird. Das zweite \noexpand bleibt also da -äh- und \relaxt. Das
dritte \noexpand verschwindert, verhindert aber, dass das aktive Character-Token
expandiert wird, welches das "ö" repräsentiert. Das "ö" "\relaxt" also auch.
Nach der ersten \edef-Expansion hat man also das zweite \noexpand und das "ö"
übrig, also die Sequenz \noexpand ö.

Wenn da jetzt eine zweite \edef-Expansion oder so etwas drüber läuft,
verschwindet das übrige \noexpand und verhindert, dass das ö expandiert wird.

Mit den drei \noexpand hat man also bei zwei aufeinanderfolgenden Expansions-
Triggern das Expandieren des ö verhindert.

>> In UTF-8 wird das Zeichen "ö" durch eine Sequenz aus mehreren Bytes codiert,
>> von denen die 8-Bit-Engine aber jedes für sich genommen als (aktives)
>> Character-Token tokenizen wird. In 8-Bit Engines werden die einzelnen Bytes
>> eines Multi-Byte-UTF-8-Character einzeln auf (aktive) Character-Token
>> abgebildet. Der Multi-Byte-Character wird also durch eine Sequenz an (aktiven)
>> Character-Token repräsentiert.
>
> War das schon immer so?

Wie man es nimmt. TeX und LaTeX gibt es länger als es Unicode und UTF-8 als
Variante, Unicode in Bytes zu codieren, gibt.
Sonst hätte Knuth vielleicht nicht ASCII als internes Character-Repräsentierungs-
Schema (im TeXbook heisst es "internal character representation scheme", weiss
auf die Schnelle nicht, wie man das adäquat übersetzen könnte) genommen. ;-)

Die Sache mit dem Abbilden der einzelnen Bytes eines Multi-Byte-UTF-8-Character
einzeln auf (aktive) Character-Token bei 8-Bit-Engines hat man in Hinblick
auf das Aktiv-Machen der jeweiligen Character dem inputenc-Paket zu verdanken.

Ob das im inputenc-Paket immer schon so implementiert war, kann ich nicht sagen,
aber als ich mich das erstenmal mit der UTF-8-Option des inputenc-Pakets näher
befasste, war das schon so. Ich kenne es also nur so. Mir fällt auf die Schnelle
auch nicht ein, wie man es auf einer 8-Bit-Engine anders effizient machen könnte.

Eine 8-Bit Engine fasst halt jedes Byte der TeX-Input-Datei als ein einzelnes
Zeichen des Input auf. Dabei, was TeX beim Einlesen der TeX-Input-Datei wegen
eines Zeichens macht, gibt es mehrere Möglichkeiten.
Im Prinzip folgende:

- Es kann sein, dass das Zeichen nicht getokenized wird, zB wenn es einen
Kategoriecode hat demuzfolge es ignoriert werden soll oder einen Kommentar
einleiten soll oder dergleichen.
- Wenn das Zeichen den Kategoriecode 0 hat (normalerweise ist nur dem
Backslash dieser Kategoriecode zugewiesen), fängt TeX an, Zeichen einzusammeln,
die den Namen eines Kontrollsequenz-Tokens bilden.
- Wenn TeX gerade Zeichen für den Namen eines Kontollsequenz-Token einsammelt,
kann es sein, dass das Zeichen als Teil des Namens des besagten Kontrollsequenz-
Tokens aufgefasst wird.
- Wenn TeX gerade kein Zechen für den Namen eines Kontollsequenz-Token einsammelt,
kann es sein, dass TeX ein explizites Character-Token an den Token-Stream
anfügt. Das ist dann ein Token, das in eine der für Character-Token möglichen
elf Kategorien gehört und einen Character-Code hat, der in den meisten Fällen
der Nummer des Zeichens im internes Character-Repräsentierungs-Schema der
TeX-Enine entspricht. In den meisten Fälllen, denn Input-Character mit
Kategoriecode 10(space) ergeben beim Tokenizen immer Character-Token der
Kategorie 10 mit Character-Code 32. (Kategoriecode 10 wird auch "space"
genannt, und 32 ist die ASCII-Nummer des Leerzeichens.)

Die elf möglichen Kategorien sind:

1 = Begin grouping, normally {
2 = End grouping, normally }
3 = Math shift, normally $
4 = Alignment tab, normally &
6 = Parameter, normally #
7 = Superscript, normally ^
8 = Subscript, normally _
10 = Space, normally <space> and <tab>
11 = Letter, normally only contains the letters a,...,z and A,...,Z. These characters can be used in command names
12 = Other, normally everything else not listed in the other categories
13 = Active character, for example ~

Die folgenden fünf Kategorie-Codes implizieren, dass Zeichen in der TeX-Input-Datei,
die diese Kategorie-Codes haben, nicht die Entstehung von expliziten Character-Token
bewirken, sondern sich anderweitig auf das Verhalten des Lese-Apparatus auswirken.

0 = Escape character, normally \
5 = End of line, normally <return>
9 = Ignored character, normally <null>
14 = Comment character, normally %
15 = Invalid character, normally <delete>

Im Gegensatz zu traditionellen 8-Bit-TeX-Engines, die jedes Byte einer
TeX-Input-Datei einzeln für ein (einziges) in der TeX-Input-Datei stehendes
Zeichen halten, gehen LuaTeX- und XeTeX-basierte Engines von vorneherein davon
aus, dass TeX-Inoput-Dateien in UTF-8 codiert sind, und fassen deshalb nicht
unbedingt nur ein Byte, sondern auch mal mehrere Bytes der .TeX-Input-
Datei, sofern sie zu einem Multi-Byte-UTF-8-Character gehören, als ein
einziges Zeichen auf.

>> ( Der Umstand, dass aktiv gemachte Zeichen beim Einlesen und Tokenizen einer
>> Eingabedatei nicht Teil des Namens eines Kontrollsequenz-Tokens sein können,
>> TeX aber zB beim Laden des inputenc-Pakets die .sty-Datei richtig in
>> Kontroll-Sequenz-Token und Character-Token aufdröseln muss, impliziert
>> unter anderem folgendes:
>>
>> 1. Im Gegensatz zu LuaTeX- oder XeTeX-basierten Engines, die von sich aus
>> davon ausgehen, dass Eingabedateien UTF-8-codiert sind, kann man bei
>> 8-Bit-Engines allenfalls solche Zeichen als Komponenten von Namen von
>> Kontroll-Sequenz-Token verwenden, die im ASCII-Encoding kodierbar sind.
>> Bei LuaTeX- oder XeTeX-basierten Engines gilt diese Einschränkung nicht.
>
> Gilt das auch, wenn ich `\csname ... \endcsname` verwende?

Da kommt es drauf an, wie man die Frage auffasst.

a)

\csname..\endcsname dient dazu, eine Sequenz von expliziten Character-_Token_(!)
zusammenzusammeln, also eine Sequenz von diesen beim Tokenizen entstehenden
Kategorie/Character-Code-Paaren, wobei expandierbare Token expandiert
werden, und die Character-Codes dieser Character-_Token_ als Komponenten
des Namens eines Kontollsequenz-Token aufzufassen, welches anstelle des
\csname...\endcsname-Ausdrucks in den Token-Stream platziert wird.

\csname..\endcsname wird in dem Stadium der Verarbeitung der Eingabe
ausgeführt, in dem das Expandieren stattfindet. Expandieren und Makros
und dergleichen bezieht sich immer auf bereits vorliegende Token.

Insofern als Einlesen und Tokenizen längst erledigt sind wenn
\csname..\encsname ausgeführt wird, ist die Frage also obsolet.

b)

Das variiert von Encoding zu Encoding.

Wenn man inputenc mit der latin1-Option verwendet, weil die Eingabedatei
in Latin1/ISO-8859-1 codiert ist, bekommt man mit dem in Latin1 codierten
"ö" innerhalb von \csname..\endcsname Probleme, weil da das Byte f6(hex)=
246(dec), welches in Latin1 das "ö" codiert, als aktives Character-Token
getokenized wird, welches wiederum zu Dingen expandiert, die innerhalb
von \csname..\endcsname nicht vorkommen dürfen und zu
"missing \encsname"-Fehlern führen.

Bein UTF-8-Encoding hat man sich Mühe gegeben, die "missing \encsname"-
Situation nicht aufkommen zu lassen:

Szenarium: UTF-8-codierte Eingabedatei wird unter Verwendung von inputenc
(mit der Option utf8) von einer 8-Bit-Engine verarbeitet.
Jedes Byte eines Multibyte-UTF-8-Character wird einzeln als (aktives)
Character-Token getokenized. Zum Beipiel das Zeichen "ö" besteht in
UTF-8 aus den Bytes c3(hex)=195(dec) und b6(hex)=182(dec). Diese Bytes
werden in 8-Bit-Engines einzeln zu (aktiven) Character-Token, die aber
offenbar alle nur zu Sachen expandieren, die in `\csname..\endcsname`-
Konstrukten erlaubt sind, als da zB wären die Catcode-11- oder -12-Pendants
dieser aktiven Character-Token, sodass die Byte-Sequenz erhalten bleibt.

Bei einer 8-Bit-Engine, die die einzelnen Bytes eines Multi-Byte-UTF-8-
Character einzeln als Character-Token interpretiert, hat man dann halt
im \csname..\endcsname-Konstrukt für einen Multi-Byte-UTF-8-Character
mehrere Character-Token im \csname..\endcsname-Konstrukt stehen,
entsprechend wird der Name des gebildeten Kontrollsequenz-Token nicht
aus einem sondern aus mehreren Zeichen bestehen.

Man kann die Anzahl an Zeichen, aus denen der Name eines
Kontrollsequenz-Tokens besteht, zählen lassen:


% \documentclass etc wird nicht gebraucht.
% Es keinerlei Text in eine .pdf- oder .dvi-Datei gesetzt.
% Es werden nur Sachen auf die Konsole ausgegeben.
% Beendet wird mit \stop statt \end{document}
\newcommand\firstoftwo[2]{#1}%
\newcommand\secondoftwo[2]{#2}%
\newcommand\countchars{\countcharsloop{0}}%
\newcommand\countcharsloop[2]{%
\ifx\relax#2\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{\message{There are #1 characters}}%
{\expandafter\countcharsloop\expandafter{\the\numexpr#1+1}}%
}%
\expandafter\expandafter\expandafter\countchars
\expandafter\string\csname ö\endcsname\relax

\expandafter\show\csname ö\endcsname\relax

\stop


Hier wird zuerst aus \csname ö\endcsname ein Kontrollsequenz-Token
gebildet. Dann wird da \string drauf losgelassen. Dann wird gezählt,
wieviele Zeichen/Character-Token \string geliefert hat.

In einer UTF-8-Engine wie LuaTeX oder XeTeX bekommt man ein
Kontrollsequenz-Token \ö, sodass \string zwei Zeichen liefert, nämlich
den Backslash und das ö. Entsprechend bekommt man mit LuaTeX oder
XeTeX auf der Konsole die Meldung
"There are 2 characters"

In einer 8-Bit-Engine, bei der (heutzutage ohne dass man dafür noch
großartig eine \usepackage-Zeile braucht) inputenc mit der utf8-Option
verwendet wird, um mit UTF-8 fertig zu werden, sieht die Sache anders
aus:

Wenn die Sache UTF-8 codiert ist, muss man bedenken, dass in UTF-8
das ö aus zwei Byte gebildet wird. Jedes davon wird in der 8-Bit-Engine
einzeln zu einem Character-Token des \csname..\endcsname-Ausdrucks.
Der Name des entstehenden Kontrollsequenz-Tokens besteht also aus zwei
Zeichen.
\string liefert also den Backslash und diese zwei Zeichen, insgesamt
also drei Zeichen, und mit 8-Bit-Engines, die inputenc mit UTF-8-Option
nutzen, bekommt man die Meldung
"There are 3 characters"

Der Name des Kontrollsequenz-Tokens hat in 8-Bit-Engines mehr Zeichen
als in UTF-8-Engines.

Das durch \csname..\endcsname erzeugte Kontrollsequenz-Token heisst in
8-Bit-Engines streng genommen gar nicht \ö.

Da das "ö" in UTF-8 aus den Bytes c3(hex)=195(dec) und b6(hex)=182(dec)
besteht, während das Byte c3(hex)=195(dec) in Latin 1/ISO-8859-1 das Zeichen
à codiert und das Byte b6(hex)=182(dec) in Latin 1/ISO-8859-1 das Zeichen
¶ codiert, liefert die 8-Bit-Engine beim Befehl

\expandafter\show\csname ö\endcsname\relax

auch diese Bytes an die Shell/Konsole.

Wenn die Shell auf Latin1/ISO-8859-1 eingestelllt ist, also ihrerseits
die Bytes, die sie geliefert bekommt, interpretiert als etwas, das in
Latin1/ISO-8859-1 codiert ist, bekommt man auf der Konsole an der
entsprechenden Stelle folgendes zu sehen:

> \ö=\relax.
<recently read> \ö

l.15 \expandafter\show\csname ö\endcsname
\relax

Da ich grade eben beschrieben habe, welche Bytes in Latin1/ISO-8859-1 die
Zeichen à bzw ¶ codieren, kann man auf die von der 8-Bit-Engine an die
Shell gelieferte Byte-Sequenz schliessen.

Das Nette daran ist, dass der Ausgangspunkt ja ein UTF-8-codiertes "ö" war,
welches durch diese beiden Bytes codiert wird.

Stellt man also die Shell auf UTF-8 um, dann interpretiert sie die Bytes,
die von der 8-Bit-Engine geliefert werden als etwas, das in UTF-8 codiert ist
und zeigt einem für die Byte-Sequenz c3(hex)=195(dec) und b6(hex)=182(dec)
ein "ö" an:

> \ö=\relax.
<recently read> \ö

l.15 \expandafter\show\csname ö\endcsname
\relax

Der Umstand, dass die auf UTF-8 eingestellte Shell das entsprechende
Multi-Byte-Zeichen anzeigt, darf einen nicht zu der Annahme verleiten,
innerhalb der 8-Bit-Engine wären die einzelnen Bytes eines UTF-8-Multibyte-
Character auf Token-Ebene irgendwie zu einem einzelnen Character-Token oder
zu einem einzelnen zum Namen eines Kontrollsequenz-Token gehörenden Zeichen
zusammengefasst.

In der 8-Bit-Engine wird bei einem UTF-8-Multibyte-Character jedes Byte
für sich zu einem Character-Token oder zu einem Zeichen, das Teil des Namens
eines Kontrollsequenz-Tokens ist, und zwischen \csname..\endcsname wird
jedes einzelne aus einem Byte eines UTF-8-Multibyte-Character entstandene
Character-Token zu einem zum Namen des zu bildenden Kontrollsequenz-Token
gehörenden Zeichen.

> Also Hände weg von EBCDIC und Co. (Gut, das war schon immer ein guter
> Rat. ;-)

Knuth geht in seinem TeXBook davon aus, dass diejenigen,
die TeX auf einer Maschine installieren, dabei die Routinen fürs
Konvertieren vom Encoding der Computerplattform zum TeX-intern
verwendeten ASCII-Encoding an die lokalen Gegebenheiten
anpassen. ;-)

Unter MiKTeX und TeXLive könnte man das zB über die tcx-files zur
Character-Translation machen. Dann könnte man EBCDIC und Co ohne
inputenc einlesen und schreiben. ;-)

Aber dann hätte man ein Problem wenn man zB parallel zu den
Character-Translation-Files inputenc verwenden möchte, um
bei einer in EBCDIC codierten Haupt-Datei via \input Dateien
zu laden, die anders codiert sind. ;->

In TeXbook, Appendix C: Character Codes werden gewissermaßen
Minimalanforderungen für den Eingabezeichensatz formuliert:

| A person who implements TeX on computer systems that do not
| have 95 externally representable symbols should adhere to the
| following guidelines: (a) Stay as close as possible to the
| ASCII conventions. (b) Make sure that codes ́ 041 – ́ 046 ,
| ́ 060 – ́ 071 , ́ 141 – ́ 146 , and ́ 160 – ́ 171 are present
| and that each unrepresentable internal code < ́ 200 leads to
| a representable code when ́ 100 is added or subtracted;
| then all 256 codes can be input and output. (c) Cooperate
| with everyone else who shares the same constraints, so that
| you all adopt the same policy. (See Appendix J for
| information about the TeX Users Group.)

In diesem Anhang C schimmern alte Pionier-Zeiten durch, in
denen Computer noch was für Rechenzentren waren, in denen
Wissenschaftler/innen ihre Standards für ihr Rechenzentrum/ihre
Fakultät entwickelten, weil es noch nichts Einheitliches gab.

> [excelente Erklärung]
> Wäre das nicht ein Beitrag in der TeXnischen Komödie wert?

Nein. Mein Geschwafel ist noch viel zu Kuddel-Muddel-mäßig.
Um das so auf die Reihe zu bekommen, dass eine Veröffentlichung
in einer Zeitschrift vielleicht verantwortbar wäre, müsste ich
noch einiges an Zeit investieren.

Und dann gäbe es bei den Leser/inne/n vermutlich im Wesentlichen
zwei Zielgruppen:

1. Diejenigen, die das alles schon lange wissen.
2. Diejenigen, die es nicht interessiert.

Vielleicht eine kleine Randgruppe Interessierter, die das noch
nicht alles wissen. Aber da halte ich Kommunikation in einem
Medium wie de.comp.text.tex/comp.text.tex oder TeX LaTeX StackExchange
für besser, weil nachgefragt werden kann und außerdem die
Regulars der Leserschhaft ein schnell eingreifendes Korrektiv
darstellen können.

Mit freundlichem Gruß

Ulrich

Ulrich D i e z

unread,
May 20, 2022, 9:09:38 AMMay 20
to
Ich schrieb:

> Man kann die Anzahl an Zeichen, aus denen der Name eines Kontrollsequenz-Tokens besteht, zählen lassen:

Um einen besseren Überblick zu bekommen, kann man nicht nur die Anzahl an
Zeichen, aus denen der Name eines Kontrollsequenz-Tokens besteht, zählen
lassen, sondern auch jedes Zeichen einzeln anzeigen lassen:



% \documentclass etc wird nicht gebraucht.
% Es wird keinerlei Text in eine .pdf- oder .dvi-Datei gesetzt.
% Es werden nur Sachen auf die Konsole ausgegeben.
% Beendet wird mit \stop statt \end{document}
\makeatletter
\newcommand\firstoftwo[2]{#1}%
\newcommand\secondoftwo[2]{#2}%
% \countchars ruft \countcharsloop mit "Startwerten für die ersten beiden
% Argumente auf.
\newcommand\countchars{\message{^^J}\countcharsloop{0}{}}%
% \countchars-loop sammelt unbegrenzte Argumente ein und zählt sie, bis
% es ein unbegrenztes Argument findet, dessen erstes Token das selbe Meaning
% hat wie das Kontrollwort-Token \relax. Bei einem solchen Argument kann es
% sich nicht um ein Token handeln, das durch \string geliefert worden ist.
\newcommand\countcharsloop[3]{%
% #1 - Anzahl an bisher eingesammelten unbegrenzten Argumenten.
% #2 - Biser eingesammelte unnegrenzte Argumente.
% #3 - In dieser Iteration eingesammeltes unbegrenztes Argument.
\ifx\relax#3\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{%
\message{We had the token #2.^^J}%
\message{Including the backslash the name of that token consists of #1 characters.}%
}{%
\message{There is the character #3.^^J}%
\expandafter\countcharsloop\expandafter{\the\numexpr#1+1}{#2#3}%
}%
}%
\expandafter\expandafter
\expandafter \countchars
\expandafter\string
\csname ö\endcsname\relax
\stop



Zuerst wird aus \csname ö\endcsname ein Kontrollsequenz-Token gebildet.
Dann wird wird \string auf dieses Kontrollsequenz-Token angewandt.
Dann wird gezählt wieviele Nicht-Space-Token \string produziert hat.
("Nicht-Space-Token", denn ich habe hier aus Faulheit schlampig gearbeitet:
\countcharsloop holt das nächste der durch \string produzierten Token
als unbegrenztes Argument. Beim Holen von unbegrenzten Argumenten werden
explizite Space-Token aber übergangen als ob sie nicht da wären. Ist bei
diesem Beispiel aber nicht wichtig, denn in diesem Fall produziert \string
nur Nicht-Space-Token.)

Das "ö" besteht in UTF-8 aus den Bytes c3(hex)=195(dec) und b6(hex)=182(dec).

Das Byte c3(hex)=195(dec) codiert in Latin 1/ISO-8859-1 das Zeichen à .
Das Byte b6(hex)=182(dec) codiert in Latin 1/ISO-8859-1 das Zeichen ¶ .

Wenn man bei zum Zeitpunkt der Abfassung dieses Postings - also am
8 .Mai 2022 - aktuellen LaTeX-Distributionen pdflatex oder latex aufruft,
wird auf 8-Bit-pdfTeX bzw auf 8-Bit-TeX basierendes LaTeX aufgerufen, bei dem
das inputenc-Paket mit der Option "utf8" gleich mitgeladen wird ohne dass man
dafür noch extra einen \usepackage-Befehl oder so etwws angeben müsste.


Man muss bei Meldungen auf der Konsole immer zwei Dinge im Auge behalten:
a) Welche Bytes schickt die Engine an die Shell?
b) Was macht die Shell selbst beim Anzeigen am Bildschirm aus diesen Bytes?

Unterscheiden von vier Szenarien - in allen vier Szenarien sei das obige
Beispiel im UTF-8-Encoding abgespeichert:

1. Engine: Das Beispiel wird mit 8-Bit LaTeX compiliert, welches von sich aus
das inputenc-Paket mit der Option "utf8" gleich mitlädt.
Encoding der Shell: Die Shell ist auf Latin 1/ISO-8859-1 eigestellt,
interpretiert also alles, was ihr von der TeX-Engine geliefert wird,
als in Latin 1/ISO-8859-1 codierten Text.

Man erhält folgende Meldungen/Zeichen auf der Konsole:

There is the character \.
There is the character Ã.
There is the character ¶.
We had the token \ö.
Including the backslash the name of that token consists of 3 characters.

Hier sieht man gut, dass die 8-Bit-Engine die beiden einzelnen Bytes des
Multi-Byte-UTF-8-Character "ö" für einzelne Zeichen hält und deshalb auch
als einzelne Zeichen an die Shell schickt. Die auf Latin 1/ISO-8859-1
eingestellte Shell zeigt diejenigen Zeichen an, die im
Latin 1/ISO-8859-1-Encoding durch diese Bytes codiert werden.

2. Engine: Das Beispiel wird mit 8-Bit LaTeX compiliert, welches von sich aus
das inputenc-Paket mit der Option "utf8" gleich mitlädt.
Encoding der Shell: Die Shell ist auf UTF-8 eigestellt,
interpretiert also alles, was ihr von der TeX-Engine geliefert wird,
als in UTF-8 codierten Text.

Man erhält folgende Meldungen/Zeichen auf der Konsole:

There is the character \.
There is the character �.
There is the character �.
We had the token \ö.
Including the backslash the name of that token consists of 3 characters.

Hier sieht man gut, dass die 8-Bit-Engine die beiden einzelnen Bytes des
Multi-Byte-UTF-8-Character "ö" für einzelne Zeichen hält und deshalb auch
als einzelne Zeichen an die Shell schickt. Die auf UTF-8 eingestellte
Shell kann mit den einzeln geschickten Bytes nichts anfangen, da sie für
sich genommen in UTF-8 keine Zeichen codieren und behilft sich, indem
sie für jedes Byte, welches nicht zu einer Byte-Sequenz gehört, die ein
UTF-8-Zeichen codiert, das Zeichen "�" anzeigt.
In der Zeile "We had the token \ö" hat die 8-Bit-Engine die beiden Bytes
des Multi-Byte-UTF-8-Character "ö" jeweils als einzelne Zeichen an die
Shell geschickt. Die Bytes, durch die diese Zeichen codiert werden,
stehen aber direkt hintereinander und werden deshalb von der auf UTF-8
eingestellten Shell als ein UTF-8-codiertes "ö" interpretiert, welches
angezeigt wird.

3. Engine: Das Beispiel wird mit lualatex oder xelatex compiliert, also mit
einer TeX-Engine, die von sich aus davon ausgeht, dass die
TeX-Eingabedate in UTF-8 codiert ist.
Encoding der Shell: Die Shell ist auf Latin 1/ISO-8859-1 eigestellt,
interpretiert also alles, was ihr von der TeX-Engine geliefert wird,
als in Latin 1/ISO-8859-1 codierten Text.

Man erhält folgende Meldungen/Zeichen auf der Konsole:

There is the character \.
There is the character ö.
We had the token \ö.
Including the backslash the name of that token consists of 2 characters.

Hier sieht man gut, dass die UTF-8-TeX-Engine das aus zwei Bytes bestehende
"ö" als ein einziges Zeichen interpretiert, welches aber von der
Latin 1/ISO-8859-1-Shell beim Anzeigen der Meldung für zwei aus jeweils
einem Byte bestehende Latin 1/ISO-8859-1 codierte Zeichen gehalten wird.

4. Engine: Das Beispiel wird mit lualatex oder xelatex compiliert, also mit
einer TeX-Engine, die von sich aus davon ausgeht, dass die
TeX-Eingabedate in UTF-8 codiert ist.
Encoding der Shell: Die Shell ist auf UTF-8 eigestellt,
interpretiert also alles, was ihr von der TeX-Engine geliefert wird,
als in UTF-8 codierten Text.

Man erhält folgende Meldungen/Zeichen auf der Konsole:

There is the character \.
There is the character ö.
We had the token \ö.
Including the backslash the name of that token consists of 2 characters.

Hier sieht man gut, dass die UTF-8-TeX-Engine das aus zwei Bytes bestehende
"ö" als ein einziges Zeichen interpretiert, welches auch von der UTF-8-Shell
beim Anzeigen der Meldung als ein einziges Zeichen interpretiert wird.


Mit freundlichem Gruß

Ulrich
Reply all
Reply to author
Forward
0 new messages