Césure sous Oméga

Césure

Quand on écrit et qu'on arrive à la fin d'une ligne, il est parfois nécessaire de couper le dernier mot pour en écrire un morceau en fin de ligne et le reste au début de la ligne suivante : c'est la césure. Mais on ne coupe pas n'importe où : cette césure est régie par certaines règles. De surcroît, ces règles changement d'une langue à l'autre. Par exemple, en français, on couperait « in-ter-chan-geable » alors qu'en anglais ce serait « in-ter-change-able ». LaTeX connait ces règles : elles sont expliquées dans des fichiers de césure, par exemple frhyph.tex, dont voici un extrait (il n'est pas du tout nécessaire de comprendre comment ces règles sont décrites : les personnes intéressées peuvent lire l'appendice H du TeX-Book)

\patterns{2'2 .a4 'a4 .\^a4 '\^a4 ab2h .ab3r\'ea 'ab3r\'ea
  ad2h a1\`e2dre .ae3s4ch 'ae3s4ch 1alcool a2l1algi
  .amino1a2c 'amino1a2c .ana3s4tr 'ana3s4tr 1a2nesth\'esi
  .anti1a2 'anti1a2 .anti1e2 'anti1e2 .anti1\'e2 .anti2enne
  'anti2enne 'anti1\'e2 .anti1s2 'anti1s2 .apo2s3ta
  'apo2s3ta apo2s3tr archi1\'e2pis
  ...
}

La commande LaTeX \showhypens permet de visualiser la césure.

\showhyphens{document sur l'acculturation}

Le résultat n'est pas affiché dans le fichier *.dvi (cette commande n'affiche rien dans ce fichier) mais juste mis dans le fichier *.log.

Underfull \hbox (badness 10000) in paragraph at lines 209--209
[] \T1/cmr/m/n/10 do-cu-ment sur l'ac-cul-tu-ra-tion

Avec les motifs de césure anglais, on aurait eu les propositions de césure suivantes.

Underfull \hbox (badness 10000) in paragraph at lines 207--207
[] \T1/cmr/m/n/10 doc-u-ment sur l'acculturation

Pour vérifier que la césure est correcte, nous aurons besoin d'un fichier de test. Pour le construire (pour trouver les exemples que je donne depuis tout-à-l'heure), je pars d'une liste de mots français (ceux du dictionnaire d'ispell), d'une liste de mots anglais (présente sur tous les systèmes UNIX),

perl -p -e 's#/.*##' `locate francais.dico | head -1` | 
  sort | uniq > ex_1_french
sort /usr/share/dict/words | uniq > ex_1_english

j'en fais l'intersection,

cat ex_1_french ex_1_english | sort | uniq -d > ex_2_common

je prends quelques mots au hasard,

cat_rand ex_2_common | head -100 > ex_3_words

et je les donne à LaTeX

(
  echo '\\documentclass{article}'
  echo '\\usepackage[T1]{fontenc}'
  echo '\\usepackage[latin1]{inputenc}'
  echo '\\usepackage[frenchb,english]{babel}'
  echo '\\begin{document}'
  for i in `cat ex_3_words`
  do
    echo '\\selectlanguage{french}\\showhyphens{'$i'}'
    echo '\\selectlanguage{english}\\showhyphens{'$i'}'
  done
  echo '\\end{document}'
) > ex_4_latex.tex

pour en avoir la césure française et anglaise.

latex ex_4_latex.tex
perl -n -e 's/.*10\s// && print' ex_4_latex.log | 
  uniq -u > ex_5_cesure

Voici quelques résultats (en premier, la césure française, ensuite, la césure anglaise).

ra-vage
rav-age
ex-ten-sible
ex-ten-si-ble
ma-lice
mal-ice
Wa-shing-ton
Wash-ing-ton
as-su-rance
as-sur-ance
des-crip-tion
de-scrip-tion
ma-dras
madras
fo-rage
for-age
illu-sion
il-lu-sion
di-la-ta-tion
di-lata-tion
An-toi-nette
An-toinette
in-ter-chan-geable
in-ter-change-able
ima-gi-nable
imag-in-able
congra-tu-la-tions
con-grat-u-la-tions
en-du-rance
en-durance
cy-clo-tron
cy-clotron
Tient-sin
Tientsin
consti-tu-tion
con-sti-tu-tion
ca-li-bra-tion
cal-i-bra-tion
mi-ser
miser
ima-gi-na-tive
imag-i-na-tive
bron-chiole
bron-chi-ole
conduc-tion
con-duc-tion
po-li-ce-men
po-lice-men
la-ser
laser
Schle-sin-ger
Schlesinger
spor-tive
sportive

Premier essai

Quand on lance Lambda (l'équivalent de LaTeX pour Oméga), on constate que les motifs ce césure français ne sont pas là.

...
Babel <v3.7h> and hyphenation patterns for english, greek, loaded.
...

Package babel Warning: No hyphenation patterns were loaded for
(babel)                the language `French'
(babel)                I will use the patterns loaded for \language=0 instead.
...

Underfull \hbox (badness 10000) in paragraph at lines 8--8
[][] \T1/cmr/m/n/10 doc-u-ment sur l&rsquo;ac-cul-tur-a-tion

Underfull \hbox (badness 10000) in paragraph at lines 9--9
[][] \T1/cmr/m/n/10 abr&eacute;via-tive-ment v&eacute;g&eacute;-tais

On voudrait les césures

do-cu-ment sur l'ac-cul-tu-ra-tion
abré-via-ti-ve-ment vé-gé-tais

Motifs de césure français

On va donc les rajouter. Ils sont fixés lors de la création du format. Le format, c'est l'ensemble des macros de LaTeX, i.e., le contenu du fichier latex.ltx, précompilé de manière que LaTeX se lance plus vite ; celui de lambda se trouve dans un fichier lambda.fmt.

La liste des motifs de césures à charger se trouve dans un fichier language.dat. Pour savoir lequel est chargé, on peut taper

kpsewhich --progname=lambda language.dat

Ce fichier contient

english ushyphen.tex
greek elhyph16.tex

On rajoute une ligne pour le français (soit dans le fichier que l'on a précédemment, soit dans une copie que l'on placera dans le répertoire courrant)

english ushyphen.tex
french frhyphen.tex
greek elhyph16.tex

On recrée ensuite le format

lambda --ini lambda.ini

On peut soit laisser le fichier lambda.fmt ainsi créé dans le répertoire courant, soit le mettre dans le répertoire adéquat (pour moi, .../texmf/web2c/)

Voici ce que l'on obtient avec des fontes T1 (on précise \usepackage[T1]{fontenc})

[][] \T1/cmr/m/n/10 do-cu-ment sur l&rsquo;ac-cul-tu-ra-tion
[][] \T1/cmr/m/n/10 abr&eacute;-via-ti-ve-ment v&eacute;-g&eacute;-tais

avec des fontes OT1 (on ne précise rien, mais les accents disparaissent -- pas bon)

[][] \OT1/cmr/m/n/10 do-cu-ment sur l'ac-cul-tu-ra-tion
[][] \OT1/cmr/m/n/10 abr-via-ti-ve-ment vg-tais

et avec des fontes Unicode

Underfull \hbox (badness 10000) in paragraph at lines 35--35
[][] \U/cyber/m/n/10 do-cu-ment sur l'ac-cul-tu-ra-tion

Underfull \hbox (badness 10000) in paragraph at lines 36--36
[][] \U/cyber/m/n/10 abr^^e9-via-ti-ve-ment v^^e9-g^^e9-tais

Scrupules et questions

Ça a l'air de marcher, mais je ne comprends pas du tout pourquoi : le TeX-Book nous apprend que les fichiers de césure sont écrits dans le codage d'une fonte. Donc un fichier de césure prévu pour les codages T1 et OT1 (oui, les deux en même temps) ne devrait pas marcher avec une fonte en Unicode.

Si quelqu'un comprends pourquoi ça marche, ou constate qu'en fait ça ne marche pas, qu'il n'hésite pas à me le signaler.

Je ne comprends pas non plus pourquoi les caractères accentués sont affichés comme &eacute; quand on utilise le codage T1 et ^^e9 quand on est en Unicode. Probablement parce que je n'ai pas dit qu'on était en Unicode. Quel est le nom LaTeX du codage unicode ? UT1 ?

Motifs de césure en Unicode

Si jamais cela posait effectivement des problèmes, on pourrait construire un fichier de motifs de césure français (pendant que j'y étais, j'ai aussi pris les motifs de césure allemands) en Unicode.

(copier-coller de vieilles notes -- je ne m'étais pas encore apperçu que ça marchait sans ça.)

Les motifs ce césure doivent correspondre au codage utilisé par les fontes. Les motifs de césure de LaTeX ne conviennent donc pas à Omega. Nous allons donc devoir écrire un fichier de césure pour le français (et l'allemand) pour Omega. Regardons le contenu du fichier de césure pour LaTeX. Après quelques lignes très complexes visant à vérifier qu'on n'utilise pas une version de TeX qui remonte au début des années 80, on lit

  \catcode"E0=11 \lccode"E0="E0 % \`a

pour les lettres àâçèéêëîïôùûüÿ oe.

Cela signifie que ces caractères, identifiés par leur code « ASCII », sont des lettres (catcode = 11), et pas des symboles pour lesquels la césure n'aurait aucun sens, et que ce sont des minuscules (la commande \lccode permet de convertir les lettres en minuscules avant de chercher les points de césure autorisés -- il faut que ce \lccode soit non nul, sinon, TeX pense que ce n'est pas une lettre).

Je m'attendrais plutôt à trouver (comme pour d'autres langues) des choses du genre

\catcode"C0=11 \lccode"C0="E0 \uccode"C0="C0    % \`A
\catcode"E0=11 \lccode"E0="E0 \uccode"E0="C0    % \`a

Ensuite, le fichier redéfinit les macros \' \` \^ \" \c de manière qu'elles appellent les caractères adéquats : cela permet de les utiliser dans le fichier de césure. (Ces définitions sont locales au fichier de césure.)

\catcode`\!=7  % use !!xy instead of ^^xy
\def\E{\errmessage{Hyphenation pattern file corrupted}}
\def\`#1{\ifx#1a!!e0\else \ifx#1e!!e8\else \E \fi\fi}
...

Vient ensuite une ligne qui dit que l'apostrophe a le droit de se trouver à l'intérieur d'un mot

\lccode`\'=`\'

Enfin, les motifs de césure, dont la syntaxe est détaillée dans l'appendice H du TeXBook. Dans ces motifs ce césure, les lettres accentuées sont tapées \'e (dans les motifs ce césure de beaucoup d'autres langues, elles sont tapées ^^a4, mais on peut aussi taper les accents normalement).

\patterns{
  2'2
  .a4
  'a4
  .\^a4
  '\^a4
  ...
}

Notre fichier de césure pour Omega ressemblera donc à

\begingroup
\ifx\OmegaVersion\undefinedcommand\else
\catcode`\"=12

% ï / Ï
\catcode"00EF=11 \lccode"00EF="00EF \uccode"00EF="00CF
\catcode"00CF=11 \lccode"00CF="00EF \uccode"00CF="00CF

% à / À
\catcode"00E0=11 \lccode"00E0="00E0 \uccode"00E0="00C0
\catcode"00C0=11 \lccode"00C0="00E0 \uccode"00C0="00C0

...

\catcode"00DF=11 \lccode"00DF="00DF % ß
\catcode"0153=11 \lccode"0153="0153 % oe
\lccode`\'=`\'
\catcode`\!=7

\def\`#1{\ifx#1a!!!!00e0\else\ifx#1e!!!!00e8\else\ifx#1u!!!!00f9\else\E\fi\fi\fi}
\def\'#1{\ifx#1e!!!!00e9\else\E\fi}
\def\^#1{\ifx#1a!!!!00e2\else\ifx#1e!!!!00ea\else\ifx#1i!!!!00ee\else\ifx#1o!!!!00f4\else\ifx#1u!!!!00fb\else\E\fi\fi\fi\fi\fi}
\def\"#1{\ifx#1a!!!!00e4\else\ifx#1e!!!!00eb\else\ifx#1i!!!!00ef\else\ifx#1o!!!!00f6\else\ifx#1u!!!!00fc\else\ifx#1y!!!!00ff\else\E\fi\fi\fi\fi\fi\fi}
\def\c#1{\ifx#1c!!!!00e7\else\E\fi}
\def\oe{!!!!0153}

\patterns{
  ...
}

\fi
\endgroup

Mais comme c'est particulièrement pénible à taper, on va le faire automatiquement.

#! perl -w
use strict;
use constant TRUE  => (0==0);
use constant FALSE => (0==1);
use Unicode::String qw(utf8 uchr);
  
sub utf_to_unicode {
  my $a = shift;
  $a = utf8($a);
  $a = $a->ord;
  $a = sprintf("%04X",$a);
  return $a;
}
  
sub unicode_to_utf {
  my $a = shift;
  $a = uchr($a);
  $a = $a->utf8;
  return $a;
}
  
die "usage: $0 hyphenation_file.tex" unless $ARGV[0];
  
print '\begingroup\ifx\OmegaVersion\undefinedcommand\else\catcode`\"=12'."\n";
my %a = qw/à À â Â ç Ç è È é É ê Ê ë Ë î Î ï Ï
           ô Ô ö Ö ù Ù û Û ü Ü ÿ ÿ/;
foreach my $a (keys %a) {
  my $b = $a{$a};
  my $lc = utf_to_unicode($a);
  my $uc = utf_to_unicode($b);
  print "\% lc: $a  uc: $b\n";
  print "\\catcode\"$lc=11 \\lccode\"$lc=\"$lc \\uccode\"$lc=\"$uc\n";
  print "\\catcode\"$uc=11 \\lccode\"$uc=\"$lc \\uccode\"$uc=\"$uc\n";
}
print '% ß'."\n";
print '\catcode"00DF=11 \lccode"00DF="00DF'."\n";
print '% oe'."\n";
print '\catcode"0153=11 \lccode"0153="0153'."\n";
print "\\lccode`\\'=`\\'\n";
print '\catcode`\!=7'."\n";
print join('',
	   map { $_>128 ? sprintf("!!!!%04x", $_) : chr($_) }
	   unpack("U*", '\def\`#1{\ifx#1aà\else\ifx#1eè\else\ifx#1uù\else\E\fi\fi\fi}
\def\\\'#1{\ifx#1eé\else\E\fi}
\def\^#1{\ifx#1aâ\else\ifx#1eê\else\ifx#1iî\else\ifx#1oô\else\ifx#1uû\else\E\fi\fi\fi\fi\fi}
\def\"#1{\ifx#1aä\else\ifx#1eë\else\ifx#1iï\else\ifx#1oö\else\ifx#1uü\else\ifx#1yÿ\else\E\fi\fi\fi\fi\fi\fi}
\def\c#1{\ifx#1cç\else\E\fi}
\def\oe{!!!!0153}
\def\ss{ß}
\def\3{ß}
\def\9{ß}
\def\n#1{#1}
'));
print '\catcode`\!=12'."\n";
  
open(HYPH, '<', $ARGV[0]) || die "Cannot open $ARGV[0] for reading: $!";
my $hyph = FALSE;
while(<HYPH>){
  $hyph=TRUE if m/^\\pattern/;
  next unless $hyph;
  # On transforme le " actif du fichier de césure allemand en \"
  s/([^\\])\"/$1\\\"/g;
  # On se débarasse du \c{...} du fichier de césure allemand
  # (c'était pour le ß en OT1)
  s/\\c\{[^\}]{2,}\}//g;
  # On se débarasse des \oeOT (\oe codé en OT1)
  s/\S*\\oeOT\S*//g;
  print;
  last if m/^\}/;
}
close(HYPH);
die "No patterns found in $ARGV[0]" unless $hyph;
  
print "\n".'\fi\endgroup';

On crée le fichier pour le français et pour l'allemand.

perl create_frhyph.pl frhyph.tex > frhyphomega.tex
perl create_frhyph.pl dehypht.tex > dehypht_omega.tex

On crée un fichier language.dat qui va les charger.

% File    : language.dat
% Purpose : specify which hypenation patterns to load 
%           while running iniTeX 
english ushyphen.tex
greek elhyph16.tex
french frhyphomega.tex
german dehypht_omega.tex

On recompile le format de Lambda.

lambda --ini lambda.ini

On teste cela sur un exemple : la commande \showhyphens afficher les points de césure choisis pour un ou plusieurs mots sur la sortie d'erreur et dans le fichier *.log.

\ocp\TexUTF=inutf8
\InputTranslation currentfile \TexUTF

\documentclass[12pt]{article}
\usepackage[T1]{fontenc}
\usepackage[german,frenchb,english]{babel}
\begin{document}

\selectlanguage{french}
\showhyphens{Élévation}

\selectlanguage{german}
\showhyphens{außerdem}

\end{document}

Bien enfoui dans le fichier *.log, on lit

Underfull \hbox (badness 10000) in paragraph at lines 10--10
[][] \T1/cmr/m/n/12 &Eacute;l&eacute;-va-tion

Underfull \hbox (badness 10000) in paragraph at lines 13--13
[][] \T1/cmr/m/n/12 au&MMLSZlig;er-dem

Vincent Zoonekynd
<zoonek@math.jussieu.fr>
latest modification on ven mai 3 17:25:39 CEST 2002