\span コマンドとは何ですか?

\span コマンドとは何ですか?

\spanプリミティブに何度か遭遇しました。TeXプログラムで定義されているという印象を受けましたが、 でもありませんplain.tex。それは正しいですか?そして、するそのコマンドは何を実行し、何のために使用するのでしょうか?

答え1

プリミティブは、\span本文の前文に現れる場合\halignと本文に現れる場合とで、2 つの非常に異なる意味を持ちます。

これがプリアンブル、つまり最初のトークンの前にある場合は\cr、後続のトークンを「展開する」ことを意味します。これが本体にある場合は、現在のセルを終了し、後続のセルと結合します。この場合、通常は と組み合わせて使用​​されます\omit

最も簡単な例は

\halign{\hfil#\tabskip1em&#\hfil\cr
  a&b\cr
  c\span d\cr
}

2行目にはセルが1つだけあります。出力は次のようになります。

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

2 行目は前後の内容\tabskipを含む 1 つのセルだけなので、「c」と「d」の間にはスペースがありませんが、TeX はセルの幅を決定する際にこれを考慮します。\hfil\tabskip

しかし、通常は\omitあなたそして部品(あなた前にあるものを指します#それに続くものへ。

TeX が のプリアンブルを読み込むとき、\halignが見つからない限りトークンを展開しません\tabskip(適切なグルー仕様を見つけるためにトークンを展開するとき)。 を前に付けると、トークンの展開を強制できます\span

一例としてはamsmath.sty

\def\align@#1#2{%
    \inalign@true \intertext@ \Let@ \chardef\dspbrk@context\z@
    \ifingather@\else\displ@y@\fi
    \let\math@cr@@@\math@cr@@@align
    \ifxxat@\else \let\tag\tag@in@align \fi
    \let\label\label@in@display
    #1% set st@r
    \ifst@rred\else \global\@eqnswtrue \fi
    \measure@{#2}%
    \global\row@\z@
    \tabskip\eqnshift@
    \halign\bgroup
        \span\align@preamble\crcr
        #2%
}

これは、および関連で使用されるヘルパーマクロですalign。プリアンブルはマクロ内で一度だけ定義されます。\align@preamble

\def\align@preamble{%
   &\hfil
    \strut@
    \setboxz@h{\@lign$\m@th\displaystyle{##}$}%
    \ifmeasuring@\savefieldlength@\fi
    \set@field
    \tabskip\z@skip
   &\setboxz@h{\@lign$\m@th\displaystyle{{}##}$}%
    \ifmeasuring@\savefieldlength@\fi
    \set@field
    \hfil
    \tabskip\alignsep@
}

\align@これにより、マクロに大量のコードを配置することで、の定義が大幅に簡素化されます。また、alignを変更することでの挙動を変更することもできます\align@preamble奇数列に暗黙的にプレフィックス {} を付けることは可能ですか?)。

LaTeX カーネルは、文字tabularの組み合わせなど、その規則に従ってプリアンブルを構築する必要があるため、に対して異なる方法を使用しますlcrp

の2番目の用途は、\span列を結合することです\halign。Plain TeXでは、\multispan

\def\multispan#1{\omit \mscount#1\relax
  \loop\ifnum\mscount>\@ne \sp@n\repeat}
\def\sp@n{\span\omit\advance\mscount\m@ne}

は、引数に指定された\omit数(マイナス1)のペアを追加します。つまり、は、、、などと同じです。LaTeXのマクロも同じアイデアに基づいています。\span\omit\multispan{1}\omit\multispan{2}\omit\span\omit\multicolumn

% latex.ltx, line 5053:
\long\def\multicolumn#1#2#3{\multispan{#1}\begingroup
  \@mkpream{#2}%
  \def\@sharp{#3}\set@typeset@protect
  \let\@startpbox\@@startpbox\let\@endpbox\@@endpbox
  \@arstrut \@preamble\hbox{}\endgroup\ignorespaces}

まず最初に(Plain とまったく同じように定義されます)、 およびで使用されるものと\multispan{#1}同じものを使用して「ローカル」アライメント プリアンブルを構築し、必須の引数を評価します。\@mkpreamtabulararray

なぜ Knuth は 2 つのまったく異なる意味に同じプリミティブを使用したのでしょうか。スペースを節約するためです。TeX はコンピュータのメモリ スペースが少ないときに書かれたもので、定義を節約することが重要でした。 は(または、もちろん )\spanでのみ出現できるため、問題にはなりません。\halign\valign

最初の意味での の誤った使用法は、\spanTeXbookの演習20.16の解答に現れている。

以下のことはあまり真剣に受け止めるべきではありませんが、確かに効果があります。

{\setbox0=\vbox{\halign{#{\c\span\d}\cr
       \let\next=0\edef\next#1{\gdef\next{\b#1}}\next\cr}}}
 \let\a=\next

この演習では\a、 を\b(完全に展開) に続いて\c(展開されていない) と\d(一度だけ展開)を、\noexpandと を使わずに定義する\the。例えば、

\def\foo{xy\baz}
\def\baz{z}
\def\b{\foo\foo}
\def\c{--}
\def\d{\baz}

\a置換テキストとして定義したいのは

xyzxyz\c\baz

部分は出力なしで\setbox0=\vbox{単に使用するだけです。TeXはプリアンブルを と評価します。これは の1レベル展開を引き起こすためです。セルには以下が含まれます。\halign\halign#{\c\baz}\cr\span\d

\let\next=0\edef\next#1{\gdef\next{\b#1}}\next

規則によれば、#プリアンブルの の代わりに が使用され、入力ストリームは

\let\next=0\edef\next#1{\gdef\next{\b#1}}\next{\c\baz}\cr

\crセルを終了させるだけなので、関係ありません。 のため\let\next=0\nextは展開不可能になり、 が定義されるように\edefなります。\next

\def\next#1{\gdef\next{<full expansion of \b>#1}}

そして\next{\c\baz}忠実に実行する

\gdef\next{<full expansion of \b>\c\baz}

そして最後が\let\a=\nextすべてを終わらせます。

これは\span1つ拡大のステップ。


\noexpande-TeX(結局、と は使用しない\the)での別の解決策は次のようになります。

\edef\a{\b\unexpanded\expandafter{\expandafter\c\d}}

関連情報