Closed RadioNoiseE closed 11 months ago
以简中句号为例,主要就是两种思路:
\hbox to0.5em{。\hss}
,印象中babel
的韩文支持就是这么做的;。\vrule width-0.5em\relax
,是xeCJK
的做法。没有「绝对正确」的做法,看你想在「horizontal list」里是加个盒子呢还是留字符本身,只要注意em
是否跟汉字大小一致即可。我没试过第1种思路,但知道第2种思路可以结合rule、glue、penalty花式玩法做出「标点悬挂」的效果。
应该用\hskip0.5em minus 0.5em
(那个plus ...
就匪夷所思了)。
\discretionary
是「完全错误」的思路:在显式的「discretionary node」处断行是要罚\hyphenpenalty
的。正确的思路应该是在铅空\hskip
处的「glue node」断行,不罚penalty。
\xdef\punct@before{...}
两个标点可能都已经隔了十万八千里了,如。字字字字「
,还要走一遍\ifin@
和\unskip
,怕是不妥吧?
应该用
\hskip0.5em minus 0.5em
(那个plus...
就匪夷所思了)。
呃的确是,大概我写这里的时候没太用脑子(
不过似乎不太该全部挤压、我JFM设的是.25em
(的确、.015
太小了)
是「完全错误」的思路:在显式的「discretionary node」处断行是要罚
\hyphenpenalty
的。正确的思路应该是在铅空\hskip
处的「glue node」断行,不罚penalty。
我再去仔细看看TeXbook(地铁上拍脑袋想的、怕是背单词背傻了
两个标点可能都已经隔了十万八千里了,如
。字字字字「
,还要走一遍\ifin@
和\unskip
,怕是不妥吧?
我也觉得不太好、但当时觉得反正\unskip
没有副作用就放这了。我再想想、比如用\aftergroup
判断、如果是汉字就把它定义为nil
?
而且我看实现,这个clist的判断是用宏的机制、不是一个一个捕获判断、也、不是特别慢(?
\def\in@#1#2%
{%
\begingroup
\def\in@@##1#1{}%
\toks@\expandafter{\in@@#2{}{}#1}%
\edef\in@@{\the\toks@}%
\expandafter\endgroup
\ifx\in@@\@empty
\in@false
\else
\in@true \fi
}
\newif\ifin@
(是我写不出来的
(谢谢您!
不过似乎不太该全部挤压、我JFM设的是
.25em
(的确、.015
太小了)
可能是对minus 0.5em
有误解吧?并不是非得全部挤压,而是「如果此行太长、需要挤压时,最多能把加上的二分铅空全部挤掉」。在实际文档中,需要挤掉二分铅空的0.25em
或以上的场合太罕见了(注意,是同一行的每个标点的铅空都要被耗掉50%或以上的压缩量)。简中排版最常见的「此行过长」基本上就是「多了一个可以行末半宽的避头标点」,总挤压量也就0.5em,要分散到行內数个标点的铅空是绰绰有余的(如果行內还有西文,那西文空格也可以吸收一些总挤压量)。总之,耗掉收缩量0.5em的50%以下是常见情况,TeX评判该行的badness也就介于0到12,属于「decent」,算不上「tight」。
而minus 0.25em
无非大大减少了可压缩的总量,当每个铅空要被耗掉0.125em或以上时,TeX就会把该行归类为「tight」,最后效果是TeX更倾向于「推出」(即拉大此行字距,把过长的内容往下一行放)而不是「挤进」。
嗯,我之前设成.25em
是因为实在不喜欢被挤压成只有只有一个标点宽度的情况。
不过似乎(又)是我TeXbook看的不够仔细了,这么看来还是.5em
看上去合理很多(
另外,我昨天晚上去看了看\discretionary
的描述。发现了在此段行惩罚值是可以通过\hyphenpenalty
以及\exhyphenpenalty
「改变」的。我在想是不是可以在标点定义包一个分组(如\[begin/end]group
)、然后局部改变这两个值使其分别为0
、也就不会影响西文的设置。
至于为什么对这个discretionary node这么执着,因为我觉得用它可以控制TeX在断行时的行为。如繁体中文句号。
后接一个「
号,句号在行末就不该做行末半角而应该保持全宽,如此就需要断行时在其后插入一个.25em
宽的铅空;同时如果不在此处断行后接的应是一个.75em
的铅空。如果不用discretionary node就非常难实现(TeX总是会在第一个glue处断行、因为其后的glue是discardable的?)。同时也能很简单地实现标点悬挂等等。
(大概也能避免某些奇怪的东西跑到下一行去)[迫真]
至于「即使标点相隔汉字也需要走一遍\unskip
」的问题,我还没什么想法(
我去今晚去看看aro-bend,看看能不能找到什么灵感(哪里有什么灵感可言)。
另外,我昨天晚上去看了看
\discretionary
的描述。发现了在此段行惩罚值是可以通过\hyphenpenalty
以及\exhyphenpenalty
「改变」的。我在想是不是可以在标点定义包一个分组(如\[begin/end]group
)、然后局部改变这两个值使其分别为0
、也就不会影响西文的设置。
不可行。TeX是读取整个段落之后再分行的,所以在分组里赋的零值是无效的。段落末尾(\par
之前)的值才是用于整段分行的值。
至于为什么对这个discretionary node这么执着,因为我觉得用它可以控制TeX在断行时的行为。如繁体中文句号
。
后接一个「
号,句号在行末就不该做行末半角而应该保持全宽,如此就需要断行时在其后插入一个.25em
宽的铅空;同时如果不在此处断行后接的应是一个.75em
的铅空。如果不用discretionary node就非常难实现(TeX总是会在第一个glue处断行、因为其后的glue是discardable的?)。同时也能很简单地实现标点悬挂等等。
是的,繁中句号在行末不应该半宽(准确地说是不应该丢掉后面的四分空)。但你去看港台好多Adobe InDesign排的书,那叫惨不忍睹啊。想留很简单,要善用penalty,以字。「字
为例:
字\nobreak \hskip0.25em minus 0.25em \vrule width-0.25em\relax
。\vrule width-0.25em\relax \nobreak \hskip0.25em minus 0.25em \allowbreak
\vrule width-0.5em\relax 「\nobreak 字
不可行。TeX是读取整个段落之后再分行的,所以在分组里赋的零值是无效的。段落末尾(
\par
之前)的值才是用于整段分行的值。
啊、你说的对(
我得再想想(麻烦了
字\nobreak \hskip0.25em minus 0.25em \vrule width-0.25em\relax 。\vrule width-0.25em\relax \nobreak \hskip0.25em minus 0.25em \allowbreak \vrule width-0.5em\relax 「\nobreak 字
我来按我的方法(切的)改一改!
然后想想那个判断的问题怎么解决
啊,我想起来我为啥弃用\hbox to...
的方式切全角了,是因为会改变标点在自然状态(不伸展不压缩)下所占据的宽度。
假设1em
等于1003sp
,以这个不实际的值为例方便说明情况。用\hbox to0.5em{。\hss}
切出来的盒子,宽501sp
,后面再补\hskip0.5em minus 0.5em
自然宽度同样是501sp
,加在一起相当于句号少了1sp宽。繁中式的句号盒子宽501sp
,前后补的四分空各宽250sp
,加在一起相当于句号少了2sp宽。此分析适应于所有除4余3的整数sp汉字尺寸。
相反,用\vrule
去配合\hskip
,能够保证正负刚好抵消,不增添不减少1sp的宽度。
啊,我想起来我为啥弃用
\hbox to...
的方式切全角了,是因为会改变标点在自然状态(不伸展不压缩)下所占据的宽度。假设
1em
等于1003sp
,以这个不实际的值为例方便说明情况。用\hbox to0.5em{。\hss}
切出来的盒子,宽501sp
,后面再补\hskip0.5em minus 0.5em
自然宽度同样是501sp
,加在一起相当于句号少了1sp宽。繁中式的句号盒子宽501sp
,前后补的四分空各宽250sp
,加在一起相当于句号少了2sp宽。此分析适应于所有除4余3的整数sp汉字尺寸。相反,用
\vrule
去配合\hskip
,能够保证正负刚好抵消,不增添不减少1sp的宽度。
(原来这里还有个坑)
话说1sp应该肉眼不可见吧(表达不太严谨),但毕竟有更好的方法。
所以说这个思路想来好像是不太好的,而且我也没想好比较好的方法来判断标点是否紧挨。
还是kern加rule的方法好(
(WRN:这不是个好方法)
因为该issue中
CJKpunct
宏集的实现导致出现了一些小问题,我就想是否能够有另一种实现能够避免这个问题。方法如下,暂时只定义
。
和一个「
(我懒):主要思路就是,把中文的全角标点用
\hbox to
的方式「切」成半角宽度,再视标点种类在前面或后面插入一个半宽的用\glue
实现的「铅空」。需断行时则有两种情况:「
):即使需断行这段铅空也应保留,故无需处理;。
):此时由于铅空属于glue,会被TeX在断行时discard掉,完成「行末半角」。断行时的行末半角解决后,为完成(多于两个标点相邻时的)标点挤压,使用
\in@
判断前一个标点类型(使用\xdef
定义\punct@before
)是否属于需要挤压的标点(预定义的\kern@punct
)。此时也有两种情况:~
和。
:判断为\else
分支,\relax
;。
和「
):判断为主分支,使用\unskip
去掉先前于标点后插入的铅空。理论上还有一些情况(比如我在写
Eva-JFM
的时候就遇到了各种奇奇怪怪的情况),但(同样)理论上都能够通过分支判断对应处理(比如\kern@before@punct
代表铅空应插在前面的标点集合、以此类推);同时(再次)理论上是能支持简中、繁中、日文字体的(?问题
这种实现方式有什么问题呢?
暑假还剩几天,我想实现一下(似乎pdfTeX下的CJK支持还挺好玩的)。又麻烦各位了:)
改动(8·2)
\string
防止死循环;\discretionary
结点处理。