10

I need to use non-breaking spaces in proper name initials, e.g.

J.~W.~Bush

Any way to make LaTeX replace regular spaces with non-breaking ones for such cases? Or would I better preprocess my tex files with some regexp/script?

9
  • A script (or manual fix) is probably a better solution as I don't think this is going to be very easy with TeX. Mar 19, 2014 at 19:59
  • This helped me with spaces before dashes, so I thought somebody could have a similar solution for initials based on @ifnextchar. But that wouldn't be easy indeed.
    – Andy K.
    Mar 19, 2014 at 20:30
  • I assume this is in the context of a bibliography? bibtex or biblatex?
    – cslstr
    Mar 19, 2014 at 21:05
  • @cslstr Not only, I need it to be like this everywhere in my document. And I use bibtex.
    – Andy K.
    Mar 20, 2014 at 3:05
  • 1
    Yes you can do it (similar to the linked question) but dont:-) making dash active so that it can adjust spacing has the potential to break things but it is a well worn path: many babel languages make ascii punctuation characters active to adjust space around them, so by now most packages/documents can cope. If you make space active then you have a real chance of breaking everything. You can make simple examples sort of work but the chance of it working reliably on real documents loading real packages from ctan isn't that great. Apr 3, 2014 at 10:39

2 Answers 2

8
+50

I added support for initials to my package luavlna. This package uses luatex node processing callbacks for language dependent insertion of non-breaking spaces after one letter words and initials.

Example:

\documentclass{article}
\usepackage{fontspec}
\usepackage[czech, english]{babel}
\usepackage{luavlna}
\preventsinglelang{czech}
\begin{document}
  \preventsingledebugon
D. E. Knuth, Ch. Somebody. \selectlanguage{czech} A. Dvořák, 
name in horizontal box \hbox{Č. Zíbrt}, Ř. Jelen \preventsingleoff C. Někdo, 
\preventsingleon Ř. Jelen, Ch. Josef, CH. Thisworkstoo

\end{document}

enter image description here

You can see that Ch is used as one letter in Czech. If you don't want language sensitive processing, set default language with \preventsinglelang{languagename} and rules for given language will be used in the whole document.

You can turn off the processing with \preventsingleoff and resume it latter with \preventsingleon

luavlna isn't on CTAN yet, I have to make language detection more robust, so you can download it from github and install in to your local TEXMFHOME dir if you want to use it.

12
  • It looks great! Is there a possibility to set an exception, something similar to \mbox{one two} when dealing with hyphenation?
    – Malipivo
    Apr 8, 2014 at 20:09
  • @Malipivo do you mean possibility to prohibit processing of text in command argument, or possibility to exclude certain letters from processing?
    – michal.h21
    Apr 8, 2014 at 20:26
  • My question is close to the first option, if there is an option of turning process on and off directly in document, if needed. I think that we usually wish to process "Ch. Somebody" no matter of language we actually use, that's just my opinion.
    – Malipivo
    Apr 8, 2014 at 20:35
  • @Malipivo I added new command \preventsinglelang for using only one language settings for whole document, if one wants this behaviour
    – michal.h21
    Apr 9, 2014 at 11:13
  • That's excellent, you are fast!
    – Malipivo
    Apr 9, 2014 at 11:39
2

EDITED to catch more cases (and examine failure modes)

I concur with David's recommendation not to make the space active. So the approach I take here is to make the dot active, with the ability to turn the feature on (\initialsON) and off (\initialsOFF) as needed, if it is found to interfere with something else.

The choice of an active dot will bring with it a severe limitation, we will find, in that an active dot occurs after the initialed letter, and so it becomes impossible to definitively know if an initial preceded the active dot. But we can nonetheless make interesting progress towards that goal.

With my original solution (the path that follows \specdothelper), the detection scheme was only triggered on initials typed without spaces, such as J.W.Bush, such that it converted a sequence .X into .~X if there was no space between the . and the X, where X represents any capital letter. This compressed syntax may take a little getting used to or even be outright unacceptable to many users.

With this latest REVISION (and my first successful use of \futurelet, yippee), I now also can search for the syntax . X., where there is a space after the first dot, then a capital letter followed by a dot. If this sequence is found, it is converted into .~X. And if and only if initials have been lately found, the sequence . Xx will assume the last name has been located and convert it to .~Xx. Thus, in a sequence like J. Z. A. Bush, it will catch all three spaces, converting them into hard spaces.

By using the dot as the active character, however, I am prevented from knowing whether the character prior to the dot was an initial, and can only try to discern it by looking forward in the input stream. In the example given by G. Washington, the problem with the first dot is that, without a pattern of initials already being established, the forward-looking . Wa set of characters could be the beginning of a sentence rather than a name following the initial. And so this important case is missed.

In this EDIT, I've reduced the discussion hereafter on the guts of the logic. I'll only summarize and say that the challenge areas were spaces, \pars, and repeated dots .. (since dots are active characters), which required special treatment. Also, the new logic with this revision follows the \foundspace macro.

Places where the compressed (no-space) syntax will fail are shown in my MWE. If a last name does not begin with a capital is one case, such as C.deLune. Also, if a url has a dot followed by a capital letter, this would cause a space to be inserted (though \initialsOFF should be used before setting such unconventional text as url's).

When employing the revised syntax where spaces remain between the initials in your LaTeX file, there are three known failure modes (one of them crucial). The first, discussed above at some length, is the case of a single initial followed by a last name. The second failure is when a sentence starts with an initial (though this is bad grammar). The third case of failure is when a sentence ends in what looks like initials, such as U. S. A. In this case, the first word of the next sentence is perceived as the last name, and a hard space is inserted.

When using the compressed syntax, the requirement to enter initials without spaces in your document may be wholly unacceptable to many users. And in the normal expanded syntax, the inabilty to detect a lone initial in a sequence greatly limits the usefulness of this approach.

In the MWE that follows, I have purposely defined my hard space \HS as a \rule to make it visible. To use this code in its intended way, that definition should be replaced with the one that defines it as a hard space (or a skinny space).

\documentclass{article}
\usepackage{ifnextok}
\def\HS{\rule{.66ex}{1ex}}% TO DEMONSTRATE WHERE ACTIVE
%\def\HS{\,}% FOR NARROW SPACE
%\def\HS{~}% FOR NORMAL HARD SPACE
\let\svdot.
\def\knowninit{F}
\makeatletter
\def\specdot{\svdot\IfNextToken\@sptoken{\foundspace}%
  {\gdef\knowninit{F}\specdothelper}}
\long\def\foundspace#1{\IfNextToken\@sptoken{ #1\gdef\knowninit{F}}%
  {\def\savefirst{#1}\lookatsecond}}
\def\lookatsecond{\futurelet\secondchar\processsecond}

\long\def\specdothelper#1{%
  \if\svdot#1%
    \svdot%
  \else%
    \ifx#1\par%
      \par%
    \else%
      \ifnum`#1>`@\ifnum`#1<`[\HS\fi\fi#1%
    \fi%
  \fi%
}
\makeatother

\catcode`.=\active
\def\processsecond{%
  \ifx\secondchar.%
    \HS\gdef\knowninit{T}%
  \else%
    \if T\knowninit%
      \ifnum\expandafter`\savefirst>`@\ifnum\expandafter`\savefirst<`[\HS\else%
        { }\fi\else{ }\fi%
    \else%
      { }%
    \fi%
    \gdef\knowninit{F}%
  \fi%
  \savefirst%
}
\def\initialsON{\catcode`.=\active\def.{\specdot}}
\def\initialsOFF{\catcode`.=12\let.\svdot}
\catcode`.=12
\parskip 1ex
\begin{document}
\footnotesize
\noindent ON\initialsON

Fully spaced initials J. Z. A. Bush being tested, and here we check double and single initials: 
J. Q. Adams and G. Washington.  A single initial cannot be discerned because the dot after 
the G cannot know if the prior letter is an initial and no other initials follow the dot.

U. S. A. is OK, since ``is'' is not capitalized.

We can be fooled by U. S. Olympic Team, in that it considers ``Olympic'' to be the last name.
Can also be fooled if sentence ends in the U. S. A. The new sentence starts with a hard-space, 
with ``The'' as the last name.  Leaving out the spaces will fix U.S.A.  If no spaces are wanted,
\initialsOFF U.S.A. \initialsON 
can be gotten by temporarily turning initials OFF.

Compressed or uncompressed C.deLune and  C. de Lune fail to insert a hard space, because 
``d'' is not a capital letter.

Unspaced combinations: 3.2, a.b, J.Z.A.Bush, and G.Washington being successfully tested
 here, with non-capital letters screened out.

Testing.. successive... dots is OK... Unless the sentence ends with odd number of dots, then 
a space immediately followed by a dotted initial... S. Segletes would never start a sentence 
with an initial.  It is poor grammar in the first place. 

\noindent\hrulefill\\
OFF\initialsOFF (This was the raw text being processed)

Fully spaced initials J. Z. A. Bush being tested, and here we check double and single initials: 
J. Q. Adams and G. Washington.  A single initial cannot be discerned because the dot after 
the G cannot know if the prior letter is an initial and no other initials follow the dot.

U. S. A. is OK, since ``is'' is not capitalized.

We can be fooled by U. S. Olympic Team, in that it considers ``Olympic'' to be the last name.
Can also be fooled if sentence ends in the U. S. A. The new sentence starts with a hard-space, 
with ``The'' as the last name.  Leaving out the spaces will fix U.S.A.  If no spaces are wanted,
U.S.A. 
can be gotten by temporarily turning initials OFF.

Compressed or uncompressed C.deLune and  C. de Lune fail to insert a hard space, because 
``d'' is not a capital letter.

Unspaced combinations: 3.2, a.b, J.Z.A.Bush, and G.Washington being successfully tested
 here, with non-capital letters screened out.

Testing.. successive... dots is OK... Unless the sentence ends with odd number of dots, then 
a space immediately followed by a dotted initial... S. Segletes would never start a sentence 
with an initial.  It is poor grammar in the first place. 
\end{document}

enter image description here

3
  • These ideas are inspiring!
    – Malipivo
    Apr 9, 2014 at 4:18
  • @Malipivo I realize "inspiring" is a polite way of saying "thanks for trying" 8^) I just wanted you to know I've made some additional progress, but flaws remain. But it has been an interesting exercise for me. Thanks for the challenge. I wonder how the lua solution performs on some of my problem situations, like as seen in the U. S. The next sentence or sentence is done. S. Segletes starts the next sentence or C. deLune or U. S. Olympic Team? Apr 10, 2014 at 0:51
  • It was my first bounty, I am still looking for a way how I could split the points. I owe you one. Yes, that's the reason I was looking for adding a list of exceptions or a way how to turn on and off the process, there are many more examples: V. van Gogh, L. van Beethoven, J. von Mises, Ch. A. J. M. de Gaulle, L. da Vinci. I believe that processing TeX/Bib file externally (as program vlna does) is the best way. We would not touch the original file (then we could process HTML/JS or other files by changing one letter ~->&nbsp;) and there would be a chance to make a backup.
    – Malipivo
    Apr 10, 2014 at 4:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .