ネストされた \def により \inaccessible エラーが発生します

ネストされた \def により \inaccessible エラーが発生します

私は、少なくとも私にとっては非常に簡単な方法で単語を大文字にしてみました。

\documentclass{article}

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

言うまでもなく、私はこれを次のようなマクロにラップしようとしました。

\documentclass{article}

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

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

これにより、TeX は内部の構文についてエラーを出し\def、 になります\inaccessible

一体何が問題なのでしょうか?また、これを回避する方法はあるのでしょうか?

答え1

\verbこれは議論の問題では普通に機能しないものです。

\obeyspacesスペースのcatcodeを変更します。つまり、スペースキャラクターファイルアクティブトークンに変換されます。catcodeの変更によりいいえすでに作成されたトークンには影響しません。あなたの場合、 の引数全体がトークン化されているため、の\newcommand後にスペース トークンはまったく存在しません。\def\def{

の前のスペースの catcode を変更する必要があり\newcommand\capitalize引数を取る前にスペースの catcode を変更する必要があります。(このため、および他の理由から、私はこれに catcode の変更を使用せず、代わりに通常のスペースを見つけるために単に区切られた引数を使用します)

\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}

コメントでリクエストされたバージョンでは、最初の文字も大文字になり、引数をマクロにすることができます。

\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}

答え2

このソリューションには、最近更新された TeX ディストリビューションが必要です。 を使用するアプローチに比べて\obeyspaces、カテゴリ コードが変更されないため、マクロを他のコマンドの引数に指定できるという利点があります。

\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}

マクロとして渡される文字列も大文字にしたい場合は、の定義を\capitalize次のように変更します。

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

そして追加する

\cs_generate_variant:Nn \ruben_capitalize:n { o }

の定義の後\ruben_capitalize:n(つまり、 の直前\ExplSyntaxOff)。

完全な例:

\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}

ここに画像の説明を入力してください


古典的なアプローチでは、\obeylinesそれを発行する必要があります前に議論を吸収する:

% 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}}}

最後の2行は

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

しかし、この\lowercaseアプローチは\obeyspaces、疑似空間による潜在的な問題を回避します。

\capitalizeただし、他のコマンドの引数に含めることができるため、区切られた引数を使用するアプローチの方が確実に優れています。

答え3

LuaLaTeX ベースのソリューション。Lua\capitalize関数string.upperとを使用する という新しいマクロを定義しますtex.sprint。 の引数は、\capitalizeハードコードされた文字列、またはおそらく文字列を生成するマクロのいずれかになります。

ここに画像の説明を入力してください

% !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}

答え4

質問はネストされた\def, に関するものですが、アプリケーションは単語を大文字にします。titlecapsパッケージはマクロを使用してこれを行います\titlecap。これにより、フォント スタイルやサイズの変更など、引数に幅広い柔軟性を持たせることができます。また、大文字にしない除外単語を設定することもできます (オプションで引数の最初の単語を除く)。単語を大文字にするときに、先頭の句読点 (括弧や角括弧など) の影響をかなり軽減できます。発音区別符号などを大文字にできます。

MWE では、「hello world」の例を示し、パッケージのドキュメントから過剰なサンプルを採用します。

\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}

ここに画像の説明を入力してください

関連情報