假设您有\macroA
一种方法,可以产生一定数量的字符。 假设您有一种方法,可以 产生一定数量的字符。\macroA{⟨TeX number-quantity denoting amount⟩}
A
\macroB
\macroB{⟨TeX number-quantity denoting amount⟩}
B
可能看起来像这样:
%\overfullrule=0pt
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\def\macroA#1{%
\expandafter\Aloop\expandafter{\romannumeral\number\number#1 000}{}%
}%
\def\Aloop#1#2{%
\ifx\relax#1\relax\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{\leavevmode#2}{%
\expandafter\ifx\expandafter\relax\firstoftwo{}#1\relax\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{%
% Don't use \discretionary with the last A to avoid
% \baselineskip after the last line in case that line being
% too long:
\expandafter\Aloop\expandafter{\firstoftwo{}#1}{#2A}%
}{%
% use \discretionary to allow linebreaks
\expandafter\Aloop\expandafter{\firstoftwo{}#1}{#2A\discretionary{}{}{}}%
}%
}%
}%
\def\macroB#1{%
\expandafter\Bloop\expandafter{\romannumeral\number\number#1 000}{}%
}%
\def\Bloop#1#2{%
\ifx\relax#1\relax\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{\leavevmode#2}{%
\expandafter\ifx\expandafter\relax\firstoftwo{}#1\relax\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{%
% Don't use \discretionary with the last B to avoid
% \baselineskip after the last line in case that line being
% too long:
\expandafter\Bloop\expandafter{\firstoftwo{}#1}{#2B}%
}{%
% use \discretionary to allow linebreaks
\expandafter\Bloop\expandafter{\firstoftwo{}#1}{#2B\discretionary{}{}{}}%
}%
}%
}%
\hrule\kern\dp\strutbox
\macroA{240}
\macroB{240}
\kern\dp\strutbox\hrule
\bye
正如你在图片上看到的,
,在终端上,
This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2019/dev/Debian) (preloaded format=pdftex)
restricted \write18 enabled.
entering extended mode
(./test.tex
Overfull \hbox (0.24593pt too wide) in paragraph at lines 26--27
[]\tenrm AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|
Overfull \hbox (2.74597pt too wide) in paragraph at lines 26--27
\tenrm AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|
Overfull \hbox (2.74597pt too wide) in paragraph at lines 26--27
\tenrm AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|
Overfull \hbox (3.57997pt too wide) in paragraph at lines 28--29
[]\tenrm BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB|
Overfull \hbox (4.83005pt too wide) in paragraph at lines 28--29
\tenrm BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB|
Overfull \hbox (4.83005pt too wide) in paragraph at lines 28--29
\tenrm BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB|
[1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] )
(see the transcript file for additional information)</usr/share/texlive/texmf-d
ist/fonts/type1/public/amsfonts/cm/cmr10.pfb>
Output written on test.pdf (1 page, 9746 bytes).
Transcript written on test.log.
,这会产生大量的过满\hboxes
,即很多文本行太宽,因此突出到右边距。
假设你申请\macroA
并且\macroB
在同一段落内,即你这样做:
\macroA{240}\macroB{240}\bye
。
您将得到一个段落,由一个字母序列A
和一个字母序列组成B
- 行可能仍然有点太宽:
问题:
B
如何才能在同一个段落中实现这样的效果:以“来自”结尾的行\macroB
不会太宽但可能会太短,因此不会突出到右边距;而以“A
来自”结尾的行\macroA
可能会太宽,因此可能会突出到右边距?
\macroA
即如何修改and/or的定义\macroB
以实现以下输出,
,不“手动”进行换行,而是将换行留给 TeX 自己的(非限制)水平模式算法?
如何让用户选择如何处理在即将断线的地方一个B
来自后面\macroB
跟着一个A
来自的\macroA
情况,这样如果紧接着断线的话线就会太短一点,B
如果紧接着断线的话线就会太宽一点A
;-)
我现在想到的解决方案是生成与字母宽度相同的水平空格,B
后跟\hskip
相同宽度的可丢弃“负片”,后跟字母B
- 这样你仍然会收到\hbox
带有B
s 的过满警告,但这样它们是由于行末的空格触发了换行符,而不是由于可见材料突出到右侧边缘:
%\overfullrule=0pt
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\def\macroA#1{%
\expandafter\Aloop\expandafter{\romannumeral\number\number#1 000}{}%
}%
\def\Aloop#1#2{%
\ifx\relax#1\relax\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{\leavevmode#2}{%
\expandafter\ifx\expandafter\relax\firstoftwo{}#1\relax\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{%
% Don't use \discretionary with the last A to avoid
% \baselineskip after the last line in case that line being
% too long:
\expandafter\Aloop\expandafter{\firstoftwo{}#1}{#2A}%
}{%
% use \discretionary to allow linebreaks
\expandafter\Aloop\expandafter{\firstoftwo{}#1}{#2A\discretionary{}{}{}}%
}%
}%
}%
\def\macroB#1{%
\expandafter\Bloop\expandafter{\romannumeral\number\number#1 000}{}%
}%
\def\Bloop#1#2{%
\ifx\relax#1\relax\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{\leavevmode#2}{%
\expandafter\Bloop\expandafter{\firstoftwo{}#1}{#2\phantom{B}\hbox{B}{\setbox1=\lastbox\hskip-\wd1 \box1}}%
}%
}%
\hrule\kern\dp\strutbox
\macroA{240}\macroB{240}
\macroA{240}
\macroB{240}
\kern\dp\strutbox\hrule
\bigskip
About the edge case:
\bigskip
\hrule\kern\dp\strutbox
The case of the 64$^{\hbox{th}}$ B not fitting in the line any more:
\macroB{64}
The edge-case of 63 B being followed by an A:
\macroB{63}\macroA{1}
\kern\dp\strutbox\hrule
\bye
我不认为这个解决方案很优雅。
我认为还有更好的方法。
答案1
首先:我必须简化您的仅扩展循环,因为它在其参数中一次又一次地重复 256 m
、 255 m
、 254 。更有效的方法是仅将这 256 放入输入队列一次。m
m
第二:我建议对 A 插入负跳过、惩罚 0、正跳过,对 B 则反之。
第三:我建议做成\rightskip
可拉伸的,以避免盒子过满。
\def\expandrepeat #1{\expandafter\expandrepeatA\romannumeral #1000\relax}
\def\expandrepeatA #1\relax#2{\expandrepeatB{#2}#1\relax}
\def\expandrepeatB #1#2{\ifx#2\relax \else #1\afterfi \expandrepeatB{#1}\fi}
\def\afterfi#1\fi{\fi#1}
\rightskip=0em minus1em
\expandrepeat{250}{A\hskip-1em\penalty0\hskip1em}%
\expandrepeat{250}{B\hskip1em\penalty0\hskip-1em}
% for testing, where is the margin?
\vskip-4cm \hfill \vrule height4cm
\end
答案2
你是什么意思
将换行留给 TeX 自己的(非限制)水平模式算法?
你能修改该算法的参数吗?比如\leftskip
或\rightskip
或\tolerance
或\hfuzz
?
如果是:
- 为了允许 TeX 制作由于太短而不好的行,您可以将其设置
\tolerance
为 10000。 - 要抑制警告和超长规则,请增加
\hfuzz
。这不会阻止行变得太长。这只会阻止被告知。这就是我对特定段落所做的。
A
或的序列B
不包含粘合。诸如此类的事情\emergencystretch
似乎并不有趣。它们还适用于整个段落,而不仅仅是段落中的几行。
重复 A 或重复 B 之间的重复惩罚始终相同,并且不会改变哪个 A 或 B 靠近线末端以利于突破线。
宏是否也必须在乳胶的\centering
(与 TeX 的不同\centering
)或center
-environment?
任何。
您需要在A
或之间设置断点B
。您可以穿插一些形成断点的内容:\penalty0
或\hskip0pt
或\discretionary{}{}{}
。(或者您可以暂时将A
或设为B
字体的连字符,但不能用于最后的A
或B
。)
该问题隐藏了复制令牌的问题。
通用宏\replicatethis
很有用,您可以在其中指定要重复的内容以及要使用的内容进行散布。
使用散布时您需要查看最后一步,因为最后一步不需要散布。
所以我用通用宏如同Wipet 的但有一些修改:
- 附加两个
\relax
以便您可以检测最后一步。 - 不
\afterfi
,但是\firstotwo
/\secondoftwo
因为方法将无法产生具有不匹配或的\afterfi
事物序列。\if..
\fi
\romannumeral0\number\number#1 000
使用字母常量时也会`\a
失败。\count24
\romannumeral#1000
- 复制的内容在参数中收集,并在循环结束时一次性交付所有内容。如果通用的
\replicatethis
\if
必须用不匹配的/保存\fi
,必须这样做,以便最后所有不匹配的\if
/都会立即出现。缺点:这比较慢,并且重复次数受到参数中适合的标记数量的限制。\fi
%\overfullrule=0pt
% / prevent nagging:
{\setbox1=\hbox{A}\expandafter}\expandafter\hfuzz\expandafter=\the\wd1
%\tolerance=10000
\long\def\permutetwoarguments#1#2{#2#1}%
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
% /
% / Generic macro \repeatthis{<<number> denoting repetitions>}{<what to repeat>}{<interspersing>}
% /
\long\def\replicatethis#1#2#3{%
% / #1 repetitions
% / #2 what to repeat
% / #3 interspersing
\romannumeral0% / <-- I *think* you may like this. ;-)
\expandafter\permutetwoarguments
\expandafter{\romannumeral\number\number#1 000}%
{\replicatethisloop{#2}{#3}{}}%
\relax\relax
}%
\long\def\replicatethisloop#1#2#3#4#5%
{%
% / #1 what to repeat
% / #2 interspersing
% / #3 what you got so far.
% / #4 other-m or \relax. If \relax done.
% / #5 other-m or \relax. If \relax last step or done.
\ifx#4\relax\expandafter\secondoftwo\else\expandafter\firstoftwo\fi
{%
\ifx#5\relax\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{\replicatethisloop{#1}{#2}{#3#1}}%
{\replicatethisloop{#1}{#2}{#3#1#2}}%
#5%
}{ #3}%
}%
% /
% / \macroA and \macroB
% /
\def\macroA#1%
% / Intersperse with zero-\hskip breakpoint
{%
\leavevmode
\replicatethis{#1}{A}{\hskip0pt}%
}%
\def\macroB#1%
% / If the \phantom causes line to be too long, then the \hskip
% / as breakpoint is used for breaking line and discarded.
{%
\leavevmode
\replicatethis{#1}{\phantom{B}\hbox{B}{\setbox1=\lastbox\hskip-\wd1}B}{}%
}%
% / Play game with unbalanced \if \fi.
\expandafter\expandafter\expandafter
\permutetwoarguments
\expandafter\expandafter\expandafter
{\replicatethis{12}{\fi}{}}
{\replicatethis{12}{\iffalse}{\else}}
% / That is the margins:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\noindent\vrule\vbox to\vsize{\advance\hsize-.8pt\leavevmode\hrule\vfill\hrule}\vrule
\par \kern-\vsize \nobreak\vskip-\baselineskip\nobreak\vskip\topskip\par
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\macroA{240}\macroB{240}
\macroA{240}
\macroB{240}
\kern\dp\strutbox\hrule
\bigskip
About the edge case:
\bigskip
\hrule\kern\dp\strutbox
The case of the 64$^{\hbox{th}}$ B not fitting in the line any more:
\macroB{64}
\smallskip
The edge-case of 63 B being followed by an A:
\macroB{63}\macroA{1}
\smallskip
The edge-case of 60A being followed by a B:
\macroA{60}\macroB{1}
\smallskip
The edge-case of an 1pt-kern and 59A being followed by a B:
\leavevmode\kern1pt\macroA{59}\macroB{1}
\smallskip
The edge-case of 59A being followed by a B:
\macroA{59}\macroB{1}
\kern\dp\strutbox\hrule
\vfill \break
\bye
答案3
我没有看到被删除的答案,但它可能是这样的。\Aloop
改为\discretionary{}{}{}
\nobreak\hskip0ptminus9pt\penalty1000\hskip0ptminus-9pt\relax
并\Bloop
变成\discretionary{}{}{}
\nobreak\hskip0ptplus9pt\penalty1000\hskip0ptplus-9pt\relax
\nobreak
当首字母非常适合整行时,可以省略首字母,以允许普通的齐平换行。