可敬的缩写宏

可敬的缩写宏

怎样才能编写一个宏,让潦草的缩写变得令人尊敬呢?

\documentclass{article}
% \newcommand\abr{...}
\begin{document}
I've seen it in the \abr{OED}.
\end{document}

我的意思是OED应该将其呈现为O.\,E.\,D.

正如 Mico 指出的那样,不应该有两个相邻的点。我想有人可能会用它\@ifnextchar.来防止这种情况。

答案1

总的来说,与 Steven B. Segletes 的答案相同,但可以扩展。此外,几乎所有内容都应该没问题(除了真正不可能的\endabr@)。

\documentclass[]{article}

\makeatletter
\newcommand\abr[1]
  {%
    \abr@#1\endabr@
  }
\def\abr@#1#2\endabr@
  {%
    #1.%
    \if\relax\detokenize{#2}\relax
      \@%
      \expandafter\@gobble
    \else
      \,%
      \expandafter\@firstofone
    \fi
    {\abr@#2\endabr@}%
  }
\makeatother

\begin{document}
Single letter:
\abr{eg}

Multi letter: 
\abr{{th}e}
\end{document}

答案2

这是我原来方法的最简单形式。它可以放在 中\edef。它的唯一缺点是,如果参数太长(可能是 256 个字符??),它可能会破坏堆栈。

\documentclass{article}
\newcommand\abr[1]{\abraux#1\relax\relax}
\def\abraux#1#2\relax{#1.\ifx\relax#2\relax\@\else\,\abraux#2\relax\fi}
\begin{document}
Here is \abr{OED} abbreviation.

Here is \abr{XO} abbreviation.
\end{document}

在此处输入图片描述

如果这确实是个问题,那么这里有一个不存在该问题的替代方案。

似乎存在误解,认为 的定义\abr不能放入 中\edef。其实可以。当然,扩展不一定美观,但会产生正确的排版。唯一的条件是\@MyOwnMacro未在文档的其他地方使用。

\documentclass{article}
\usepackage[T1]{fontenc}
\makeatletter
\let\@MyOwnMacro\relax
\newcommand\abr[1]{\abraux#1\relax\relax}
\def\abraux#1#2\relax{%
  #1.\ifx\relax#2\relax\def\@MyOwnMacro{\@}\else\def\@MyOwnMacro{\,\abraux#2\relax}\fi%
  \@MyOwnMacro%
}
\makeatother
\begin{document}
Here is \abr{OED} abbreviation.

Here is \abr{XO} abbreviation.

Can be edef'ed:

\edef\tmp{\abr{OED}} \detokenize\expandafter{\tmp}

expands to \tmp
\end{document}

在此处输入图片描述

答案3

这是一个基于 LuaLaTeX 的解决方案。

  • \abr{OED}或之类的情况\abr{IMF}可以按预期工作。如果首字母缩略词包含大写和小写字母,则仅在首字母缩略词内部的大写字母前插入点。例如,\abr{MSc}generatesM.\,Sc.\abr{PhD}generates Ph.\,D.

  • 它可以直接处理大小写混合的缩写词,例如“PhD”——无需写入\abr{{Ph}D}

  • 如果“粗略的缩写”结束一个句子,应该将“。”标点符号放在 的参数内\abr。代码会小心地\@在最后一个.字符前插入一个“space factor*”指令。这反过来会通知 LaTeX.应该将该字符视为句子的结尾。

  • 如果 的参数\abr为空或扩展为不返回任何内容,则代码不返回任何内容。例如,\def\ttt{} /\abr{\ttt}/返回//。如果代码遇到非字母字符(例如和),()不会在它们之前或之后插入句点。

  • 代码是可扩展的,\abr可以包含在\edef指令的参数中。

在此处输入图片描述

\documentclass{article}
\usepackage{luacode}   % for 'luacode' environment

%% Lua-side code:
\begin{luacode}
function abr ( s )
  n = string.len ( s )
  -- Do nothing unless "s" is non-empty.
  if n>0 then 
    s_mod = ""  -- initialize the string

    -- Process the first n-1 characters in "s"
    for i=1, n-1 do
      s12 = string.sub ( s  , i, i+1 )
      s1  = string.sub ( s12, 1, 1 )
      if string.match ( s12 , "%a%u" ) then
        s_mod = s_mod .. s1 .. ".\\,"
      else
        s_mod = s_mod .. s1
      end
    end

    -- Process the final character in "s"
    s_n = string.sub ( s , n)
    if     string.match (s_n, "%.") then   -- "." char.
      s_mod = s_mod .. "\\@." 
    elseif string.match (s_n, "%l") then   -- lowercase letter
      s_mod = s_mod .. s_n .. ".\\hbox{}"
    elseif string.match (s_n, "%u") then   -- uppercase letter
      s_mod = s_mod .. s_n .. "."
    else                    -- Any other character:
      s_mod = s_mod .. s_n  -- don't add anything after 's_n'
    end
    -- Print the modified string
    tex.sprint ( s_mod )
  end
end

\end{luacode}

%% LaTeX-side code: macro that calls the Lua function
\newcommand\abr[2]{\directlua{abr("#1")}}

\begin{document}
\abr{OED}, \abr{PhD}, \abr{DPhil}, \abr{MSc}, \abr{()}

\smallskip
% Two calls to "\abr" with an empty argument (upon expansion):
.\abr{}. \quad 
\def\ttt{} .\abr{\ttt}. 

\bigskip
\edef\tmp{\abr{MA}}   \detokenize\expandafter{\tmp}

\edef\tmp{\abr{MA.}}  \detokenize\expandafter{\tmp}

expands to: \tmp

\smallskip
\edef\tmp{\abr{MSc}}  \detokenize\expandafter{\tmp}

\edef\tmp{\abr{MSc.}} \detokenize\expandafter{\tmp}

expands to: \tmp

\bigskip
Some tests of spacing after punctuation marks:

\smallskip
a \abr{PhD} candidate --- good

a Ph.\,D. candidate   --- just to verify

\smallskip
an \abr{MSc} candidate --- good

an M.\,Sc.\ candidate  --- just to verify

\smallskip
She has a \abr{PhD.} So do I. --- good

She has a Ph.\,D\@.  So do I. --- just to verify

\smallskip
He has an \abr{MSc.} So do I. --- good

He has an M.\,Sc.    So do I.  --- just to verify

\smallskip
Does he have an \abr{MSc.}? Really?! --- good

Does he have an M.\,Sc.?    Really?!  --- just to verify
\end{document} 

答案4

\documentclass{article}
\usepackage{xinttools}
\newcommand\abr[1]{\xintListWithSep{.\,}{#1}.}
\begin{document}
I've seen it in the \abr{OED}.

I got my \abr{{Ph}D}.
\end{document}

在此处输入图片描述

已更新(采用 Mico 风格,但没有 LuaLaTeX)

这里的语法是\abr{PhD.}在句末使用例如,\abr{PhD}在句末使用如果不是。

\documentclass{article}
\usepackage{xinttools}
\makeatletter
\newcommand\abr[1]
   {\expandafter\@gobbletwo\romannumeral0\xintapplyunbraced\abr@aux{#1}.\@}
\def\abr@sep{.\,}
\def\abr@aux#1{\if.#1\expandafter\abr@end
               \else
                \if1\ifnum`#1<`A 0\fi\ifnum`#1>`Z 0\fi1%
                   \expandafter\expandafter\expandafter\abr@sep
                \fi
               \fi#1}%
\def\abr@end.{ \abr@@end}
\def\abr@@end.\@{\@.}
\makeatother

\begin{document}%\ttfamily
I've seen it in the \abr{OED}, and if located at end of a sentence
just insert a dot in the \verb|\abr| argument: \abr{OED.} It ended a
sentence and in non-French spacing mode, TeX inserted the extra
space.

\texttt{We can see it better with monospace font: \abr{OED.} See?}

I got my \abr{PhD} and even my \abr{PhilD}, leniency ruled
in those days.

\texttt{The dots are added in a smart way: \abr{AaaaBbbbCccc.} But it is
assumed that the first letter is \abr{Uppercased.} That's it.}

\texttt{Notice that neitger \abr{Aaaa} nor \abr{AaA} trigger an end of
  sentence spacing after the dot, which is \abr{Good.} Isn't it?}
\end{document}

在此处输入图片描述

再次更新,用于缩写后自动检测句子结尾的点

这里将自动检测句子末尾的点。

当然我们不能使用\@ifnextchar它,因为它会占用空格。

我添加了一些关于可扩展性的评论,这似乎在其他答案中引起了极大的关注:)

\documentclass{article}
\usepackage{shortvrb}\MakeShortVerb{\|}
\usepackage{xinttools}

\makeatletter
\protected\def\abrsep{.\,}% maybe redefined even after \edef\foo{\abr{DPhil}}...
\protected\def\abrend{\futurelet\@let@token\abr@end}
\def\abr@end{\ifx.\@let@token\@\else.\@\fi}
\newcommand\abr[1]
   {\expandafter\@gobble\romannumeral0\xintapplyunbraced\abr@aux{#1}\abrend}
\def\abr@aux#1{\if1\ifnum`#1<`A 0\fi\ifnum`#1>`Z 0\fi1%
                   \expandafter\abr@sep
               \fi#1}%
\def\abr@sep{ \abrsep}
\makeatother

\begin{document}%\ttfamily
I've seen it in the \abr{OED}, and if located at end of a sentence
it will detect it automatically: \abr{OED}. There was no double dot.
Besides, TeX applied its end of sentence extra space.

\texttt{We can see it better with monospace font: \abr{OED}. See?}

\texttt{We can see it better with monospace font: \abr{OED}, See?}

I got a \abr{MSc}, a \abr{PhD} and even a \abr{DPhil}. Leniency ruled
in those days. 

{The abbreviation dots are added in a smart way, after the last
  lowercase letter following an uppercase letter:
  \abr{AaaaBbbbCccc}. But it is \emph{assumed} that the first letter is
  \abr{Uppercased}. That's it.}

\texttt{Notice that neither \abr{DPhil} nor \abr{PhilD} get \TeX\ to
  consider the inserted final dot as signaling  an end of
  sentence spacing after the dot, which is \abr{Good}. Isn't it?}

About expandability, the correct way for \LaTeX2e's users would be to use
|\protected@edef|, not a naked |\edef|; although nowadays some
\LaTeX2e\ users have heard about |\edef|, they might not know
about |\protected@edef|, which requires a cumbersome extra
|\makeatletter| for its usage. Anyway, none of that is described in
\textsc{Lamport} book, so I wonder if \LaTeX2e users are really
\emph{allowed} into using |\edef| to start with.

But as it seems they know about |\edef|, we as macro programmers need
better to use the e-\TeX's |\protected| prefix and not the \LaTeX2e
|\DeclareRobustCommand|, because users will not do |\protected@edef|.

This is what I have done here for a macro |\abrsep| (why haven't we all
used |\abbr| by the way?) which is deliberately |\protected|,
allowing it to be redefined at location of use, long after some macro
will have been defined via |\edef\foo{\abr{ABCDEFGH}}|.

\edef\foo{\abr{ABCDEFGH}}\texttt{\string\foo\ is \meaning\foo}

\edef\foo{\abr{AaaBccCcc}}\texttt{\string\foo\ is \meaning\foo}

The |\abrend| is also |\protected|, anyway as its expansion will be
context dependent (it detects if a dot follows), it had to not expand
in the |\edef|.
\end{document}

在此处输入图片描述

请注意,我的提案 v2 和 v3 仅适用于 ascii 大写字母,不适用于变音符号。

相关内容