scratch/content/html/fr/blog/2010-02-15-All-but-something-regexp.md

83 lines
2.5 KiB
Markdown
Raw Normal View History

2010-02-17 12:27:01 +00:00
-----
# Custom
isHidden: false
menupriority: 1
kind: article
created_at: 2010-02-15T11:16:12+02:00
2010-04-26 14:48:52 +00:00
title: Expression régulière pour tout sauf quelquechose
2010-02-17 12:27:01 +00:00
tags:
- regexp
2010-04-19 14:10:56 +00:00
- regular expression
2010-02-17 12:27:01 +00:00
-----
2010-04-26 14:48:52 +00:00
Parfois vous ne pouvez simplement pas écrire :
2010-02-17 12:27:01 +00:00
2010-04-15 09:45:50 +00:00
<div><code class="ruby">
2010-02-17 12:27:01 +00:00
if str.match(regexp) and
not str.match(other_regexp)
do_something
2010-04-15 09:45:50 +00:00
</code></div>
2010-02-17 12:27:01 +00:00
2010-04-26 14:48:52 +00:00
et vous devez obtenir le même comportement avec seulement une expression régulière. Le problème c'est que le complémentaire des régulier n'est pas régulier. Donc pour cetaines expression, c'est absolument impossible à faire.
2010-02-17 12:27:01 +00:00
2010-04-26 14:48:52 +00:00
Cependant, pour certaines expressions ce peut être possible<sup><a href="#note1">&dagger;</a></sup>. Disons que vous souhaitez matcher tout les lignes contenant le mot `bull`, mais que vous ne souhaitez pas matcher `bullshit`. Voici une façon sympa d'y arriver :
2010-02-17 12:27:01 +00:00
2010-04-15 09:45:50 +00:00
<div><code class="ruby">
2010-04-26 14:48:52 +00:00
# matcher toute les chaines qui
# matchent 'bull' (bullshit compris)
2010-02-17 12:27:01 +00:00
/bull/
2010-04-26 14:48:52 +00:00
# matcher toutes les chaines qui
# contiennent 'bull' sauf 'bullshit'
2010-02-17 12:27:01 +00:00
/bull([^s]|$)|
bulls([^h]|$)|
bullsh([^i]|$)|
bullshi([^t]|$)/
2010-04-26 14:48:52 +00:00
# une autre façon de l'écrire serait
2010-02-17 12:27:01 +00:00
/bull([^s]|$|s([^h]|$)|sh([^i]|$)|shi([^t]|$))/
2010-04-15 09:45:50 +00:00
</code></div>
2010-02-17 12:27:01 +00:00
2010-04-26 14:48:52 +00:00
Regardons de plus près. Dans la première ligne, l'expression est :
`bull([^s]|$)`, pourquoi avons nous besoin du `$` ?
Parce que sans lui, le mot `bull` ne serait pas matché. Cette expression signifie :
2010-02-17 12:27:01 +00:00
2010-04-26 14:48:52 +00:00
> La chaine finie par `bull`
> ou,
> contient `bull` suivi d'une lettre différente de `s`.
2010-02-17 12:27:01 +00:00
2010-04-26 14:48:52 +00:00
Et voilà. J'espère que ça a pu vous aider.
2010-02-17 12:27:01 +00:00
2010-04-26 14:48:52 +00:00
Notez que cette méthode n'est pas toujours la meilleure. Par exemple essayons d'écrire une expression régulière équivalente à l'expression conditionnelle suivante :
2010-04-15 09:45:50 +00:00
<div><code class="ruby">
2010-04-26 14:48:52 +00:00
# Commence avec 'a': ^a
# Se finit par 'a': c$
# Contient 'b': .*b.*
# Mais n'est pas 'axbxc'
if str.match(/^a.*b.*c$/) and
not str.match(/^axbxc$/)
2010-02-17 12:27:01 +00:00
do_something
end
2010-04-15 09:45:50 +00:00
</code></div>
2010-02-17 12:27:01 +00:00
2010-04-26 14:48:52 +00:00
Une solution est :
2010-02-17 12:27:01 +00:00
2010-04-15 09:45:50 +00:00
<div><code class="ruby">
2010-04-26 14:48:52 +00:00
/abc| # longueur 3
a.bc| # longueur 4
2010-02-17 12:27:01 +00:00
ab.c|
2010-04-26 14:48:52 +00:00
a[^x]b[^x]c| # longueur 5
a...*b.*c| # longueur >5
2010-02-17 12:27:01 +00:00
a.*b...*c/
2010-04-15 09:45:50 +00:00
</code></div>
2010-02-17 12:27:01 +00:00
2010-04-26 14:48:52 +00:00
Cette solution utilise la longueur maximale de la chaine qui ne doit pas être matchée. Il existe certainement d'autres méthodes. Mais la leçon importante c'est qu'il n'est pas naturel d'exclure des solutions d'un expression régulière.
2010-02-17 12:27:01 +00:00
---
<small><a name="note1">&dagger;</a>
2010-04-26 14:48:52 +00:00
Il peut être démontré que tout ensemble régulier privé d'un ensemble fini est aussi régulier.
2010-02-17 12:27:01 +00:00
</small>