This question led to a new package:
selnolig

One of the major attractions -- for me at least -- of typesetting my papers in (La)TeX is its automated and fully transparent use of typographic ligatures. However, as Knuth pointed out in the TeXbook, it is sometimes necessary to disable or suppress ligatures in order to either improve a word's legibility (Knuth uses the word shelfful as an example) or so as not to inadvertently change its meaning, which is especially important in some non-English European languages, such as German, which have lots of compound words (viz., Sauf{}laden vs. Sau{}fladen, and Chef{}innenleben vs. Chefinnen{}leben).

Here's my question, which is related to a question I posed in comp.text.tex about half a year ago but which didn't generate any good answers: If one were to compile a list of words for which ligatures should be suppressed, is there a way to program TeX (possibly/likely LuaTeX) not to use ligatures for these words? Please note that I am not looking to suppress ligatures globally for the entire document, but only those that occur in certain words.

Suppose one had a list of words such as

shelf{}ful, self{}ish, self{}less, half{}life, shelf{}life, dwarf{}like, 
waif{}like, wolf{}like, half{}line, roof{}line, Pfaff{}ian, cuff{}link, 
off{}load, off{}line, wolf{}fish, chaf{}finch, saf{}flower

Is there a way to pass this list to TeX and to instruct it to either not insert a ligature at all (as in shelfful and shelflife) or to use only a two-character rather than a three-character ligature (for Pfaffian and offline, say)? Possibly, this no-ligation list would also indicate to TeX the method by which the ligation should be suppressed. To suppress a ligature, one can insert a pair of braces, {}, an italics correction, \/, or a zero-width kern, \kern0pt. However, these methods do not in general produce the same outcome, especially in the case of the fl character pair, and it may therefore be desirable to instruct TeX exactly which non-ligation method it should employ when it encounters a word on the no-ligation list.

By the way, observe that the no-ligation instances for all words in the above list correspond to potential hyphenation points. A pure guess on my part: a solution to the challenge I'm posing may involve creating two types of hyphenation points: the first type would consist of "ordinary" hyphenation points, and instances of the second type would inform TeX that it's dealing with both a hyphenation point and a no-ligation point.

Addendum 16 September -- I've added a "bounty" of 200 points. :-)

And the winning answer is...

I've declared Aditya's entry below the winner. Here's a modified version of his MWE, which contains a (very!!) contrived sentence that contains words with seven different types of ligatures that should be suppressed (f-f, f-i, f-l; ff-i, ff-l; f-fi, and f-fl). Observe that the MWE needs to be compiled with ConTeXt.

\usemodule[translate]

\translateinput[shelffuls][shelf|*|fuls]
\translateinput[selfish][self|*|ish]
\translateinput[halflife][half|*|life] 
\translateinput[standoffish][stand|*|off|*|ish]
\translateinput[cufflinks][cuff|*|links] 
\translateinput[offloads][off|*|loads]    
\translateinput[chaffinches][chaf|*|finches]
\translateinput[safflower][saf|*|flower]

\definetextmodediscretionary * {\prewordbreak\discretionary{-}{}{\kern0pt}\prewordbreak}
\hyphenation{chaf-finches}
\starttext

No ligatures disabled:\\
A standoffish and selfish person who offloads shelffuls 
   of cufflinks and doesn't watch chaffinches in the
   safflower field has a short halflife.

\medskip
\enableinputtranslation 
Some, but not all, ligatures disabled:\\
A standoffish and selfish person who offloads shelffuls 
   of cufflinks and doesn't watch chaffinches in the
   safflower field has a short halflife.

\stoptext

enter image description here

  • 4
    To prevent ligatures also "| as in Kauf"|leute should be mentioned. (Which doesn't answer the question how to do so globally, which would be really interesting. Therefore it's just a comment.) – Stephen Sep 14 '11 at 18:27
  • Thanks, Stephen. Just out of curiosity: how does the output of the "| method of suppressing ligatures compare with that of the {} and \/ methods? – Mico Sep 14 '11 at 19:23
  • 1
    "| is babel's command to suppress a ligature in some languages, cf. my comment to tex.stackexchange.com/questions/19263/… and also see tex.stackexchange.com/questions/27198/…. – doncherry Sep 14 '11 at 21:18
  • 4
    The babel "| is language dependent. It usually does something like \textormath{\discretionary{-}{}{\kern.03em}}{} so it's both a hyphenation point and no-ligation point. – Lev Bishop Sep 15 '11 at 5:54
  • 1
    @mico -- Writing treff\NL{l}ich sort-of works: it retains the ff-ligature, but not ffl. The problem is, that the kern between ff and l is ignored. But most fonts don't have a good kerning for this pair anyway, so this might call for a manual \kern. – Florian Sep 20 '11 at 12:40
up vote 27 down vote accepted
+200

In LuaTeX you can intercept the input and change it before TeX sees it. This can be used to disable certain ligatures. Here is a proof of concept in ConTeXt.

\usemodule[translate]

\translateinput[selfish][self|*|ish]
\translateinput[halflife][half|*|life]

\starttext

A selfish person has a small halflife.

\enableinputtranslation 

A selfish person has a small halflife.

\disableinputtranslation

A selfish person has a small halflife.

\stoptext

which gives

enter image description here

See m-translate.mkiv in the ConTeXt distribution for implementation details. Keep in mind that this will change all occurrences of "selfish" to "self|*|fish", including those in csname. For example, if you have a selfish environment, it will fail! The advantage of this approach is that it will work for all words that contain selfish; for example, selfishness, unselfish, etc.

|*| disables ligatures and does not affect hyphenation. But it introduces a 0.05em kern between the two letters. If you do not like that add

\definetextmodediscretionary *
  {\prewordbreak\discretionary{-}{}{}\prewordbreak}
  • @Mico: The above fragment is a MWE...I guess you mean a MWE in LaTeX :) – Aditya Sep 17 '11 at 22:16
  • I don't know how TeXworks invokes ConTeXt. Can you simply try to call context filename from command line. – Aditya Sep 17 '11 at 22:23
  • 1
    @Mica: It does disable hyphenation :( I don't know how to disable ligatures in ConTeXt without disabling hyphenation. A simple {} like in self{}ish does not work. I'll try to find out. – Aditya Sep 17 '11 at 23:58
  • 1
    @Mico: Another option is \self|*|ish which does not disable hyphenation between f and i, but inserts a 0.05em space. You can get rid of that space by redefining * discretionary. The original definition is \definetextmodediscretionary *{\prewordbreak\discretionary{-}{}{\kern.05em}\prewordbreak} Change .05em to 0pt. – Aditya Sep 19 '11 at 14:24
  • 1
    @Aditya: And +1 for getting a word of wisdom out of a small list of random words ;-) – ℝaphink Sep 21 '11 at 6:06

Just today I discovered a blog-entry on this issue. As it turns out there are two ready-to-use different solutions to this problem on CTAN:

  • rmligs uses a word-list from Ispell
  • ligatex uses a syllable-based approach, not unlike TeX's hyphenation

Both are TeX-independend programs which modify the source before compiling. Both are only for German, but are supposed to be customisable for other languages.

  • 1
    Thanks for this! Does anyone know if these packages are still maintained and, if so, by whom? More importantly, could anyone share practical experiences with these programs? As written, they're mainly (exclusively?) intended for German documents, and they require the use of babel and/or german, which makes me a bit concerned about their usability for languages other than German. Anyone wish to comment? – Mico Sep 14 '11 at 19:20
  • 1
    There is also DeLig - ctan.org/tex-archive/support/delig – koppor Apr 15 '14 at 15:29
  • 1
    Note that these tools do wrong in the case of other fonts: See @Mico: The issue of how much whitespace (if any) should be inserted in order to create a visible gap between "f" and f/i/l is strongly font-dependent. babel's "| method not only breaks up the ligature but also inserts 0.03em of whitespace. This setting seems to have been arrived at for the Computer/Latin Modern Roman font face and, in particular, the f-l ligature case. [...] With Times Roman, in contrast, 0.03em is not sufficient for the f-l case. And, for EB Garamond, one would have to insert 0.11em to create a gap. – koppor Mar 9 at 10:53
  • Long comparison about selnolig vs. babel shortcuts: tex.stackexchange.com/a/389439/9075 – koppor Mar 9 at 21:13

In case one use LuaLaTeX, you can use the selnolig package. Be aware that one has to use the fontspec package then.

English:

\usepackage[english]{selnolig}

German:

\usepackage[ngerman]{selnolig}

More information:

  • 7
    This nicely comes full circle, because it's the author of this question who later went on to create the selnolig package. :-) – ShreevatsaR Mar 7 at 0:37

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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