为什么波浪号 ~ 有时不像不间断空格那样表现?

为什么波浪号 ~ 有时不像不间断空格那样表现?

这又是在可重构(且简单)的示例中很难捕捉的行为之一,因此必须借助于动画。

基本上,问题是这样的:波浪号 ( ~) 应该是一个不间断的空格字符,对吧?那么,为什么当我Fig.~\ref{fig:myfigure}在下面的 MWE 中使用时,它有时会断行确切地在该~角色的位置,如下面的 .gif 所示:

测试-tilde-O2.gif

例如,第 41 帧最终如下所示(单击可查看完整分辨率):

测试-tilde-41.png

这难道不是波浪号所要阻止的吗?

Fig.~\ref{...}我怎样才能找出发生这种情况的原因 - 以及如何在我的构造中获得不间断的空间?

下面是 MWE,它使用了我发布的test-tilde.texrepeat-build.sty这里(目前仅在 Linux 上测试) - 并且需要构建两次,使用-shell-escape

pdflatex -shell-escape test-tilde.tex # first time, refs wrong here
pdflatex -shell-escape test-tilde.tex # second time, refs ok (can enable the `convert` post action if desired)

...这样就生成了上面动画中使用的所有 PDF。

编辑:我修改了代码,因此它将在没有的情况下构建repeat-build.sty;并且它将重建上面静止屏幕截图上的情况(其中变量\tester= 87);然后如果您想使用repeat-build,只需(取消)注释相应的行。

代码如下:

\documentclass[%
  12pt,
  journal,
  onecolumn,
  twoside,
  draftcls,
  letterpaper,
]{IEEEtran}

\usepackage[demo]{graphicx} %
\usepackage{xcolor} % \pagecolor
\pagecolor{yellow!15}
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}

\usepackage[nopar]{lipsum}
\usepackage{xstring}
% https://tex.stackexchange.com/a/26808/2595
\makeatletter
\def\unpacklipsum#1#2#3{%
  \count@=#1\relax
  \advance\count@\m@ne
  \def#3{}%
  \loop\ifnum\count@<#2\relax
    \advance\count@\@ne
    \edef#3{#3\csname lipsum@\romannumeral\count@\endcsname}%
  \repeat}
% https://tex.stackexchange.com/a/168754/2595
\def\loremnchars[#1]#2{%
  \unpacklipsum{#1}{#1}{\myunpacked}%
  \StrMid{\myunpacked}{1}{#2}% same as \StrLeft{\myunpacked}{#2}
}
\def\eloremnchars#1#2#3{%
  \unpacklipsum{#1}{#1}{\myunpacked}%
  % \StrMid is not an expandable macro (can't go in \def) - but
  % can "return" by saving in #3
  \StrMid{\myunpacked}{1}{#2}[#3]
}
\def\getLoremParaNumChars#1#2{%
  \unpacklipsum{#1}{#1}{\myunpacked}%
  \StrLen{\myunpacked}[#2]
  \typeout{Lorem paragraph #1 has #2 characters}.
}
\makeatother

\usepackage[format=plain,font=small,skip=12pt]{caption} %
\usepackage{listings} %
\usepackage{units} %
\usepackage{floatrow}
\floatsetup[figure]{capposition=bottom}
\usepackage{etoolbox}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{tikz}
\usetikzlibrary{shapes,positioning}
\usetikzlibrary{fit}
\usetikzlibrary{calc}
\usetikzlibrary{decorations.markings}
\usepackage{txfonts} % Times font in math; tlmgr install txfonts
\renewcommand{\ttdefault}{pcr}
\usepackage[UTF8]{ctex} % needs simsun.ttc in same directory
\usepackage{setspace}
\usepackage{siunitx}
\usepackage[american]{babel}
\usepackage{csquotes}
\makeatletter
\let\l@AMERICAN\l@american % https://tex.stackexchange.com/q/88861/
\makeatother
\usepackage[style=ieee,isbn=true,doi=false,url=true,backend=biber]{biblatex}


% here, set the \tester at a number,
% so we don't hit an error if we
% compile without repeat-build (-shell-escape)

% https://tex.stackexchange.com/a/185976/2595
%%%% uncomment the below part if you want to use {repeat-build}:
%   \ifx\tester\undefined{%
%     \global\protected\def\tester{100} %
%   }\fi
%   % do not rm the .aux here; need them for fig label;
%   % since the process needs to run twice for correct
%   % label - comment the convert post action.
%   %% manual convert command:
%   %% convert -verbose -density 150 test-tilde-*.pdf[0] -crop 1024x580+137+773 -resize 512x +repage -delay 15 -loop 0 test-tilde.gif
%   %% gifsicle -O2 test-tilde.gif -o test-tilde-O2.gif # helps reduce size
%   \def\pacode{%
%     pwd; %
%     ls \jobname-*.log \jobname-*.aux; %
%     rm -vrf \jobname-*.log ;% \jobname-*.aux; %
%   %   convert -verbose -density 75 \jobname-*.pdf[0] %
%   %     -crop 512x290+68+386 %
%   %     +repage %
%   %     -delay 15 -loop 0 % -delay 5
%   %     \jobname.gif %
%   %   ; %
%   %   eog \jobname.gif ; % run viewer
%   }
%   \usepackage[%
%     vartoken=\tester,%  % loop the variable token: \tester
%     varvals={15,16,...,29,41,42,...,52,58,59,...,65,77,78,...,89},% set \tester to change; (was from 0 to 100 {0,...,100})
%     postactioncode={\pacode},%
%   ]{repeat-build}
%   \unprotect\tester
%   \makeatletter
%   \def\getrjname{\rpbuild@jobname}
%   \makeatother
%%%% else this should be enough for a usual run:
\def\tester{83} % comment this if using repeat-build!

\begin{document}

  \title{Test title}
  \author{test}

  \maketitle

  \begin{abstract}
  The abstract text goes here.
  \end{abstract}

  \section{Test section}

  Test text, before figure:

  \setcounter{figure}{22} % if 10, then {figure} becomes 11
  \begin{figure}[h!t]
    \singlespacing
    \includegraphics[width=\textwidth,height=100pt]{demo.whatever}
    %\caption[shortdesc]{The figure is being shown here. \protect\loremnchars[3]{255}}
    \captionof{figure}[shortdesc]{The figure is being shown here. \protect\loremnchars[3]{255}}
    \label{fig:myfigure}
  \end{figure}

  Current: doc: \jobname; \verb!\tester!: \tester ... \loremnchars[1]{150}

  \eloremnchars{2}{\tester}{\tretA} %
  \pgfmathtruncatemacro{\tB}{\tester/2} %
  \eloremnchars{4}{\tB}{\tretB} %
  \eloremnchars{5}{\tester}{\tretC} %
  \tretA\space on Fig.~\ref{fig:myfigure}.
  \tretB\space on Fig.~\ref{fig:myfigure},
  \tretC\space on Fig.~\ref{fig:myfigure}.

  \loremnchars[3]{712}.. And ... \lipsum[7]

  %\getLoremParaNumChars{3}{\tret} %\typeout{\tret}
  %\eloremnchars{3}{712}{\tret} \typeout{\tret}

\end{document}

答案1

以下是问题中缺少的 MWE:

\documentclass[12pt,onecolumn,draftcls]{IEEEtran}
\usepackage{ctex}
\begin{document}
%\show~
  Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi.
  Morbi auctor \space on Fig.~23. Quisque ullamcorper placerat ipsum. 
  Cras \space on Fig.~23, Fusce mauris. Vestibulum luctus nibh at lectus. Sed 
  bibendum, nulla a faucibus semp \space on Fig.~23.
\end{document}

取消注释\show~告诉我们

> ~=macro:
->\hspace {0.25em plus 0.125em minus 0.08em}\ignorespaces . 
l.4   \show~

即可破坏空间,删除该\usepackage{ctex}线会将其恢复到正常状态

> ~=macro:
->\nobreakspace {}.
l.4   \show~

如果必须使用,ctex那么似乎您可以用~来替换\nbs,或者您可以使用\standardtilde来恢复 的通常行为~

答案2

只是想在这里包含一些有关我的调试过程的注释。

显然,由于波浪号是问题所在,我首先想看看它到底起什么作用。起初,我甚至不认为它是一个宏(我猜我以为它“只是”一个带有“特殊 catcode”的字符),然后我想texdef在控制台 shell 中尝试一下:

$ texdef -t latex '~'

\~:
macro:->\OT1-cmd \~\OT1\~ 

好的,事实证明,它可能是一个宏......但这不是我正在寻找的宏:texdef自动添加一个反斜杠,所以我们实际看到的是宏的定义(反斜杠波浪号),而不是(波浪号)\~的定义。~

此时,事情变得复杂了,因为很难在线搜索;波浪号是 ASCII 字符(因此它没有 html 实体表示,经 确认php -r 'echo htmlentities("a~a\n",ENT_COMPAT,"UTF-8");')- 因此,我无法真正搜索查询,\def ~无论是在线搜索还是 Tex.SE 上的本地搜索。不过,不知何故,我在在线搜索结果中注意到了这一点:

[R] R 文档中的波浪符号。 - Grokbase

... )\textasciitilde 是 latex 的标准部分(在文件 latex.ltx 中)。...

啊,至少有一个指针;所以现在可以从终端 shell 执行此操作:

$ kpsewhich latex.ltx
/path/to/texlive/2011/texmf-dist/tex/latex/base/latex.ltx
$ grep '~' $(kpsewhich latex.ltx) | grep def
\chardef\active=13 \catcode`\~=\active % tilde is active
\def~{\errmessage{%
\def~{\typeout{! %
\def~{\nobreakspace{}}
     \lowercase{\endgroup\def~{\leavevmode\kern\z@\char`#1}}}

此外,我还偶然发现https://tex.stackexchange.com/a/59260/2595https://tex.stackexchange.com/a/66951/2595- 这对我来说证实了 tilde 作为宏的原始定义是\def~{\nobreakspace{}}

好的,那现在怎么办?好吧,首先我想重新定义 tilde,这样它就会将消息打印到 stdout;所以我想,如果它被某个东西替换,那么打印就会停止,并指向重新定义发生的位置。所以我用了这个:

% should stop when something changes its def...
\newcounter{tildcount}
\typeout{tilde MEANING AT START: \meaning~ }
% tilde MEANING AT START: macro:->\nobreakspace {}
\let\origtilde~
\def~{%
  \stepcounter{tildcount}%
  % \meaning~ remains the same as before, as long as 
  % this \def is in place; so don't print it. 
  \typeout{tilde called \thetildcount\space times}%
  \origtilde%
}

到目前为止一切顺利 - 除了这个宏可能会在标题内的波浪号等上崩溃。更糟糕的是,重新定义不会发生在文档中间,所以这最终没有多大帮助。

因此,唯一剩下的事情就是打印\meaning~整个文档(包括序言),并查看其中的变化。所以我做了与此相当的事情(如上所示test-tilde.tex):

% https://tex.stackexchange.com/questions/81789/get-current-source-line-number/81794#81794
\def\showLineMean{\typeout{line \the\inputlineno; MEANING: \meaning~}}
...
\usetikzlibrary{calc} \showLineMean                    % l.61
\usetikzlibrary{decorations.markings} \showLineMean    % l.62
\usepackage{txfonts} \showLineMean % Times font ...    % l.63
\renewcommand{\ttdefault}{pcr} \showLineMean           % l.64
\usepackage[UTF8]{ctex} \showLineMean % simsun.ttc ... % l.65
\usepackage{setspace} \showLineMean                    % l.66
\usepackage{siunitx} \showLineMean                     % l.67
\usepackage[american]{babel} \showLineMean             % l.68
\usepackage{csquotes} \showLineMean                    % l.69
...
\usepackage[style=ieee,...]{biblatex} \showLineMean    % l.73
...
\showLineMean                                          % l.115
\begin{document}                                       % l.116
\showLineMean                                          % l.117

\title{测试标题} ...

然后可以这样:

$ pdflatex test-tilde.tex # ...
$ grep MEANING test-tilde.log 
line 61; MEANING: macro:->\nobreakspace {}
line 62; MEANING: macro:->\nobreakspace {}
line 63; MEANING: macro:->\nobreakspace {}
line 64; MEANING: macro:->\nobreakspace {}
line 65; MEANING: macro:->\nobreakspace {}
line 66; MEANING: macro:->\nobreakspace {}
line 67; MEANING: macro:->\nobreakspace {}
line 68; MEANING: macro:->\active@prefix ~\active@char~ 
line 69; MEANING: macro:->\active@prefix ~\active@char~ 
line 73; MEANING: macro:->\active@prefix ~\active@char~ 
line 115; MEANING: macro:->\active@prefix ~\active@char~ 
line 117; MEANING: macro:->\hspace {0.25em plus 0.125em minus 0.08em}\ignorespa

哈哈!所以波浪符号在加载~时第一次改变babel- 然后,紧接着第二次改变\begin{document}

当然,我看不出这背后的任何逻辑——作为最后的手段,我尝试在互联网上查找最后一个含义(在文档编写期间有效的含义);幸运的是,最先找到的结果之一是:

这是 CJK 宏包 ver. 4.8.3 的命令文件 command.txt ...

\CJKtilde 此命令将活动“~”字符的定义从不可断开的空格更改为 \def~{\hspace{0.25em plus 0.125em minus 0.08em}}

嗯,这最终证实了问题是什么(并且解决方案与接受的答案相同)。

然而,有些令人难过的是 - 经过这一切,我不能说这是一个我只能在本地机器上完成的调试过程,而无需在线查找......希望我的程序比这更强大:)

好吧,希望这对某人有帮助,
干杯!

相关内容