如何自动检测内联数学模式中溢出的 \hboxes

如何自动检测内联数学模式中溢出的 \hboxes

我正在尝试创建一个应具有以下行为的宏:

  • \( \)如果不引起overfull \hbox警告,则使用内联模式编写数学表达式,
  • 如果第一个选项引起警告,则在dmath环境中(从包中)写入相同的表达式。breqnoverfull \hbox

我的问题是检测overfull \hbox,然后将变量设置为 true 或 false,以便宏可以相应地执行。这是我的宏:

\newcommand{\mymath}[1]{%
\newif\iftest%
\testfalse
\iftest
 \(#1\)
\else
: \begin{dmath}#1\end{dmath}
\fi}

\testfalse为了实现所需的行为,我应该用什么来代替该行(这里仅用于示例目的)?

答案1

\overfull \hbox感谢 egreg 的评论,我意识到在编译代码时检测警告并不容易。这就是为什么我决定开发一个小脚本来编译 .tex 文件,检测overfull \hbox与使用宏相关的警告并在重新编译之前调整 .tex 文件。

用于演示的 TeX 文件

\documentclass[draft]{article}

\usepackage{lipsum}
\usepackage[demo]{graphicx}
\usepackage{breqn}

\newif\ifoverfullbox%
\newcommand{\mymath}[1]{%
\ifoverfullbox
: \begin{dmath}#1\end{dmath}
\else
 \(#1\)
\fi}
\overfullboxfalse

\begin{document}
\lipsum[1]

Here-is-a-definition-of-a-long-long-long-math-environment,-a-long-one\mymath{f(x),g(y),h(z)}.

\begin{figure}[!h]
\includegraphics[width=15cm,height=3cm]{blabla}
\end{figure}

Here-is-a-\mymath{and again}-of-a-long-long-long-math-environment,-a-long-one\mymath{f(x),g(y),h(z)}.

\end{document}

使用脚本之前的输出

脚本之前的输出

此示例产生 3 个警告:

  • 第一个原因是在行尾使用了宏,而 TeX 不知道如何换行,
  • 第二个是由于图形太宽,
  • 第三个与第一个类似,但包含两次对宏的调用。

使用脚本后的 TeX 文件

序言完全一样

\begin{document}
\lipsum[1]

\overfullboxtrue Here-is-a-definition-of-a-long-long-long-math-environment,-a-long-one\mymath{f(x),g(y),h(z)}.\overfullboxfalse

\begin{figure}[!h]
\includegraphics[width=15cm,height=3cm]{blabla}
\end{figure}

Here-is-a-\mymath{and again}-of-a-long-long-long-math-environment,-a-long-one\mymath{f(x),g(y),h(z)}.

\end{document}

有两个新元素:变量overfullbox在包含一次宏调用的行首设置为 true,并在此行末尾重置为 false。

使用脚本后的输出

脚本之后的输出

由于该脚本,一个Overfull \hbox警告消失了。

剧本

#!/bin/bash
FILENAME=$1
MYCMD=$2
TEXCMD="pdflatex -interaction=batchmode"
OUTFILE=${FILENAME}_overfull_correction.txt
eval "rm $OUTFILE"
echo "This is the report file from the overfull \hbox correction for the $FILENAME.tex file." >> $OUTFILE
eval "$TEXCMD $FILENAME.tex"
OBOXES=( $(fgrep 'Overfull' $FILENAME.log | grep -o 'lines.*--'| grep -P '\d*' -o) )
COUNTER=$(fgrep 'Overfull' $FILENAME.log | grep -o 'lines.*--'| grep -P '\d*' -oc)
echo " " >> $OUTFILE

for ((ii=0;ii<COUNTER;ii++))
do
TEST=$(sed "${OBOXES[$ii]}q;d" $FILENAME.tex | grep -o "$MYCMD" | wc -l)
if [ "$TEST" == "0" ]
then
echo "Overfull \hbox warning not due to $MYCMD line ${OBOXES[$ii]}" >> $OUTFILE
fi
if [ "$TEST" == "1" ]
then
eval "sed -i '${OBOXES[$ii]}s/^/\\\overfullboxtrue /' $FILENAME.tex"
eval "sed -i '${OBOXES[$ii]}s/$/\\\overfullboxfalse/' $FILENAME.tex"
echo "Overfull \hbox warning corrected line ${OBOXES[$ii]}" >> $OUTFILE
fi
if [ "$TEST" == "1" -a "$TEST" == "0" ]
then
echo "More than one occurence of the $MYCMD command line ${OBOXES[$ii]}" >> $OUTFILE
fi
done

eval "$TEXCMD $FILENAME.tex"
COUNTER2=$(fgrep 'Overfull' $FILENAME.log | grep -o 'lines.*--'| grep -P '\d*' -oc)
echo "Recompiled file, $COUNTER2 Overfull \hbox warning(s) remaining" >> $OUTFILE
echo "Process exited normally" >> $OUTFILE
exit

简要介绍一下它的工作原理:

  • 首先,它编译.tex 文件并写入报告文件的标题。
  • 它计算并存储引起警告的.tex 文件中的行,并将其存储Overfull在.log 文件中。
  • 它对这些行执行循环,针对每个警告:
  • 如果不是来自指定的命令,它会将其写入报告文件并进入下一次迭代,
  • 如果相关行上有多个宏调用,它会将其写入报告文件并进入下一次迭代,
  • 如果在关注的行中有一个宏调用,它会添加到\overfullboxtrue该行的开头和\overfullboxfalse结尾。
  • 它重新编译.tex 文件并在报告文件中写入剩余警告的数量Overfull

优点和缺点

对于好的方面,我让你判断这可能如何有助于修复一些警告,但是我想强调一些缺点(也许你会有一些想法来修复它们?):

  • 无论如何,您都需要去手动更改您的.tex 文件以修复所有其他警告......
  • dmath就您围绕数学表达式编写句子的方式而言,从内联模式切换到环境可能看起来很尴尬,并且您可能需要重新措辞您的段落。
  • ...

如何使用脚本

将上述代码复制粘贴到与.sh您的 .tex 文档位于同一目录中的文件中。从终端运行chmod +x <name>.sh以修改文件的执行权限。最后,假设您的 .tex 文件名为 foo.tex,使用 在您的终端中调用它./<name>.sh foo <name_of_the_macro>

如果你有任何改进的建议,请不要犹豫(特别是如果它们涉及 b 代码,因为我是一个新手如果您发现有这种语言,我会很乐意更新它!

相关内容