Verschachtelte \defs verursachen \inaccessible-Fehler

Verschachtelte \defs verursachen \inaccessible-Fehler

Ich habe eine - zumindest in meinen Augen - sehr einfache Möglichkeit zur Großschreibung von Wörtern ausprobiert:

\documentclass{article}

\begin{document}
\begingroup%
\obeyspaces%\catcode`\ \active
\def {\space\MakeUppercase}%
Hello world
\endgroup
\end{document}

Selbstverständlich habe ich auch versucht, dies in ein Makro zu packen, wie

\documentclass{article}

\newcommand{\capitalize}[1]{\begingroup\obeyspaces\def {\space\MakeUppercase}#1\endgroup}

\begin{document}
\capitalize{Hello world}
\end{document}

was dazu führt, dass TeX die Syntax des inneren Elements bemängelt \defund es erstellt \inaccessible.

Was genau läuft schief und gibt es eine Möglichkeit, das Problem zu umgehen?

Antwort1

Dies ist das übliche \verbProblem, wenn ein Argument nicht funktioniert.

\obeyspacesändert den Catcode von Space, was bedeutet, dass ein SpaceCharakterin einemDateiwird in ein aktives Token umgewandelt. Catcode-Änderungen wurdenNEIN\newcommandAuswirkungen auf bereits erstellte Token. In Ihrem Fall wurde das gesamte Argument von tokenisiert, sodass \defdanach überhaupt kein Leerzeichen-Token mehr vorhanden ist \def{.

Sie müssen den Catcode des Leerzeichens vor dem ändern \newcommandund \capitalizemüssten den Catcode des Leerzeichens ändern, bevor Sie dessen Argument übernehmen. (Aus diesem und anderen Gründen würde ich hierfür keine Catcode-Änderung verwenden, sondern einfach ein abgegrenztes Argument, um normale Leerzeichen zu finden.)

\documentclass{article}

\newcommand{\capitalize}[1]{\xcapitalize#1 \relax}
\def\xcapitalize#1 #2{%
#1%
\ifx\relax#2%
\else
\space\MakeUppercase{#2}%
\expandafter\xcapitalize
\fi}

\begin{document}
\capitalize{Hello world and this}
\end{document}

eine in Kommentaren angeforderte Version, die auch den ersten Buchstaben groß schreibt und es zulässt, dass das Argument ein Makro ist:

\documentclass{article}

\newcommand{\capitalize}[1]{\ignorespaces
\expandafter\expandafter\expandafter
\xcapitalize\expandafter\space #1 \relax}
\def\xcapitalize#1 #2{%
#1%
\ifx\relax#2%
\else
\space\MakeUppercase{#2}%
\expandafter\xcapitalize
\fi}

\begin{document}
\capitalize{hello world and this}

\newcommand\zzz{hello world and this}
\capitalize{\zzz}
\end{document}

Antwort2

Diese Lösung erfordert eine aktuelle TeX-Distribution. Sie hat gegenüber dem Ansatz mit den Vorteil \obeyspaces, dass kein Kategoriencode geändert wird, das Makro also auch als Argument für andere Befehle verwendet werden kann.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\capitalize}{m}
 {
  \ruben_capitalize:n { #1 }
 }

\seq_new:N \l__ruben_capitalize_words_seq
\seq_new:N \l__ruben_capitalize_out_seq

\cs_new_protected:Npn \ruben_capitalize:n #1
 {
  \seq_set_split:Nnn \l__ruben_capitalize_words_seq { ~ } { #1 }
  \seq_set_map:NNn \l__ruben_capitalize_out_seq \l__ruben_capitalize_words_seq
   {
    \tl_mixed_case:n { ##1 }
   }
  \seq_use:Nn \l__ruben_capitalize_out_seq { ~ }
 }
\ExplSyntaxOff

\begin{document}
\capitalize{Hello world}
\end{document}

Wenn Sie auch Zeichenfolgen, die als Makro übergeben werden, groß schreiben möchten, ändern Sie die Definition von \capitalizein

\NewDocumentCommand{\capitalize}{m}
 {
  \ruben_capitalize:o { #1 }
 }

und füge hinzu

\cs_generate_variant:Nn \ruben_capitalize:n { o }

nach der Definition von \ruben_capitalize:n(d. h. direkt davor \ExplSyntaxOff).

Vollständiges Beispiel:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\capitalize}{m}
 {
  \ruben_capitalize:o { #1 }
 }

\seq_new:N \l__ruben_capitalize_words_seq
\seq_new:N \l__ruben_capitalize_out_seq

\cs_new_protected:Npn \ruben_capitalize:n #1
 {
  \seq_set_split:Nnn \l__ruben_capitalize_words_seq { ~ } { #1 }
  \seq_set_map:NNn \l__ruben_capitalize_out_seq \l__ruben_capitalize_words_seq
   {
    \tl_mixed_case:n { ##1 }
   }
  \seq_use:Nn \l__ruben_capitalize_out_seq { ~ }
 }
\cs_generate_variant:Nn \ruben_capitalize:n { o }
\ExplSyntaxOff

\newcommand{\myhello}{hello world}

\begin{document}
\capitalize{Hello world}

\capitalize{hello world}

\capitalize{\myhello}

\capitalize\myhello
\end{document}

Bildbeschreibung hier eingeben


Der klassische Ansatz \obeylineserfordert, dass Sie es ausgebenVordas Argument aufnehmen:

% First setup obeyspace and give a meaning to active space
\newcommand{\capitalize}{\begingroup\obeyspaces\setupcapspace\docapitalize}
% Just absorb the argument and end the group
\newcommand{\docapitalize}[1]{#1\endgroup}
% Define (locally) the behavior of active space
\begingroup\lccode`~=`\ % <--- don't forget this one
  \lowercase{\endgroup\newcommand\setupcapspace{\def~{\space\MakeUppercase}}}

Die letzten beiden Zeilen können auch

{\obeyspaces\gdef\setupcapspace{\def {\space\MakeUppercase}}}

Der \lowercaseAnsatz vermeidet jedoch \obeyspacesmögliche Probleme mit unechten Leerzeichen.

Ein Ansatz mit abgegrenzten Argumenten ist jedoch sicherlich besser, da er es ermöglicht, \capitalizeim Argument auf andere Befehle zuzugreifen.

Antwort3

Eine LuaLaTeX-basierte Lösung. Wir definieren ein neues Makro namens \capitalize, das die Lua-Funktionen string.upperund verwendet tex.sprint. Das Argument von \capitalizekann entweder ein fest codierter String oder ein Makro sein, das vermutlich einen String generiert.

Bildbeschreibung hier eingeben

% !TEX TS-program = lualatex
\documentclass{article}
{\catcode\%=12 
 \gdef\capitalize#1{
   \directlua{ str="#1"; 
               tex.sprint ( string.gsub(" "..str, "%W%l",
                string.upper):sub(2)) } }
} 
\begin{document}

\capitalize{Once upon a time there was a princess
  who lived in a great palace that was close to the 
  edge of a dark and mysterious forest.}
\end{document}

Antwort4

Während Ihre Frage sich auf verschachtelte \def,s bezieht, schreibt die Anwendung Wörter groß. Das titlecapsPaket macht das mit dem \titlecapMakro. Es ermöglicht große Flexibilität im Argument, einschließlich Änderungen von Schriftart und -größe. Sie können damit auch Ausschlusswörter festlegen, die nicht großgeschrieben werden (außer optional als erstes Wort des Arguments). Es kann bei der Großschreibung von Wörtern usw. führende Satzzeichen (wie Klammern und Klammern) weitgehend überspringen. Es kann diakritische Zeichen usw. großschreiben.

Im MWE zeige ich Ihr „Hallo Welt“-Beispiel und verwende dann das übertriebene Beispiel aus der Paketdokumentation.

\documentclass{article}
\usepackage{titlecaps}
\def\bs{$\backslash$}

\begin{document}
\titlecap{hello world}

\Addlcwords{for a is but and with of in as the etc on to if}
\titlecap{% 
to know that none of the words typed in this paragraph were initially
upper cased might be of interest to you.  it is done to demonstrate the
behavioral features of this package.  first, you should know the words
that i have pre-designated as lower case.  they are:  ``for a is but and
with of in as the etc on to if.''  you can define your own list.  note
that punctuation, like the period following the word ``if'' did not mess
up the search for lower case (nor did the quotation marks just now).
punctuation which is screened out of the lower-cased word search pattern
include . , : ; ( ) [ ] ? ! ` ' however, I cannot screen text braces;
\{for example in\} is titled, versus (for example in), since the braces
are not screened out in the search for pre-designated lower-case words
like for and in.  However, \texttt{\bs textnc} provides a workaround:
\{\textnc{for example in}\}.  titlecap will consider capitalizing
following a (, [, \{, or - symbol, such as (abc-def).  you can use your
text\textit{\relax xx} commands, like i just did here with the prior xx,
but if you want the argument of that command to not be titled, you
either need, in this example, to add \textit{xx} to the lowercase word
list, which you can see i did not.  instead, i put ``\bs relax~xx'' as
the argument, so that, in essence, the \bs relax was capitalized, not
the x.  Or you could use \texttt{\bs textnc} .  here i demonstrate that
text boldface, \textbf{as in the \bs textbf command}, also works fine,
as do \texttt{texttt}, \textsl{textsl}, \textsc{textsc},
\textsf{textsf}, \textit{etc}.  titlecap will work on diacritical marks,
such as \"apfel, \c cacao \textit{etc.}, \scriptsize fontsize \LARGE
changing commands\normalsize\unskip, as well as national symbols such as
\o laf, \ae gis, and \oe dipus.  unfortunately, i could not get it to
work on the \aa~nor the \l~symbols. the method will work with some
things in math mode, capitalizing symbols if there is a leading space,
$x^2$ can become $ x^2$, and it can process but it will not capitalize
the greek symbols, such as $\alpha$, and will choke on most macros, if
they are not direct character expansions.  Additionally,
\textsf{titlecaps} also works with font changing declarations, for
example, \bs itshape\bs sffamily. \itshape\sffamily you can see that it
works fine.  likewise, any subsequent \bs textxx command will, upon
completion, return the font to its prior state, such as this
\textbf{textbf of some text}.  you can see that i have returned to the
prior font, which was italic sans-serif. now I will return to upright
roman\upshape\rmfamily.  a condition that will not behave well is inner
braces, such as \ttfamily \bs titlecap\{blah \{inner brace material\}
blah-blah\}. \rmfamily see the section on quirks and limitations for a
workaround involving \texttt{\bs textnc}.  titlecap will always
capitalize the first word of the argument (\textbf{even if it is on the
lower-case word list}), unless \texttt{\bs titlecap} is invoked with an
optional argument that is anything other than a capital p.  in that case,
the first word will be titled \textit{unless} it is on the lowercase
word list.  for example, i will do a \bs titlecap[\relax s]\{\relax
a~big~man\} and get ``\titlecap[s]\textnc{a big man}'' with the ``a''
not titled.  i hope this package is useful to you, but as far as using
\textsf{titlecaps} on such large paragraphs\ldots \textbf{do not try
this at home!}}
\end{document}

Bildbeschreibung hier eingeben

verwandte Informationen