Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tabular 内のJFMグルーの入り方 #43

Closed
doraTeX opened this Issue Apr 6, 2017 · 28 comments

Comments

Projects
None yet
4 participants
@doraTeX
Copy link
Member

doraTeX commented Apr 6, 2017

(u)pLaTeXでの

\begin{tabular}{|c|}
(ほげ)
\end{tabular}

の組版結果は

2017-04-06 15 44 57

となり,中央からずれて見えます。

一方,同じソースを LuaTeX-ja で処理すると

2017-04-06 15 43 47

となり,きちんと中央に揃って見えます。

可能ならば LuaTeX-ja 方式に統一した方が,おそらく意図通りで望ましい結果になるかと思います。(ただし,LuaTeX-ja 方式に変更すると横方向に伸びますので,既存の書類への影響が大きそうです。)

@h-kitagawa

This comment has been minimized.

Copy link
Member

h-kitagawa commented Apr 6, 2017

LuaTeX-ja で特別なことをやっているという意識はありません.
中央に揃って見えるのは,LuaTeX-ja では

\hskip1sp\ignorespaces\@sharp\unskip\hfil

中の \unskip によって JFM グルーを消すことができない(一回 \hbox を組んで,それを \unhbox しない限り)ことによるのでしょう.

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Apr 6, 2017

pLaTeX の結果は確かに期待とは違うので気になりますね。\@tabclassz のなかの \@preamble で \unskip の前に \null でも仕込めば JFM グルーが消えなくなって揃うのかな,と思いますが,影響としてはどうなのでしょう? → どちらかというと JFM を消すほうが期待に添う気がしてきました…

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Apr 6, 2017

しかし,JFM グルーが片側だけに入る

アレ。

のような要素の場合を考えると,むしろグルーを消す方がよいという意見にもなりますね。(つまり pLaTeX の末尾はこのままで,先頭のグルーを削除する必要がある)

@doraTeX

This comment has been minimized.

Copy link
Member Author

doraTeX commented Apr 6, 2017

確かに,JFMグルーを両方消すのが最も期待に添っている気がします。
自分はこの手の状況においては,いつも

\mbox{(ほげ)}

としてJFMグルーを消してました。

@kbhonda

This comment has been minimized.

Copy link

kbhonda commented Apr 8, 2017

段落の先頭の開きかっこ類と同じだろうということで
基本的には \< を入れて対処しています.
(ほげ)単独のセルでは4字幅3字幅になってほしいです.(修正しました)

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Apr 8, 2017

(ほげ)単独のセルでは4字幅になってほしいです.

明確にさせてください。これはセルの幅,すなわち罫線と罫線の間隔が 4zw という意味でしょうか? それとも "あいうえ" 等の4字が入ったセルと "(ほげ)" が入ったセルが揃うという意味でしょうか?

@kbhonda

This comment has been minimized.

Copy link

kbhonda commented Apr 9, 2017

あっ!4字じゃない,3字だ・・
無茶苦茶になってます.すみません.
\<いれるんだから3字です.

罫線<tabcolsep由来のあき>(ほげ)<tabcolsep由来のあき>罫線
「(ほげ)」は3文字幅
(=.5zw,ほげ=2zw,)=.5zw

こう書けば誤解はないですか?
「あいう」と「(ほげ)」が縦に並んだときはそろってほしいということです.

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Apr 9, 2017

明快な説明をありがとうございます.助かります.

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented May 9, 2017

JFMグルーを両方消すのが最も期待に添っている気がします。

中間報告です。テストケースとして

\documentclass{article}
\begin{document}

% テスト
\begin{tabular}{|c|c|c|}
(ほげ) & (ほげ) & (ほげ)
\end{tabular}

% 比較用(\mbox に入れるとグルーが両方とも消える)
\begin{tabular}{|c|c|c|}
\mbox{(ほげ)} & \mbox{(ほげ)} & \mbox{(ほげ)}
\end{tabular}

\end{document}

のようなものを作って,pLaTeX で走らせてみました(c のところは l や r に変えてもよい)。すると,「前のグルー」は全てのセルで入っており,「後ろのグルー」は同一行内の最後のセルだけ消滅し,それ以外のセルには入っていることに気づきました。挙動に統一性がないので気になりますね。

「前のグルー」を消すのは比較的簡単で

\def\@tabclassz{%
  \ifcase\@lastchclass
    \@acolampacol
  \or
    \@ampacol
  \or
  \or
  \or
    \@addamp
  \or
    \@acolampacol
  \or
    \@firstampfalse\@acol
  \fi
  \edef\@preamble{%
    \@preamble{%
      \ifcase\@chnum
        \hfil\inhibitglue\ignorespaces\@sharp\unskip\hfil % c
      \or
        \hskip1sp\inhibitglue\ignorespaces\@sharp\unskip\hfil % l
      \or
        \hfil\hskip1sp\inhibitglue\ignorespaces\@sharp\unskip % r
      \fi}}}

のように \inhibitglue を入れればよいのですが,「後ろのグルー」はまだわかりません。

@kbhonda

This comment has been minimized.

Copy link

kbhonda commented Jun 15, 2017

見逃してました.

挙動に統一性がないので気になりますね。

&の前後にある空白が作用しています.

r,c,lの場合セル内での改行はない(中に\parboxとかをいれるのは別として)のと
\mboxでアドホックに処理できるのでいっそ\mboxを入れ込むというのはどうでしょう.
ひとまずたたき台です.

\documentclass{article}
%\iffalse
\makeatletter
\def\@tabclassz{%
  \ifcase\@lastchclass
    \@acolampacol
  \or
    \@ampacol
  \or
  \or
  \or
    \@addamp
  \or
    \@acolampacol
  \or
    \@firstampfalse\@acol
  \fi
  \edef\@preamble{%
    \@preamble{%
      \ifcase\@chnum
        \hfil\mbox{\ignorespaces\@sharp\unskip}\hfil % c
      \or
        \hskip1sp\mbox{\ignorespaces\@sharp\unskip}\hfil % l
      \or
        \hfil\hskip1sp\mbox{\inhibitglue\ignorespaces\@sharp\unskip}% r
      \fi}}}
\makeatother
%\fi
%\usepackage{array}
\begin{document}

% テスト %% &の前後に空白なし
\begin{tabular}{|c|c|c|}
(ほげ)&(ほげ)&(ほげ)
\end{tabular}

% テスト %% &の前後に空白あり
\begin{tabular}{|c|c|c|}
(ほげ) & (ほげ) & (ほげ)
\end{tabular}

% 比較用(\mbox に入れるとグルーが両方とも消える)
\begin{tabular}{|c|c|c|}
\mbox{(ほげ)}&\mbox{(ほげ)}&\mbox{(ほげ)}
\end{tabular}
\end{document}
@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Jun 15, 2017

&の前後にある空白が作用しています.

なるほど,気づいていませんでした。ありがとうございます。

r,c,lの場合セル内での改行はない(中に\parboxとかをいれるのは別として)のと
\mboxでアドホックに処理できるのでいっそ\mboxを入れ込むというのはどうでしょう.

いいと思います。plext を使った場合の縦組を含めてもう少しテストしてみます。(手元では \inhibitglue も入れないとまずいっぽい?)

→ kbhonda さんのコードに \inhibitglue を挿入した例を Gist に置いてみました。 【ファイル削除】

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Jun 15, 2017

\usepackage{array}

な場合は,これよりも後に

\makeatletter
\def\insert@column{%
   \the@toks \the \@tempcnta
   \mbox{\inhibitglue \ignorespaces \@sharp \unskip}%
   \the@toks \the \count@ \relax}
\makeatother

を書けば ok でした。 → と思ったら

  \begin{tabular}{|>{$}c<{$}|c|}\hline
    \exp(x) & 指数関数 \\ \hline
    \log(x) & 対数関数 \\ \hline
  \end{tabular}

がダメですね。

私が管理している https://github.com/aminophen/platex-tools に「plextarray.sty」という「plext.sty と array.sty を共存させるパッケージ」があるので,これと同じ要領で「parray.sty plarray.sty」というのを作って提供すればよいでしょうか。そうすれば「pLaTeX / upLaTeX で array.sty を使うときは,parray.sty plarray.sty を読み込む」という仕様にできますし。

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Jun 15, 2017

759bbf3 で exppl2e.sty に \@tabclassz を入れました。

% \section{tabular環境のセル内のJFMグル―}
%
% \begin{macro}{\@tabclassz}
% \LaTeX{}カーネルは、アラインメント文字|&|の周囲に半角空白を書いたかどうかに
% かかわらず余分なスペースを出力しないように、|\ignorespaces|と|\unskip|を
% 発行しています(lttab.dtx)。しかし、これだけではJFMグルーが消えずに残ります。
% そこで、セルの中身を|\mbox|に入れ、さらに最初に|\inhibitglue|を発行する
% ことで、セル要素の周囲のJFMグル―を消します。
% \changes{v???}{????/??/??}{tabular環境のセル内のJFMグル―を削除}
@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Jun 15, 2017

array.sty の場合は,安直には

\def\insert@column{%
   \the@toks \the \@tempcnta
\ifmmode
   \mbox{}\inhibitglue \ignorespaces \@sharp \unskip
\else
   \mbox{\inhibitglue \ignorespaces \@sharp \unskip}%
\fi
   \the@toks \the \count@ \relax}

で動いていますが… まだ不安が残ります。

@kbhonda

This comment has been minimized.

Copy link

kbhonda commented Jun 15, 2017

検証&修正ありがとうございます.
\inhibitglueの有無がとっちらかってました.
まだちょっと怖いですね.週末にでも
exppl2e.styをTL2017で動かしてみます.

@kbhonda

This comment has been minimized.

Copy link

kbhonda commented Jun 25, 2017

遅れてしまいました.

以下,array packageは考えてません.
また,欧文のみの場合も考慮してませんが
本質的には\inhibitglueと\mbox{}と\unskipをセルの最初か最後に入れるだけなので
まあ,和文のみでいいのではないかと仮定しています.

TL2017

This is e-pTeX, Version 3.14159265-p3.7.1-161114-2.6 (utf8.sjis) (TeX Live 2017/W32TeX) 
(preloaded format=platex 2017.6.12) 

で,動かしています.

以下のようなサンプルで@tabclasszの変更を入れたりしてましたが
\mboxの最初の\inhibitglueはなしでも問題ないように思えます.
この修正で組版結果は従来とは変わりますが
tabularのrclは主観的には自然になると思います.

修正前の状態だと
セルの最後に「)」だけのときと
「)+半角空白」の場合に挙動の変化がありますが,
修正を施せば,セルの最後が
「文字+半角空白」の場合は,単に「文字」だけのときと同じで
空白の有無は関係なくなっているようです.
\unskipが作用してくれています.
セルの最後が「句読点」「句読点+半角空白」でも修正前は差がでますけど
修正後は同じになります.
#「文字」というのはjfmのcharsintypeの0のかもしれませんが,
#整理できていません.

この動作はjsでも同じです,

こういう意味で「主観的には自然」といっています.

ただ気になるのは,pの動作です.
pLaTeX2eの@classvとLaTeX2eの@classvが違ってませんか?
どこで処置しているか追い切れなかったので,
\meaningで@classvをのぞいてみると,pLaTeX2eでは

\def\@classv{\@addtopreamble {\@startpbox {\@nextchar}\ignorespaces\@sharp\@endpbox}}

のようですが,LaTeX2eだと

\def\@classv{\@addtopreamble{\@startpbox{\@nextchar}\ignorespaces\@sharp\unskip\@endpbox}}

@sharpのあとに\unskipが入ってます.\unskipがないと
やはりセルの最後に半角空白があると,pのときに空白行が発生することがあります.
加えてpのときの先頭および末尾の全角パーレンの挙動も
rclとそろえる必要があると思います.
そこで@classv

\def\@classv{\@addtopreamble{\@startpbox{\@nextchar}\mbox{}\inhibitglue\@sharp\unskip\@endpbox}}

としてみると,期待通り(セルの先頭・末尾の全角パーレンが.5zwになるという意味)に
なりそうです.

\documentclass{jarticle}

\begin{document}

\begin{tabular}{|c|c|c|}
ああ)&(あ&(あ)\\
ああ) & (あ & (あ) \\
\end{tabular}

\vskip.5\baselineskip

\begin{tabular}{|r|r|r|}
ああ)&(あ&(あ)\\
ああ) & (あ & (あ) \\
\end{tabular}

\vskip.5\baselineskip

\begin{tabular}{|l|l|l|}
ああ)&(あ&(あ)\\
ああ) & (あ&(あ)\\
\end{tabular}

\vskip.5\baselineskip

\begin{tabular}{|p{2zw}|p{2zw}|p{2.5zw}|}
あ)\<&\<(あ&\<(あ)\<\\
あ)&(あ&(あ) \\ %% )と\\の間に半角空白がある
\end{tabular}

\end{document}
@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Jun 25, 2017

ただ気になるのは,pの動作です.
pLaTeX2eの\@classv とLaTeX2eの \@classv が違ってませんか?

\@classv は変えていないはずと思ったので LaTeX2e (source2e) を見に行きましたが,LaTeX2e のほうでも \unskip は入っていませんでした。latexrelease パッケージもざっと見ましたが,当該コードは含まれていませんでした。あれっ? どこから入手された LaTeX2e でしょうか?

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Jun 25, 2017

\inhibitglue は

\documentclass{tarticle}
\begin{document}

\begin{tabular}{|c|}
(ほげ)
\end{tabular}

\end{document}

の場合,つまり「縦組でかつ(lcr によらず)表の行内で最初の要素が開きカッコ類の場合」に必要です。\inhibitglue がないと,JFM グルーが入ってしまうようです。

@kbhonda

This comment has been minimized.

Copy link

kbhonda commented Jun 26, 2017

申し訳ないです.
@classvのオリジナルは\unskipないです
pの動作を追いかけているうちになんか勘違いしたようです.
ただ,実際のところ\unskipは入ってほしい気がします.

つまり「縦組でかつ(lcr によらず)表の行内で最初の要素が開きカッコ類の場合」

そうなんですね,縦は考慮してませんでした.理解しました.

@aminophen aminophen added bug and removed enhancement labels Jun 26, 2017

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Jun 26, 2017

実際のところ\unskipは入ってほしい

挙動を見るに,lcr の時・p のとき共に,enhancement ではなく bug だと感じました。従って,挙動が変わることを気にせず「直して然るべき」ものである,と考えています。

というのも,LaTeX2e は lcr の時に「& の前後の半角空白によって出力が変わらないように,\ignorespaces と \unskip で挟む」という処置が入っているわけなので,pLaTeX で文字集合が増えた場合にもこの「半角空白によって出力が変わらないように」は維持すべきですし,p のときは明らかに意図しない空白行が発生するからです。少なくとも私は LaTeX2e を見た時には \ignorespaces の意義に気づいていなかったので,半角空白の違いを指摘して下さった kbhonda さんに感謝です。

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Jun 26, 2017

b56fd44 でテストケースだけ増やしておきました。今まで出た問題な挙動は網羅しているつもりです。なお,\@classv を具体的にどのコードにするかはまだ考えていません。もしも欧文の場合にも \unskip がないことが不可解な挙動を示すようなら,本家にもレポートした方がいいことになりますし。

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Jul 3, 2017

7604c5d で exppl2e.sty に \@classv を入れました。

\def\@classv{\@addtopreamble{\@startpbox{\@nextchar}\mbox{}\inhibitglue\ignorespaces
\@sharp\unskip\@endpbox}}

LaTeX2e に比べると \mbox{}\inhibitglue\unskip を追加したことになります。array パッケージの検討はまだですし、欧文だけの場合の検討もまだですが、とりあえず。

@kbhonda

This comment has been minimized.

Copy link

kbhonda commented Jul 15, 2017

亀な応答で申し訳ないです.
どうにも気になる挙動があります.

半角空白によって出力が変わらないように

このことなんです.
「コードにおける行の末尾にある半角空白」が
「(内部限定)垂直モードの末尾」にあったらどうなる
かです.
その空白が水平モード内なら問題ないでしょうが,垂直モードの最後だったら?
その直前の文字が「閉じかっこ」のように直後のものによっては
tfmもしくはjfmに由来するアキの類を後ろに出すものなら?

\documentclass{jarticle}

%\expandafter\let\csname JY1/mc/m/n/10\endcsname\relax
%\DeclareFontShape{JY1}{mc}{m}{n}{<-> s*jis}{}

\begin{document}
\parindent0pt
\fbox{\vbox{\hsize1.5zw あ)}}\par
\fbox{\vbox{\hsize1.5zw あ) }}%%%これ

\fbox{\vbox{\hsize1.5zw あ.}}\par
\fbox{\vbox{\hsize1.5zw あ. }}%%%これ

\fbox{\vbox{\hsize1zw あ}}\par
\fbox{\vbox{\hsize1zw あ }}%%%半角消える

\setbox0=\hbox{mm}
\fbox{\vbox{\hsize\wd0\relax mm}}\par
\fbox{\vbox{\hsize\wd0\relax mm }}%%%欧文でも消える

\end{document}

少なくともpの挙動に関しては,このサンプルと同じものかもしれません.
コメント内で「これ」と書いた部分がすっきりしません.
jisかmin10でも挙動が違います.
\usepackage{otf}はjisと同じで.
\fboxで明示するためにLaTeXの書式で書いてますが,
plainでも同じようです.

@h-kitagawa

This comment has been minimized.

Copy link
Member

h-kitagawa commented Jul 15, 2017

\fbox{\vbox{\hsize1.5zw あ) }}%%%これ
jis の場合でも,\showlists で調べてみると

\hbox(7.77588+1.38855)x28.86649, glue set 9.6222fil
.\hbox(0.0+0.0)x0.0
.\JY1/mc/m/n/10 あ
.\penalty 10000(for kinsoku)
.\glue(\kanjiskip) 0.0 plus 0.4 minus 0.5
.\JY1/mc/m/n/10 )
.\glue(refer from jfm) 4.81107 minus 4.81107
.\penalty 10000
.\glue(\parfillskip) 0.0 plus 1.0fil
.\glue(\rightskip) 0.0
prevdepth 1.38855, prevgraf 1 line

と,段落最後の「)」とその後の半角空白の間の JFM グルーが消えずに残っています.

これは TeX82 の行分割処理の最初で行われる「最後に \parfillskip を加える」処理が

@<Get ready to start...@>=
link(temp_head):=link(head);
if is_char_node(tail) then tail_append(new_penalty(inf_penalty))
else if type(tail)<>glue_node then tail_append(new_penalty(inf_penalty))
else  begin type(tail):=penalty_node; delete_glue_ref(glue_ptr(tail));
  flush_node_list(leader_ptr(tail)); penalty(tail):=inf_penalty;
  end;

と,「最後のノードが glue ならば,それを \parfillskip に置き換える」という実装になっているためです.ただ,安直に「末尾にある glue の連続」を削除する処理に置き換えるのは TeX82 との互換性をなくすだけなので私は反対です.

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Jul 17, 2017

pTeX の挙動はさておき,本題の tabular の JFM グルーの修正を今月中に exppl2e からカーネルに移し, pLaTeX および upLaTeX をリリースする予定です。array と共存した場合のことも考え,私の platex-tools もこれらと同時にリリースすることにします。問題が起きそうな例を発見されましたら,お早めにお願いします。

@kbhonda

This comment has been minimized.

Copy link

kbhonda commented Jul 19, 2017

本題の tabular の JFM グルーの修正

縦で問題が起きないようなら大丈夫だと思います.

@kbhonda

This comment has been minimized.

Copy link

kbhonda commented Jul 19, 2017

h-kitagawaさん:
段落の最後のグルーおよび\parfillskipの入り方の仕様は理解しました
極端な話
\vbox{a\hskip10pt\hskip20pt}
みたいな場合\hskip10ptが残るんですね.

ptexの場合,「和文文字+半角空白+改行の場合には半角空白は消える」
のが適用されてから(これは最初の読み込み,TeXのいわゆる「口」でしょうか)
行分割が始まるということですよね.それだから

\vbox{あ) }%%%閉じ全角パーレンのあとに半角空白

\vbox{あ) 
}%%%閉じ全角パーレンのあとに半角空白,改行

の結果は異なると理解します.前者は)+半角空白によりjfmのグルーが入り,
半角空白は\parfillskipの処理で削除され,
後者は和文+空白+改行で半角空白と改行が消えて,jfmのグルーが入らない

普通はこんな(段落終わりに空白がある)変なコードをを書くことはない
(表は見やすくするためにセルの最初や最後に空白があることはよくある)
と思うので,問題はないと思います

ただ「半角空白」がなんで生き残るのが気になったのですが,理解しました.
ありがとうございました.

@aminophen

This comment has been minimized.

Copy link
Member

aminophen commented Jul 29, 2017

予定どおり,pLaTeX と upLaTeX 2017/07/29 版をリリースしました。platex-tools の plarray.sty もアップロードしました。今は CTAN に反映されるのを待っているところです。

現時点では close しますので,問題が発生しましたら再度 open してください。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.