latex中字母大小写转换实践


要点概览

  1. 目的

    • 实现常用的字母大小写转换,可以用于常规的字符串处理以及biblatex参考文献样式定义
    • 全部大写/全部小写
    • 句首大写(句首字母大写其它不变,句首字母大写其它小写)
    • 词首大写(句中每个单词的首字母大写,其它小写)
  2. 运行环境
    • tex环境:texlive 2017
    • 词首大写方法:(a)利用mfirstuc中的命令; (b)定义宏并利用biblatex中命令
  3. 注意点:
    • biblatex中处理域格式的命令的层级要正确

之所以研究字母大小写的转换,最直接的原因是在定制biblatex参考文献样式的过程中,某些域的存在大小写要求。尽管这种要求可以通过在bibtex数据源文件输入时候完成,但对于参考文献样式定制者来说,能够通过格式定义来简化用户的输入是一件很有意义的事情。事实上latex内核提供字母大小写转换命令,但这是整体的转换,对于句首和词首大小写转换则没有提供,这就需要通过定义宏实现,而有些宏包提供有这些功能的宏。据我了解,biblatex很早就提供了句首大写命令,而较新的宏包mfirstuc提供了词首大写命令。在参考文献格式定制过程中,我首先测试了mfirstuc提供的命令,在域格式定义中使用出现错误。于是自己定义了一个宏来实现,但同样出错。在咨询biblatex作者后,发现是这是使用方式问题,也就是说无论是mfirstuc提供的命令的命令还是自定义的命令都是可以使用的。

下面我们通过实践来总结一下latex中的字母大小写转换:

整体大小写转换

latex提供了两个基本的大小写转换命令,\MakeUppercase\MakeLowercase分别将参数整体转换为大写和小写。

\documentclass{article}
\usepackage{etoolbox,xstring,mfirstuc,textcase}
\usepackage[backend=biber,style=numeric]{biblatex}%
\addbibresource[location=local]{egbib.bib}
\begin{document}
\MakeUppercase{Electronic resources : selection and $x \neq Y$}\par
\MakeLowercase{Electronic resources : selection and $x \neq Y$}\par
\MakeTextUppercase{Electronic resources : selection and $x \neq Y$}\par
\MakeTextLowercase{Electronic resources : selection and $x \neq Y$}
\end{document}

结果为:

ELECTRONIC RESOURCES : SELECTION AND X ̸= Y
electronic resources : selection and x ̸= y
ELECTRONIC RESOURCES : SELECTION AND x ̸= Y
electronic resources : selection and x ̸= Y

注意:其中还给出了textcase宏包提供的两个替代命令:\MakeTextUppercase\MakeTextLowercase
其差别在于,textcase提供的这两个命令不会将参数中的数学公式转换大小写。

另外latex3提供了titlecase功能,可以利用使用命令:

\text_lowercase:n
\text_uppercase:n {⟨tokens⟩}
\text_uppercase:nn {⟨language⟩} {⟨tokens⟩}
\text_uppercase:n
\text_titlecase:n
\text_titlecase_first:n
\text_lowercase:nn
\text_uppercase:nn
\text_titlecase:nn
\text_titlecase_first:nn

句首字母转换为大写

句首字母转换为大写,biblatex宏包和mfirstuc宏包都有提供命令。

biblatex提供了:

  • \MakeCapital{text},类似于\MakeUppercase,但仅将text的第一个可打印字符转换为大写
  • \MakeSentenceCase{text},将text参数转换为句子模式,即字符串中的第一个单词首字母大写而剩下其他部分转换为小写。

mfirstuc提供了:

  • \makefirstuc,提供了类似\MakeCapital的功能。

    \documentclass{article}
    \usepackage{etoolbox,xstring,mfirstuc,textcase}
    \usepackage{amsmath,amsfonts,amssymb,amsthm}
    \usepackage[backend=biber,style=numeric]{biblatex}%
    \addbibresource[location=local]{egbib.bib}
    \begin{document}
    \MakeCapital{electronic resources : Selection and x ≠ Y x \neq Y x​=Y}\par
    \MakeSentenceCase{electronic resources : Selection and x = y x= y x=y}\par% x ≠ Y x \neq Y x​=Y
    \makefirstuc{electronic resources : Selection and x ≠ Y x \neq Y x​=Y}
    \end{document}

结果为:

Electronic resources : Selection and x ̸= Y
Electronic resources : selection and x = y
Electronic resources : Selection and x ̸= Y

可以看到,首字母由小写变为大写,\MakeSentenceCase命令还将句子中的大写转换为小写,注意,在\MakeSentenceCase的参数中,一些数学符号命令会导致错误。

词首字母转换为大写

将词首字母转换为大写有两种方法,一种是使用mfirstuc提供的\capitalisewords命令,另一种是自定义命令。使用\capitalisewords命令比较简单,放到后面说明,下面我们先介绍自定义命令的方式。

首先来分析一下要定义的命令需要实现的功能:它能接受一个句子(字符串),并能根据句中空格解析不同的词,并将词首字母大写。

本着从易到难的思路,我们从最简单的例子出发,假设一个句子只有两个词,中间由空格隔开,那么对其进行转换的话,我们可以定义一个很简单的命令:

\documentclass{article}
\usepackage{etoolbox,xstring,mfirstuc,textcase}
\usepackage{amsmath,amsfonts,amssymb,amsthm}
\usepackage[backend=biber,style=numeric]{biblatex}%
\addbibresource[location=local]{egbib.bib}
\begin{document}\def\strtowds#1 #2{\MakeSentenceCase{#1} \MakeSentenceCase{#2}}%\strtowds{abc cn} %error!%\strtowds{abc}{cn} %error!\strtowds abc cn\def\abc{abc cn}\expandafter\strtowds\abc%\expandafter\strtowds{abc cn} %error!
\end{document}

其中\strtowds命令解析一个由空格分隔的字符串,并利用\MakeSentenceCase命令将解析后的两部分字符串首字母大写。注意该命令的参数分界和输入流,当其后跟的参数输入流,正确的方式是\strtowds abc cn,当需要在其后使用一个宏所代表的字符串时,则需要利用\expandafter将该宏展开为输入流。

递归解析输入流设计宏

根据这种思路,我们写出一个宏,首先能将输入参数转换为一个输入流,然后对这个流进行解析:

\def\strtowdudf#1{%\edef\coefone{#1}%%\meaning\coefone\expandafter\stowparse@udf\coefone%}

其中\strtowdudf宏将输入参数转换为输入流后,由\stowparse@udf宏进行解析。这种思路是很正常的,那么下面需要将\stowparse@udf宏实现出来。我们知道解析是通过字符串中的空格进行的,也就是可以将其作为参数的分界符。根据空格对分界后的两部分进行分别处理,其中第一部分进行大小写转换操作,第二部分继续进行解析,于是我们写出为:

\def\stowparse@udf#1 #2\par{\def\coefone{#1}\def\coeftwo{#2}%%\par\meaning\coefone \meaning\coeftwo\ifx\coeftwo\@empty%\MakeSentenceCase{#1 }\par%\else%\MakeSentenceCase{#1 }%\edef\coeftwos{#2\par}%\expandafter\stowparse@udf\coeftwos%\@empty%\par\fi%}

通过测试,发现当使用\par作为第二个参数后的分界时,宏能正常工作。\stowparse@udf宏读取其后的以\par结尾的输入流进行解析,当输入流中存在空格,那么空格前面内容定义为\coefone,后面内容定义为\coeftwo,当\coeftwo不为空时,则继续利用\stowparse@udf对其进行解析。需要注意到这种利用\par作为输入流结尾分界的宏定义,利用了\par命令在行末自动插入空格,并且解析需要将\par从输入流中丢出,因此使用\strtowdudf命令时,其后要跟换行,否则就会出错。这也就说明这个宏的设计其实是有问题的。而这个问题的根子还在于\strtowdudf的设计,主要是它没有对输入参数做进一步的处理,以得到适合解析的输入流。我们观察,解析过程中剩下一个词的情况,比如abc cn def ghi字符串解析到剩下ghi时,这时#2\par就是ghi\par,那么再对其进行解析时必须要存在空格,否则无妨解析,这里之所以能工作是因为换行自动插入了空格。所以当结尾分界不使用\par而使用其它任何字符时,都会出错。因此可以知道,要时\stowparse@udf能够正确的解析,那么其输入流中必须要有空格,因此我们重新设计\strtowdudf,使的\stowparse@udf的输入流中总是带有空格,而不需要某些情况下需要换行提供。

\documentclass{article}
\usepackage{etoolbox,xstring,mfirstuc,textcase}
\usepackage{amsmath,amsfonts,amssymb,amsthm}
\usepackage[backend=biber,style=numeric]{biblatex}%
\addbibresource[location=local]{egbib.bib}
\makeatletter\newrobustcmd{\strtowdudfa}[1]{%\edef\coefone{#1 $}%%注意这里的空格对于定界很关键%\meaning\coefone\expandafter\stowparsea@udf\coefone%}\def\stowparsea@udf#1 #2${%\par%\@empty\def\coefone{#1}\def\coeftwo{#2}%%\par\meaning\coefone \meaning\coeftwo\ifx\coeftwo\@empty%\MakeSentenceCase{#1 }%\else%\MakeSentenceCase{#1 }%\def\coeftwos{#2$}%\expandafter\stowparsea@udf\coeftwos%\@empty%\par\fi%}
\makeatother
\begin{document}
\strtowdudfa{abc cn}\par
\strtowdudfa{abc cn def ghi}
\end{document}

结果为:

Abc Cn
Abc Cn Def Ghi

其中,\strtowdudfa将输入参数末尾加入一个空格并用$符号作为结尾分界。\stowparsea@udf则以$符号作为结尾分界进行解析。通过测试这个宏完全满足了提出的要求。

利用xstring宏包的字符串处理功能设计宏

上一小节,我们直接根据输入流递归解析来实现了目的。如果从编程更容易的角度,其实可以利用专门处理字符串的宏包xstring来实现宏的设计。

xstring宏包提供了命令\StrPosition命令可以返回字符串中某一字符的位置,而\StrSplit命令可以将字符串根据位置分割成两个部分。我们先设计一个简单的宏:

\newcommand\strxparse[1]{
\StrPosition{#1}{ }[\posspace]%name is a cs
\StrSplit{#1}{\posspace}{\stra}{\strb}
\MakeSentenceCase{\stra}\MakeSentenceCase{\strb}}
\strxparse{abc edf}

\strxparse宏首先得到输入参数中空格的位置\posspace,然后根据该位置将其分为两个部分,并对两个部分进行\MakeSentenceCase处理。通过测试表明利用\StrPosition\StrSplit命令是可行的。那么如果要处理多个词,就需要进行循环,所以我们要先验证一下能否实现循环,于是我再设计一个宏:

\newcommand\strxparsea[1]{
\edef\strtobeparse{#1}
\StrPosition{\strtobeparse}{ }[\posspace]%name is a cs
\StrSplit{\strtobeparse}{\posspace}{\stra}{\strb}
\MakeSentenceCase{\stra}\MakeSentenceCase{\strb}}
\strxparsea{abc edf}

该宏与前一个宏的差别在于将输入参数表示为\strtobeparse,该宏能正常工作说明可以对\strtobeparse表示的字符串进行分割,那么当循环时,只要将要需要解析的字符串不断地定义为它,那么就能实现循环。下面我们利用tex中loop命令来实现循环:

\documentclass{article}
\usepackage{etoolbox,xstring,mfirstuc,textcase}
\usepackage{amsmath,amsfonts,amssymb,amsthm}
\usepackage[backend=biber,style=numeric]{biblatex}%
\addbibresource[location=local]{egbib.bib}%\newcounter{countA}
\newif\ifemptystr
\newcommand\strxparseb[1]{\edef\strtobeparse{#1}%\setcounter{countA}{0}\loop%\StrPosition{\strtobeparse}{ }[\posspace]%name is a cs\StrSplit{\strtobeparse}{\posspace}{\stra}{\strb}%%\stepcounter{countA}%%\arabic{countA}\meaning\strtobeparse\meaning\posspace\meaning\stra\meaning\strb\par %\meaning\emptystr%\ifnumequal{\value{countA}}{3}{\emptystrfalse\MakeSentenceCase{\strb}}{\emptystrtrue\MakeSentenceCase{\stra}}%\IfStrEq{\stra}{}{\emptystrfalse\MakeSentenceCase{\strb}}{\emptystrtrue\MakeSentenceCase{\stra}}%\ifemptystr%\let\strtobeparse=\strb%%\arabic{countA}\meaning\strtobeparse\par\repeat}
\begin{document}
\strxparseb{abc cn}\par
\strxparseb{abc cn def ghi}
\end{document}

其中,\strxparseb首先将输入参数表示为\strtobeparse,接着获取其中第一个空格的位置,利用该位置将其分割为\stra\strb,当\stra为空时,表示解析到最后一个词(注意当\StrPosition没有找到字符时,返回0,且\StrSplit命令从位置0分割时,分割得到第一部分为空),则利用\emptystrfalse将判断表达式设置为false,否则为true,表示循环继续,设置\strtobeparse=\strb继续分割。其中注释掉的部分是利用计数器来测试指定数量的循环。

上面MWE得到的结果为:

Abc Cn
Abc Cn Def Ghi

利用mfirstuc宏包的提供的命令

mfirstuc宏包提供的命令\capitalisewords可以实现词首大写功能。同时该宏包还可以利用\MFUnocap指定某些词不用进行大写。比如:

\documentclass{article}
\usepackage{etoolbox,xstring,mfirstuc,textcase}
\usepackage{amsmath,amsfonts,amssymb,amsthm}
\usepackage[backend=biber,style=numeric]{biblatex}%
\addbibresource[location=local]{egbib.bib}
\begin{document}
\capitalisewords{in the long run, We would like to use all-caps fonts}\par
\MFUnocap{to}
\MFUnocap{the}
\MFUnocap{in}
\capitalisewords{in the long run, We would like to use all-caps fonts}\par
\capitalisewords{abc cn}\par
\capitalisewords{abc cn def ghi}
\end{document}

结果为:

In The Long Run, We Would Like To Use All-caps Fonts
In the Long Run, We Would Like to Use All-caps Fonts
Abc Cn
Abc Cn Def Ghi

在biblatex参考文献样式中应用大小写转换命令

在biblatex参考文献样式定制中,常常需要进行域格式定义。比如:

%\DeclareFieldFormat{booktitle}{\strxparseb{#1}}%\strxparseb\strtowdudfa\capitalisewords\MakeCapital\MakeSentenceCase
\DeclareFieldFormat{booktitle}{\mkbibitalic{#1}}%\mkbibemph

即对booktitle域进行一个格式处理,上述的定义中,测试发现\mkbibemph等biblatex提供的命令没有问题,但是新定义的\strxparseb\strtowdudfa,以及\capitalisewords都会报错。错误提示为:

! Missing \endcsname inserted.
<to be read again>\protect
1.41 \printbibliography[heading=bibliography]

我开始以为这是宏的处理不适应于biblatex,于是希望从biblatex.STY中寻找答案。但在深入研究之前决定咨询一下biblatex作者,很快作者给了回复,问题出在了域格式的使用上。

事实上,biblatex通过多层域格式来实现复杂的功能,比如这里实现一个斜体效果,但对于booktitle域还有针对该域本身的更低一层的域格式titlecase。比如:

{\printtext[booktitle]{%\printfield[titlecase]{booktitle}%\setunit{\subtitlepunct}%\printfield[titlecase]{booksubtitle}}%\newunit}

biblatex作者指出,直接针对域内容处理的格式应该在titlecase域格式中设置。显然,答案就是这样,在其中使用就没有问题。而且测试biblatex提供的\MakeSentenceCase命令,它放在booktitle域格式中同样也会出错,这说明了同样的问题。

于是重新定义如下:

\DeclareFieldFormat{bkttlcase}{\strtowdudfa{#1}}%\capitalisewords\strtowdudfa\renewbibmacro*{booktitle}{%\ifboolexpr{test {\iffieldundef{booktitle}}andtest {\iffieldundef{booksubtitle}}}{}{\printtext[booktitle]{%\printfield[bkttlcase]{booktitle}%\setunit{\subtitlepunct}%\printfield[titlecase]{booksubtitle}}%\newunit}%\printfield{booktitleaddon}}

如此实现了需要的词首字母大写需求。但是标题内全部单词首字母大写的方式其实在英文出版中并不常见,而通常是其它两种模式即句子模式和标题模式,句子模式首字母大写其它小写,标题模式则大写nouns, pronouns, adjectives, verbs and adverbs等词首字母,其它如articles, conjunctions and short prepositions则不大写。这种标题模式可能是我们需要使用的,但全部单词首字母大写是达不到这种要求的,显然真正的需求是根据需要大写单词首字母。而这可是使用\capitalisewords配合\MFUnocap命令实现,利用\MFUnocap枚举所有不需要大写的单词,然后使用\capitalisewords实现句首大写以及其它没有限制的单词的首字母大写,尽管这使用起来并不是那么的方便。

当然还有更简单的不用处理的方式,即前面说过的,在bib源文件中由参考文献用户自己定义大小写,而样式根据定义大小写原样输出。

小结

通过上述实践,完成了latex中字符大小写转换测试,并且在biblatex参考文献样式定制中进行了应用。
在整个实践过程中,不仅了解了多个宏包的提供的功能,也更进一步理解了tex的宏定义机制。

参考资料

[1]. Philipp Lehman, Philip Kime, Audrey Boruvka and JosephWright. The biblatex Package.
[2]. Philipp Lehman, Joseph Wright. The etoolbox Package.
[3]. David Carlisle. The textcase package.
[4]. Nicola L.C. Talbot. mfirstuc.sty v2.04: uppercasing first letter
[5]. Latex help e-book
[6]. LATEX2e: An unofficial reference manual
[7]. D. E. KNUTH. The TEXbook. trans by xianxian & zoho.
[8]. Victor Eijkhout. TEX by Topic, A TEXnician’s Reference. trans by zoho.
[9]. Make the first letter of each word uppercase in sentence
[10]. various case styles-Headings and publication titles

##ps:

##history:
v1.0 20171112 完成基本内容

latex中字母大小写转换实践相关推荐

  1. c语言中字母大写转小写,C语言中字母大小写转换的简单操作

    大写字母要转换小写字母,要怎么操作呢?而在C语言开发中,我们经常会遇到这样或者那样的问题,别着急,爱站技术频道为你细细道来C语言中字母大小写转换的简单操作. C语言tolower()函数:将大写字母转 ...

  2. eclipse中字母大小写转换快捷键(备忘)

    eclipse中字母大小写转换快捷键(备忘) Ctrl+Shift+X 转为大写 Ctrl+Shift+Y 转为小写 该快捷键是可以在eclipse中自定义的,但并不推荐自定义:

  3. c语言中字母大小写转换的两种办法

    起因: 牛客网一道题,需要按行输入多组字母,然后按行输出其转换大小写后的字母,我们来探讨一下. 分析: 有两个要点需要注意,一是要按行多组输入,二是要字母大小写转换.首先是按行多组输入,我们可以用wh ...

  4. php将字母大写转小写,php中字母大小写转换函数_PHP教程 - strtolower

    ...注解.可以通过 commit记录查看已添加的注解. strtolower string strtolower ( string $string ) 将字符串转换成小写字符. strtoupper ...

  5. Oracle 中字母大小写转换

    开发工具与关键技术:Oracle sql * plus PLSQL Developer 作者:唐国铭 撰写时间:2019年03月31日 在做练习过程中总会遇到一些需求是获取某一字段里的某一个字母,无论 ...

  6. Eclipse中字母大小写转换,及常用快捷键

    大写转换小写 ctrl+shift+y 小写转换大写 ctrl+shift+x 其他常用的快捷键  1. ctrl+shift+r:打开资源 这可能是所有快捷键组合中最省时间的了.这组快捷键可以让你打 ...

  7. SQL 中字母大小写转换

    大写字母改成小写字母 update 表名 set 字段名a= Lower(字段a) 小写字母改成大写字母 update 表名 set 字段名a= upper(字段a) 转载于:https://www. ...

  8. eclipse中字母大小写转换快捷键

    ctrl+shift+x   转为大写     ctrl+shift+y   转为小写

  9. latex中英文字母大小写变换再讨论

    latex中英文字母大小写变换再讨论 在英文的习惯中,特别是标题等内容中,大小写有一些常用的习惯. 在latex中如果正常输入英文段落和语句,通常作者会注意使用这些习惯,因此通常不太会需要太多的字母大 ...

最新文章

  1. (学)DEV在设计界面部分组件显示红叉并报错的问题
  2. php yanzhengm,ThinkPHP 在使用M方法(不创建模型类)时实现自动验证与自动填充
  3. linux系统备份路径,linux系统备份恢复到本机或是别的机器上
  4. 如何在管理员页面查看知识星球活跃度和更多明细
  5. 苏宁大数据怎么运营_18个“硬核”数据告诉你,苏宁大数据如何火力全开护航618!...
  6. 【李宏毅2020 ML/DL】P75 Generative Adversarial Network | Conditional GAN
  7. 仅需10道题轻松掌握Python文件处理 | Python技能树征题
  8. Q106:Linux系统下安装编译PBRT-V3
  9. 机器学习面试题60~100
  10. mac 删除磁盘图标_如何在Mac上更改硬盘图标
  11. 经济学和金融学的区别
  12. 将7z分卷合并成一个7z文件,然后就可以使用7z或rar软件等打开
  13. python爬虫脚本 初级入门爬虫英雄联盟所有皮肤_用Python爬取英雄联盟(lol)全部皮肤...
  14. 别忘了看,今年中秋月亮“瘦”了!网友扎心了:我还没瘦…
  15. typedef和typename的区别
  16. 浏览器乱码的原因是什么?如何解决?
  17. FOC之park变换推导笔记
  18. 古籍制作 - 古书制作 - 古籍制作工具 - 古籍制作软件 - 古籍修复工具 -古籍修复软件 - 古书制作软件 - 古书修复工具 - 古籍修复软件 -古籍修复软件
  19. java如果智慧小区物业系统,基于ssm\springboot智慧小区物业管理平台实现
  20. 无法加快开发用于机械制造的电气系统?选对设计软件至关重要!

热门文章

  1. [USACO09MAR]Moon哞哞叫Moon Mooing(模拟)
  2. python用途适合做什么生意好赚钱_2019年学Python10大理由:功能多、资源多、挣钱多!...
  3. 地暖品牌:保利地暖管道系统介绍
  4. Java替换文件名字符串中的特殊字符,避免创建文件失败
  5. 我是如何年薪五十万的
  6. 笔记本html到电视,互联网资讯:笔记本如何连接电视(通过HDMI)
  7. content-box和border-box区别
  8. BFS广度优先遍历寻找最短路径(超详细实现过程)
  9. Verilog——一个简单仲裁器的实现
  10. 裸辞4个月,面试了30家公司,终于找到理想工作了