9

I often find myself adding a lot of \textsl{} around inside \emph{} or \textit{} blocks because I find italicized digits to look too "showoffy" and "baroque" and to hinder legibility (I'm using $$ when the number has a mathematical sense, but this situation occurs in less technical texts like CVs, and such.).

Could someone help me write a renewcommand to automate this, or better, a single low level command that makes \emph, \itshape, \textit and friends choose slanted over italic for numbers? I'm not too familiar with the low level latex font selection system nor with a way to detect digits from regular letters.

Edit: MWE of what I need and what I want to avoid

\documentclass{article}
\begin{document}
He thought: '\emph{Why 1234567890 apples?}'
then he realized '\emph{ah yes, he has \textsl{1234567890} childs}'
\end{document}

gives:

I find the italicized version (first one) of 2,3,4 and 7 to look especially bad.

  • Could you please provide a little compilable example of what you want to get? Just one emphasized sentence with some slanted numbers in it. We will then try to reproduce the very same by one macro. Thanks. – LaRiFaRi Sep 16 '14 at 12:29
  • 1
    I think the “proper” solution is to use virtual fonts. However, virtual fonts are extremely difficult to create for common users. – Leo Liu Sep 16 '14 at 14:25
8

As I understand, there's no maths involved since you are writing just text. This solution is not perfect but may give you a start.

This solution replaces all the numbers with the \textsl{…} version. If you want any number not to be replaced, you must enclose it in {…}.

\documentclass{scrartcl}

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand \italicize { m }
  { \nathdwek_italicize:n { #1 } }
\cs_new_protected:Npn \nathdwek_italicize:n #1
 {
  \tl_set:Nn \l_tmpa_tl { #1 }
  \tl_map_inline:nn { 0123456789 }
   { \tl_replace_all:Nnn \l_tmpa_tl { ##1 } { \textsl { ##1 } } }
  \textit { \tl_use:N \l_tmpa_tl }
 }
\ExplSyntaxOff

\begin{document}
I want this with upright numbers. Like 1, or 2 or 123.\par
\emph{I want this with italics numbers. Like 1, or 2 or 123.}\par
\italicize{I want this with slanted numbers. Like 1, or 2 or 123.}
\end{document}

enter image description here

  • Would there be a simple (non repetitive) way to do this so that every known or unknown command that ends up needing italicized text behaves like this? A single custom command seems plenty enough, but just wondering. – nathdwek Sep 16 '14 at 13:02
  • 1
    You could change the definition of \emph or \textit to behave correctly (that is, with slanted numbers), and every command that uses those would work well. What you can't control with this command is \itshape or \em switches. If you post what is the problem (when do you need all italics to behave like this), we might be able to help. – Manuel Sep 16 '14 at 13:05
6

Very similar to Manuel's, but with regular expressions instead of mappings:

\documentclass{scrartcl}

\usepackage{xparse,l3regex}

\ExplSyntaxOn
\NewDocumentCommand \italicize { m }
  { \nathdwek_italicize:n { #1 } }

\tl_new:N \l_nathdwek_text_tl
\cs_new_protected:Npn \nathdwek_italicize:n #1
 {
  \tl_set:Nn \l_nathdwek_text_tl { #1 }
  \regex_replace_all:nnN { (\d+) } { \c{textsl}\cB\{\1\cE\} } \l_nathdwek_text_tl
  \textit { \tl_use:N \l_nathdwek_text_tl }
 }
\ExplSyntaxOff

\begin{document}
I want this with upright numbers. Like 1, or 2 or 123.\par
\emph{I want this with italics numbers. Like 1, or 2 or 123.}\par
\italicize{I want this with slanted numbers. Like 1, or 2 or 123.}
\end{document}

enter image description here

The search expression

(\d+)

means “find any cluster of one or more digits and remember it”; the replace expression

\c{textsl}\cB\{\1\cE\}

means “replace with \textsl{ followed by what you found (the \1 bit) followed by }.

An advantage is that 123 will be replaced by \textsl{123} instead of \textsl{1}\textsl{2}\textsl{3}.

  • Would there be a simple (non repetitive) way to do this so that every known or unknown command that ends up needing italicized text behaves like this? A single custom command seems plenty enough, but just wondering. – nathdwek Sep 16 '14 at 13:03
  • 3
    @nathdwek You can't do it in “free text”, unless you change the category code of the digits, which would break innumerable other things. The simplest thing is to use upright digits (in math mode) or a font that has pleasing italic digits. – egreg Sep 16 '14 at 13:05
  • May be reading the documentation would help, but asking here might be faster: why :nnN signatures in l3regex instead of the most commond :Nnn? By the way, \cB\{ means “character { (escaped in the regular expression as \{) with category code 1 (begin group, \cB)”, or what does it mean? – Manuel Sep 16 '14 at 13:16
  • Why :nnN instead of :Nnn? Ask Bruno Le Floch. ;-). \cB is a prefix meaning that the next character should have category code 1 (Beginning of group); similarly \cE means category code 2 (End of group). – egreg Sep 16 '14 at 13:17
  • 1
    @Manuel Comes down to module: the tl functions are 'token list focused' so (almost always) the first argument is a tl or tl var. On the other hand, the regex ones are 'regex focussed'. It's a reasonably solid convention that the first arg should 'agree' with the module if at all possible. – Joseph Wright Sep 16 '14 at 21:41
6

The search and replace solutions provided by Manuel and egreg are quite tricky. The restriction of those solutions is that, you can only change the text font in the argument of the command, without any special macro expansion.

The straightforward solution to the problem, however, is to use a mixed font. A mixed font can be dynamically set up in a modern TeX engine like XeTeX and LuaTeX, but the virtual font mechanism is also available in old TeX engines.

I will provide a XeTeX solution as well as an old virtual font solution, leaving the LuaTeX solution for LuaTeX experts.

1. A XeTeX Solution

See also: Font selection in XeTeX for specific characters

% !TeX program = xelatex
\documentclass{article}

\XeTeXinterchartokenstate=1
\chardef\CharNormal=0
% Test for old and new versions of the latex kernel
\ifx\e@alloc@intercharclass@top\@undefined
    \chardef\CharBound=255
\else
    \chardef\CharBound=\e@alloc@intercharclass@top % 4095 for new version of XeTeX engine
\fi
\newXeTeXintercharclass\CharNumbers
\XeTeXcharclass`0=\CharNumbers
\XeTeXcharclass`1=\CharNumbers
\XeTeXcharclass`2=\CharNumbers
\XeTeXcharclass`3=\CharNumbers
\XeTeXcharclass`4=\CharNumbers
\XeTeXcharclass`5=\CharNumbers
\XeTeXcharclass`6=\CharNumbers
\XeTeXcharclass`7=\CharNumbers
\XeTeXcharclass`8=\CharNumbers
\XeTeXcharclass`9=\CharNumbers
\newtoks\TokSetfont
\makeatletter
\TokSetfont={\begingroup
  \ifnum\strcmp{\f@shape}{\itdefault}=0
    \slshape
  \fi}
\makeatother
\XeTeXinterchartoks\CharNormal\CharNumbers=\TokSetfont
\XeTeXinterchartoks\CharBound\CharNumbers=\TokSetfont
\XeTeXinterchartoks\CharNumbers\CharNormal={\endgroup}
\XeTeXinterchartoks\CharNumbers\CharBound={\endgroup}

\usepackage{listings,color}

\begin{document}

\textit{Italic text can be 01234567890 different.}

\begin{itshape}
Text mode 123 in math equation:
\[
  xyz1234 \ne \textit{xyz1234}
\]
Complex macro expansion:
\def\foo{[123\noexpand\bar456]}
\def\bar{hello 789 hello}
\foo
\end{itshape}

\begin{lstlisting}[basicstyle=\itshape\color{blue}]
There is not any restriction for the mixed 1234567890 font:
qwerty001 bar456
\end{lstlisting}

\end{document}

enter image description here

2. Using Virtual Fonts

It is also possible to create a virtual font to mix cmti* and cmsl* fonts. Although it is much more complicated, a virtual font can work in TeX without any restriction.

  1. Create cmti10.pl via

    tftopl cmti10.tfm cmti10.pl
    
  2. Edit cmti10.pl, add these font mappings at the beginning of the file:

    (MAPFONT D 0 (FONTNAME cmti10))
    (MAPFONT D 1 (FONTNAME cmsl10))
    (CHARACTER C 0 (MAP (SELECTFONT D 1) (SETCHAR C 0)))
    (CHARACTER C 1 (MAP (SELECTFONT D 1) (SETCHAR C 1)))
    (CHARACTER C 2 (MAP (SELECTFONT D 1) (SETCHAR C 2)))
    (CHARACTER C 3 (MAP (SELECTFONT D 1) (SETCHAR C 3)))
    (CHARACTER C 4 (MAP (SELECTFONT D 1) (SETCHAR C 4)))
    (CHARACTER C 5 (MAP (SELECTFONT D 1) (SETCHAR C 5)))
    (CHARACTER C 6 (MAP (SELECTFONT D 1) (SETCHAR C 6)))
    (CHARACTER C 7 (MAP (SELECTFONT D 1) (SETCHAR C 7)))
    (CHARACTER C 8 (MAP (SELECTFONT D 1) (SETCHAR C 8)))
    (CHARACTER C 9 (MAP (SELECTFONT D 1) (SETCHAR C 9)))
    

    and save the file as cmtisl10.vpl.

  3. Create cmtisl10.tfm and cmtisl10.vf via

    vptovf cmtisl10.vpl
    
  4. You can use the mixed font now:

    \documentclass{article}
    \font\1=cmtisl10
    \begin{document}
    \1 Italic text can be 01234567890 different.
    \end{document}
    
  5. You may want to define a new font shape for the mixed font in NFSS. And of course there are more different sizes to handle too (repeat step 1 to 3).

    \documentclass{article}
    
    \DeclareFontShape{OT1}{cmr}{m}{itsl}{
            <-8>    cmtisl7
            <8-9>   cmtisl8
            <9-10>  cmtisl9
            <10-12> cmtisl10
            <12->   cmtisl12
          }{}
    \newcommand\itslshape{\fontshape{itsl}\selectfont}
    \DeclareTextFontCommand\textitsl{\itslshape}
    
    \usepackage{listings,color}
    
    \begin{document}
    
    \textitsl{Italic text can be 01234567890 different.}
    
    \begin{lstlisting}[basicstyle=\itslshape\color{blue}]
    There is not any restriction for the mixed 1234567890 font:
    qwerty001 bar456
    \end{lstlisting}
    
    \end{document}
    

enter image description here

See also: How to create a virtual font?

  • Hey is it possible that a recent release of xelatex broke this solution or something? I just started to get braces-related errors in documents which use it. – nathdwek Feb 27 '17 at 16:16
  • @nathdwek: fixed. – Leo Liu Mar 21 '17 at 2:54
  • Thanks a lot! However, this didn't seem to work out of the box as I get ! Undefined control sequence. l.22 \chardef\CharBound=\e @alloc@intercharclass@top % 4095 for new versi.... Using =4095, it works as expected. – nathdwek Mar 22 '17 at 14:30
  • @nathdwek: You may need to update your TeX distribution. – Leo Liu Mar 23 '17 at 5:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.