Planche 1
Cours 4
Chaînes de caractères
Jean-Jacques.Levy@inria.fr
http://jeanjacqueslevy.net
tel: 01 39 63 56 89
secrétariat de l'enseignement:
Catherine Bensoussan
cb@lix.polytechnique.fr
Aile 00, LIX
tel: 01 69 33 34 67
http://www.enseignement.polytechnique.fr/informatique/
Planche 2
Plan
-
Caractères -- chaînes de caractères
- Exceptions
- Entrées-Sortie
- Filtrage naif
- Filtrage linéaire
- Rappel sur les automates finis
- Expressions régulières
- Analyse lexicale
Planche 3
Caractères -- Chaînes de caractères
Les caractères sont des types primitifs
char c = 'a';
Caractères spéciaux: '\n' (newline), '\r' (retour
charriot), '\t' (tabulation), '\\ (backslash), '\''
(apostrophe), '\"' (guillemet).
Fonctions: isLetter(c), isDigit(c), isLetterOrDigit(c), etc
Les chaînes de caractères sont des objets
String s = "Vive l'informatique!"
dont les méthodes
s.length() donne la longueur de s
s.equals(t) teste l'égalité de s et t
s.indexOf(c) donne la première occurence de c dans s
s.charAt(i) donne le ième caractère de s
etc.
Les chaînes sont immuables.
Planche 4
Chaînes modifiables
On se sert de la classe StringBuffer
String x = "a" + 4 + "c"
est équivalent à
String x = new StringBuffer().append("a").append(4).append("c").toString()
La classe StringBuffer a deux méthodes
s.insert(i,t) insère la chaîne t après le ième caractère de s
s.append(t) met t au bout de s
Planche 5
Conversion des chaînes en entier
static int parseInt (String s) {
int r = 0;
for (int i = 0; i < s.length(); ++i)
r = 10 * r + s.charAt(i) - '0';
return r;
}
Exercice 1Le faire en base 16.
Que faire si la chaîne contient des caractères différents des
chiffres décimaux?
-
Retourner une valeur réservée: -1 par exemple. Laid!
-
Lever une exception.
Planche 6
Conversion des chaînes en entier
static int parseInt (String s) {
int r = 0;
for (int i = 0; i < s.length(); ++i) {
if (!Character.isDigit (s.charAt(i)))
throw new Error ("Pas un nombre");
r = 10 * r + s.charAt(i) - '0';
}
return r;
}
La classe Error est une classe d'erreurs dites
``irrattrapables''. (On n'a pas besoin de le signaler dans la signature
de la fonction qui lève cette erreur).
Planche 7
Conversion des chaînes en entier
Avec des erreurs rattrapables:
static int parseInt(String s) throws NumberFormatException {
int r = 0;
for (int i = 0; i < s.length(); ++i) {
if (!Character.isDigit (s.charAt(i)))
throw new NumberFormatException (s);
r = 10 * r + s.charAt(i) - '0';
}
return r;
}
NumberFormatException est une sous-classe de la classe
générale des Exception.
java.lang.Object
+----java.lang.Throwable
+----java.lang.Error
+----java.lang.Exception
+----java.lang.RuntimeException
+----java.lang.IllegalArgumentException
+----java.lang.NumberFormatException
Planche 8
Récupération d'exceptions
public static void main (String[] args) {
try {
int x = parseInt (args[0]);
System.out.println (x);
} catch (NumberFormatException e) {
System.err.println ("Mauvais argument: " + e.getMessage());
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println ("Mauvais nombre d'arguments");
}
}
On a séparé le cas des exceptions du traitement normal. A la place de
catch, on peut écrire finally pour effectuer une opération
finalle s'il y a exception ou pas (cela évite la duplication de code).
Planche 9
Entrées-Sorties
Impression: System.out.print, System.err.print
Lecture: 2 constructeurs pour obtenir les entrées tamponnées!
import java.io.*;
class IO {
public static void main (String[] args) {
BufferedReader in =
new BufferedReader(new InputStreamReader(System.in));
try {
String s;
while ((s = in.readLine()) != null) {
int n = Integer.parseInt(s);
System.out.println(n);
}
} catch (IOException e) {
System.err.println(e);
}
}
Exercice 2Comment éviter d'écrire la clause catch ?
Planche 10
Filtrage -- String Matching
Données: deux chaînes s et t.
But: indice de la première occurence de s dans t.
static int match (String s, String t) {
int m = s.length(), n = t.length();
loop:
for (int i = 0; i + m <= n; ++i) {
for (int j = 0; j < m; ++j)
if (t.charAt(i+j) != s.charAt(j))
continue loop;
return i;
}
return -1;
}
Complexité?
Cf. l'animation de l'université de Kyushu.
Planche 11
Filtrage linéaire -- Knuth-Morris-Pratt
Traitement initial sur s pour trouver les plus grands suffixes qui
sont aussi des préfixes. On ne recompare pas deux fois un même
caractère de t.
static int[] preprocess(char[] s, int m) {
int[] next = new int[m+1];
int j = 0; int t = -1; next[0] = -1;
while (j < m) {
while (t >= 0 && s[j] != s[t])
t = next[t];
++t; ++j;
next[j] = t;
}
return next;
}
Complexité?
Planche 12
Filtrage linéaire -- Boyer-Moore
Comme la méthode précédente, mais en procédant de la droite vers la gauche.
Sublinéaire.
Planche 13
Quelques notions d'automates finis
- Mécanisme d'un distributeur automatique
- Protocoles réseau (bit alterné, etc)
- Peloton d'exécution (Firing squad problem)
- Systèmes réactifs
- Contrôle dans les circuits
- Analyseurs lexicaux
Planche 14
Distributeur de boissons
Il y a une fente pour les pièces de 1F, 2F. Le café sort si on met
3F. On peut aussi faire une machine avec un tampon de longueur 1 ou 2,
qui permet de mettre directement 6F pour avoir 2 cafés.
Planche 15
Peloton d'exécution -- Firing Squad Problem
Il y a une forte brûme sur le plateau. Le général convoque 400
soldats, les aligne, et veut les faire tirer, tous en même temps. A
tout moment, le général et les soldats changent d'état de manière
synchrone en ne tenant compte que de leurs 2 voisins immédiats. Il y
a donc 3 types de machines: le général, les soldats et le soldat du
bout de la chaîne.
Montrer qu'on peut trouver une solution en moins de 8 états pour les 3
types de machines quelquesoit le nombre de soldats.
Planche 16
Autre exemple
Automate fini acceptant tous les mots contenant un nombre pair de a
et de b.
Planche 17
Automate fini
Un automate fini M est un quintuplet (Q, S, d, q0, F)
où:
S est un alphabet (de terminaux ou tokens),
Q est un ensemble fini d'états,
q0 Î Q est l'état initial,
F Ì Q est l'ensemble des états finaux,
d : Q × S ® Q est la fonction de transition
On peut étendre d sur Q × S* ® Q comme suit:
d(q, e) = q
d(q, aw) = d(d(q,a), w)
Le langage reconnu par l'automate M est:
T(M) = {w | d(q0,w) Î F}
Planche 18
Graphiquement
Les mots de S à analyser sont sur une bande (non
modifiable). L'automate est un lecteur de bande. Initialement la tête
de lecture est sur la première lettre du mot, l'automate est dans
l'état q0. Puis la tête de bande de déplace d'un cran vers la
droite en changeant d'état en fonction du caractère lu, et ainsi de
suite jusqu'à la fin du mot. Le mot est accepté si sa fin est obtenue
dans un état de F.
Planche 19
Représentation des automates finis
ou
Planche 20
Automates non déterministes
A chaque état, l'automate peut faire un choix non déterministe entre
plusieurs transitions. Formellement, d : Q × S ®
2Q et on étend d comme suit
| d(q, e) = {q}
d(q, aw) = |
|
d(q',w) |
Le langage reconnu par l'automate non déterminite M est:
T(M) = {w | d(q0,w) Ç F ¹ Ø }
Un mot est accepté si une série de choix peut amener l'automate dans
un des états finaux de F. Les mauvais choix ne comptent donc pas.
Planche 21
Exemples non déterministes
-
L = { xaay | x,y Î S* } È { xbby | x,y Î S* }
-
L = L1 È L2 où L1 et L2 sont reconnus par des automates
finis
-
L = { xwy | x,y Î S* } où w est un mot donné.
Planche 22
Déterminisation des automates finis
Théorème 1 [Rabin-Scott] Tout langage reconnu par un
automate fini non déterministe peut aussi être reconnu par un automate
fini déterministe.
Démonstration: on considère l'automate déterministe défini sur
2Q, en prenant { q0 } comme état initial et F comme ensemble
de fin.
Remarque: l'automate déterminisé peut avoir 2n états, si
n est le nombre d'états de l'automate non-déterministe.
Théorème 2 [Myhill - Nerode] Tout langage reconnu par un
automate fini est reconnu par un automate déterministe minimal unique
à un isomorphisme près sur le nom des états.
Planche 23
Expressions régulières
Une expression régulière e représente un langage [[ e ]]
[[ a ]] = { a }
[[ e + e' ]] = [[ e ]] È [[ e' ]]
[[ e e' ]] = [[ e ]] [[ e' ]]
[[ e* ]] = [[ e ]]*
[[ (e) ]] = [[ e ]]
Parfois, on écrit e | e ' au lieu de e + e '.
Exemples
(a+b)*abb est l'ensemble des mots sur a et b finissant par abb
(a+b)*w(a+b)* est l'ensemble des mots contenant w.
Théorème 3 Les langages décrits par des expressions
régulières sont exactement les langages reconnus par les automates
fini.
Cours complet sur automates finis -- calculabilité en Majeure 1
Planche 24
Un peu d'algèbre
Ajoutons 0 et 1 en posant
[[ 0 ]] = Ø et
[[ 1 ]] = { e }.
Les lois suivantes sont vérifiées:
| (1) |
e + e' = e' + e |
| (2) |
e + (e' + e'') = (e + e') + e'' |
| (3) |
e + 0 = e |
| (4) |
e + e = e |
| (5) |
e(e'e'') = (e e') e'' |
| (6) |
1 e = e 1 = e |
| (7) |
e (e' + e'') = e e' + e e'' |
| (8) |
(e + e') e'' = e e'' + e' e'' |
| (9) |
0 e = e 0 = 0 |
| (10) |
1 + e e * = e * |
| (11) |
1 + e * e = e * |
Planche 25
Expressions régulières et Unix
Les commandes shell d'Unix autorisent les expressions
régulières. D'autres commandes comme
/bin/sh (Bourne) pour les noms de fichiers,
sed, ed (Thomson) Stream editor, Editor
grep Get Regular ExPression
Emacs ESC-x re-search-forward
awk, perl Interpréteurs C (Aho, Weinberger, Kernighan),
(Wall)
lex (Lesk) Méta-compilateur d'expressions régulières pour C
recherchent des expressions régulières dans les fichiers. Tous ont
leur syntaxe propre. En général, ils essaient d'avoir les expressions
régulières les plus déterministes possible, sauf awk et perl.
Regardez le manuel sous Unix
% man awk
% man lex
% man sed
Planche 26
Analyse lexicale
Comment passer d'une chaîne de caractères à un arbre?
Problème de tout analyseur syntaxique (qu'on verra au cours prochain).
Se rappeler de la lecture des arbres dans le cours précédent!
En général, l'analyse syntaxique est précédée d'une phase d'analyse
lexicale, qui consiste à retirer des lexèmes dans un flot de
caractères.
Lexème: entité importante pour l'analyse syntaxique. Par exemple, un
identificateur, une constante numérique, un opérateur.
Les espaces,
tabulations, retour à la ligne, commentaires ne sont pas des lexèmes.
Planche 27
Lexèmes et expressions régulières
Ident = Lettre (Lettre | Chiffre)*
Chiffre = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
Lettre = a | b ... | z | A | B ... | Z
Entier = Chiffre Chiffre*
Operateur = + | - | * | /
Blanc = ' ' | \t' | '\r' | '\n'
Exercice 3Donner l'expression régulière pour les constantes réelles.
A partir de cette description, on construit l'analyseur lexical en
écrivant le programme correspondant à l'automate fini engendré par les
expressions régulières. Certains outils (lex) peuvent le faire
automatiquement. Manuellement, la difficulté réside dans la
déterminisation de l'automate.
Planche 28
Exemple d'exécution
Sur la chaîne d'entrée:
class PremierProg {
public static void main (String[ ] args){
System.out.println ("Bonjour les forts!");
System.out.println ("fib(20) = " + fib(20));
}
}
le résultat doit être
IDENT(class) IDENT(PremierProg) ACCG IDENT(public) IDENT(static)
IDENT(void) IDENT(main) PARG IDENT(String) CROG CROD IDENT(args)
ACCG IDENT(System) POINT IDENT(out) POINT IDENT(println) PARG
CHAINE(Bonjour les forts!) IDENT(System) POINT IDENT(out) POINT
IDENT(println) PARG CHAINE(fib(20) = ) PLUS IDENT(fib) PARG NOMBRE(20)
PARD PARD POINTVIRGULE ACCD ACCD FINFICHIER
Planche 29
Représentation des lexèmes
class Lexeme {
final static int NOMBRE=0, IDENT=1, OP=2;
int nature;
String as_var; int as_int; char as_op;
Lexeme (int i) { nature = NOMBRE; as_int = i; }
Lexeme (String s) { nature = IDENT; as_var = s; }
Lexeme (char op) { nature = OP; as_op = op; }
Et deux fonctions nextToken() et une variable globale
curToken.
En TD la calculette genre HP.
This document was translated from LATEX by HEVEA.