检测宏中句子开头的大写字母

检测宏中句子开头的大写字母

能否让宏在新的句子开头给出不同的结果?假设我希望宏“\secname”在新的句子开头写“Section”,在其他地方写“section”。我该怎么做?

答案1

您可以将“句子结尾”字符的 \sfcode 设置为不同的值并进行测试:

 \documentclass[10pt]{report}
 \sfcode`\.=1001
 \sfcode`\?=1001
 \sfcode`\!=1001
 \sfcode`\:=1001
 \newcommand\secname{\ifnum\spacefactor=1001 Secname\else secname\fi}
 \begin{document}
 abc. \secname\ is \secname.

 e.g.\@ \secname
 \end{document}

\nonfrenchspacing 也设置 \sfcodes。在这种情况下,您可以使用类似下面的命令:

 \documentclass[10pt]{report}
 \nonfrenchspacing
 \newcommand\secname{\ifnum\spacefactor>1900 Secname\else secname\fi}
 \begin{document}
 abc. \secname\ is \secname.
 abc: \secname, \secname.
 e.g.\@ \secname
 \end{document}

答案2

最简单的方法是定义两个宏:

\def\secname{section}
\def\Secname{Section}

确定句子边界是一项非常困难的任务,也是计算语言学中最热门的话题之一。要正确做到这一点,您需要确定在《神秘博士》中,“Dr.”后面的句号不是句子的结尾,因此您需要解析所有缩写,当您想测试下一个字母是否以大写字母开头时,请考虑我们使用的所有拉丁缩写。

答案3

在 Ulrike 发布使用 的漂亮答案之前\spacefactor,我曾认为如果不重新定义 ,在 TeX 中这是不可能的.。 只是为了完整性:这是我的答案,它确实重新定义.(在将其激活之后,这可能不是一个好主意)。 请注意,您不必\@在 Ulrike 的解决方案中使用 as 。

\documentclass{article}
\let\period.
\catcode`.=\active
\let\qwe\relax
\futurelet\myspace{ }
\newcommand.{\period\futurelet\nextchar\testspace}
\newcommand\testspace{\ifx\nextchar\myspace\expandafter\eatspace\expandafter.\fi}
\def\eatspace. { \futurelet\nextchar\testsec}
\newcommand\testsec{\ifx\nextchar\secname\def\qwe{ }\fi}
\newcommand\secname{\ifx\qwe\relax section\else Section\let\qwe\relax\fi}
\begin{document}
abc. \secname\ is \secname.
abc: \secname, e.g.\ \secname.
\end{document}

是的,这看起来好像我试图让它尽可能地晦涩难懂。两个有趣的点:1. 请注意\myspace\space不起作用!)的定义。2. 我没有设法使用 LaTeX 来\ifnextchar测试下一个字符是否是空格,所以我使用了\futurelet

答案4

这是一个新的答案,部分灵感来自最近的查询在句子开头表现不同的宏,该查询因与当前查询重复而被关闭(直到今天我才意识到这一点)。

假设作者定义了两个宏\agt,分别称为 ,输出字符串“the agent”,和\Agt,输出“The agent”(大写“T”)。此外,我们假设作者希望自动\agt表现为\Agt如果- 和除非--\agt出现在句子开头。(出于某种原因,作者无法根据需要手动替换\agt... \Agt

假设我们可以放心地忽略诸如Mr. \agtMrs. \agt之类的情况,因为它们不太可能出现在实际文档中,那么以下基于 LuaLaTeX 的解决方案可能会引起人们的兴趣。它不对\sfcode各种潜在的句末标点符号的 -status 做出任何假设,并且无论\frenchspacing\nonfrenchspacing是否有效,它都可以正常工作。它的工作假设是,在以下两种情况下,\agt应该将 更改为:\Agt

  • \agt出现在输入行的开头。行首和 之间的空格\agt是可以的。或者,

  • \agt前面是?!、 或.(英语中三个主要的句末标点符号),后面是一个或多个空格字符。(因此,诸如.\agt和 的情况?\agt不会被修改。)

    当然,如果您的文档所用的语言具有不同的句末标点符号,请随意修改下面显示的[...]第二个语句中所括的字符列表。gsub

另外:我写这个答案时假设人们使用的编辑器通过插入“软”换行符来“重新排列”段落。(这是我使用的所有编辑软件的行为......)但是,正如@jfbu 在评论中指出的那样,其他编辑器(显然包括 Emacs - 抱歉,我个人不使用 Emacs)使用了不同的方法,即,他们通过插入“硬”换行符来重新排列段落,实际上将段落存储为一系列单独的字符串。这种方法显然增加了某些实例\agt出现在行首的风险,这反过来又使所提出的方法变得不那么有吸引力。唉。恐怕我不知道该给出什么建议。

那么,这里就是一个 MWE。

在此处输入图片描述

% !TEX TS-program = lualatex
\documentclass{article}

\def\agt{the agent}
\def\Agt{The agent}

\usepackage{luacode}
\begin{luacode}
function agt_to_Agt ( s )
  s = s:gsub ( "^%s-\\agt", "\\Agt" )
  return s:gsub ( "([?!.])%s+\\agt" , "%1 \\Agt" )
end
\end{luacode}
\AtBeginDocument{\directlua{luatexbase.add_to_callback 
  ( "process_input_buffer" , agt_to_Agt , "agt_to_Agt" )}}
  
\begin{document}
\noindent
 \agt\ says x. \agt\ shouts Y!  \agt\ asks z? \agt\ whispers something 
to \agt.  \agt\ says the phrase,  ``\agt''.
 
\end{document}

相关内容