Ecriture d'expressions régulières performantes
Voici quelques-uns des aspects importants que vous devez prendre en compte lors de l'élaboration d'expressions régulières performantes.
Pour connaître les structures d'expression régulière pouvant être utilisées avec les analyseurs, les libellés et les filtres de données, reportez-vous à la documentation Java Platform Standard Ed. 8.
En cas de recherches et d'expression régulière de temps de requête, reportez-vous à la syntaxe RE2J à l'adresse Implémentation Java de RE2.
Classes de caractères
Les classes de caractères spécifient les caractères que vous essayez ou non de mettre en correspondance. Veillez à remplacer .
dans .*s
par un caractère plus spécifique. La partie .*
passe invariablement à la fin de votre entrée, puis revient à l'état précédemment enregistré pour poursuivre la recherche de correspondance. Si vous utilisez une classe de caractères, vous contrôlez le nombre de caractères que le moteur d'expression régulière consommera grâce à *
, vous donnant la possibilité d'arrêter le retour en arrière incontrôlé.
Prenons l'exemple d'expression régulière suivant :
(\d{4})(\d{2})(\d{2}),(\S+),([\S\s]*),([\S\s]*),([\S\s]*),([\S\s]*),([\S\s]*),([\S\s]*),([\S\s]*),([\S\s]*),([\S\s]*),([\S\s]*),([0-9.]+),([0-9.]+),([0-9.]+),([0-9.]+),([0-9.]+),([0-9.]+)
Pour l'entrée suivante :
20150220,201502,16798186260,tvN,Entertainment/Music,Female,67,2,Individual,ollehtv Economic,Commercial Housing,5587,0,2,0,1,1Du fait de l'expression régulière spécifiée, la correspondance peut subir des retours en arrière. Cette situation est détectée par Oracle Logging Analytics et l'opération de correspondance est abandonnée.
En remplaçant l'expression régulière par l'exemple ci-dessous, vous pouvez vous assurer que la mise en correspondance se termine plus rapidement. Nous remplaçons [\S\s]*
par [^,]
, ce qui évite tout retour en arrière inutile.
(\d{4})(\d{2})(\d{2}),(\S+),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([0-9.]+),([0-9.]+),([0-9.]+),([0-9.]+),([0-9.]+),([0-9.]+)
Quantificateurs lazy
Dans de nombreuses expressions régulières, les quantificateurs à consommation importante de ressources (.*s)
peuvent être remplacés sans encombres par des quantificateurs lazy (.*?s)
, augmentant ainsi les performances de l'expression régulière sans modifier le résultat.
Prenons l'entrée suivante :
Trace file /u01/app/oracle/diag/rdbms/navisdb/NAVISDB/trace/NAVISDB_arc0_3941.trc
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
ORACLE_HOME = /u01/app/oracle/product/11.2.0/db_1
System name: Linux
Node name: NAVISDB
Release: 2.6.18-308.el5
Version: #1 SMP Fri Jan 27 17:17:51 EST 2012
Machine: x86_64
Instance name: NAVISDB
Redo thread mounted by this instance: 1
Oracle process number: 21
Unix process pid: 3941, image: oracle@NAVISDB (ARC0)
Prenons également l'expression régulière à consommation importante de ressources ci-dessous pour l'entrée donnée :
Trace\sfile\s(\S*).*ORACLE_HOME\s*[:=]\s*(\S*).*System\sname:\s*(\S*).*Node\sname:\s*(\S*).*Release:\s*(\S*).*Machine:\s*(\S*).*Instance\sname:\s*(\S*).*Redo\sthread\smounted\sby\sthis\sinstance:\s(\d*).*Oracle\sprocess\snumber:\s*(\d*).*Unix\sprocess\spid:\s(\d*).*image:\s+([^\n\r]*)
Le moteur d'expression régulière est renvoyé à la fin de l'entrée chaque fois qu'il rencontre .*.
. La première fois que .*
apparaît, il consomme toute l'entrée, puis revient en arrière jusqu'à atteindre ORACLE_HOME
. Cette méthode de correspondance n'est pas efficace. L'expression régulière lazy alternative est la suivante :
Trace\sfileRelease:\s*(\S*).*?Machine:\s*(\S*).*?Instance\sname:\s*(\S*).*?Redo\sthread\smounted\sby\sthis\sinstance:\s(\d*).*?Oracle\sprocess\snumber:\s*(\d*).*?Unix\sprocess\spid:\s(\d*).*?image:\s+([^\n\r]*)
L'expression régulière lazy ci-dessus est lue à partir du début de la chaîne jusqu'à ORACLE_HOME
, point auquel elle peut alors mettre en correspondance le reste de la chaîne.
Remarque : si le champ ORACLE_HOME
dans les débuts de l'entrée, le quantificateur lazy doit être utilisé. Si le champ ORACLE_HOME
apparaît vers la fin, il conviendrait d'utiliser le quantificateur à consommation importante de ressources.
Ancrages
Les ancrages indiquent au moteur d'expression régulière que vous comptez placer le curseur à un endroit particulier dans l'entrée. Les ancrages les plus courants sont ^
et $
, indiquant le début et la fin de l'entrée.
Prenons les expressions régulières suivantes pour rechercher une adresse IPv4 :
\d{1,3}\.d{1,3}.\d{1,3}.\d{1,3}
^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
La deuxième expression régulière commence par ^
et est spécifique de l'adresse IP qui apparaît au début de l'entrée.
Nous recherchons l'expression régulière dans l'entrée qui ressemble à l'exemple suivant :
107.21.20.1 - - [07/Dec/2012:18:55:53 -0500] "GET
/extension/bsupport/design/cl/images/btn_letschat.png HTTP/1.1" 200
2144
Une entrée non correspondante ressemblerait à l'exemple suivant :
[07/Dec/2012:23:57:13 +0000] 1354924633 GET "/favicon.ico" "" HTTP/1.1 200 82726 "-"
"ELB-HealthChecker/1.0"
La deuxième expression régulière (commençant par ^
) est exécutée plus rapidement sur l'entrée non correspondante car elle l'annule instantanément.
Importance de l'alternance
L'ordre d'alternance a une importance. Placez donc les options les plus courantes en premier pour qu'elles puissent être mises en correspondances plus rapidement. Si les options les plus rares apparaissent en premier, le moteur d'expression régulière perd du temps à les vérifier avant de vérifier les plus courantes, qui sont plus susceptibles de réussir. Essayez également d'extraire des modèles courants. Par exemple, au lieu de (abcd|abef)
, utilisez ab(cd|ef)
.
Observez les expressions régulières suivantes :
{TIMEDATE}\s{0,1}:\s*(?:|\[)(\w+)(?:\:|\])(?:\[|)(\d+)(?:\:|\])(.{1,1000}).*
{TIMEDATE}\s{0,1}:\s*(?:\[|)(\w+)(?:\:|\])(?:\[|)(\d+)(?:\:|\])(.{1,1000}).*
Sur l'entrée suivante :
2014-06-16 12:13:46.743: [UiServer][1166092608] {0:7:2} Done for
ctx=0x2aaab45d8330
La deuxième expression régulière est mise en correspondance plus rapidement lorsque l'alternance cherche le caractère [
en premier, suivi de null. La correspondance est plus rapide car l'entrée possède le caractère [
.
Exemples d'expression d'analyse
Vous pouvez vous reporter aux exemples d'expression d'analyse suivants afin de créer une expression d'analyse appropriée pour extraire des valeurs du fichier journal.
Un fichier journal comprend des entrées générées par la concaténation de plusieurs valeurs de champ. Vous n'aurez peut-être pas besoin de visualiser toutes les valeurs de champ pour analyser un fichier journal d'un format particulier. A l'aide d'un analyseur, vous pouvez extraire uniquement les valeurs des champs que vous voulez visualiser.
L'analyseur extrait les champs d'un fichier journal en fonction de l'expression d'analyse que vous avez définie. L'expression d'analyse est écrite sous la forme d'une expression régulière qui définit un modèle de recherche. Dans l'expression d'analyse, vous placez les modèles de recherche entre parenthèses () pour chaque champ correspondant à extraire d'une entrée de journal. Les valeurs correspondant à un modèle de recherche en dehors des parenthèses ne sont pas extraites.
Exemple 1
Si vous voulez analyser les exemples d'entrée de journal suivants :
Jun 20 15:19:29 hostabc rpc.gssd[2239]: ERROR: can't open clnt5aa9: No such file or directory
Jul 29 11:26:28 hostabc kernel: FS-Cache: Loaded
Jul 29 11:26:28 hostxyz kernel: FS-Cache: Netfs 'nfs' registered for caching
L'expression d'analyse doit être la suivante :
(\S+)\s+(\d+)\s(\d+):(\d+):(\d+)\s(\S+)\s(?:([^:\[]+)(?:\[(\d+)\])?:\s+)?(.+)
Dans l'exemple précédent, voici certaines des valeurs capturées par l'expression d'analyse :
-
(\S+)
: plusieurs caractères imprimables pour le mois -
(\d+)
: plusieurs caractères imprimables pour le jour -
(?:([^:\[]+)
(facultatif) : tous les caractères, sauf ^, :, \, [] ; nom du service -
(.+)
(facultatif) : contenu de message principal
Exemple 2
Si vous voulez analyser les exemples d'entrée de journal suivants :
####<Apr 27, 2014 4:01:42 AM PDT> <Info> <EJB> <host> <AdminServer> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <OracleSystemUser> <BEA1-13E2AD6CAC583057A4BD> <b3c34d62475d5b0b:6e1e6d7b:143df86ae85:-8000-000000000000cac6> <1398596502577> <BEA-010227> <EJB Exception occurred during invocation from home or business: weblogic.ejb.container.internal.StatelessEJBHomeImpl@2f9ea244 threw exception: javax.ejb.EJBException: what do i do: seems an odd quirk of the EJB spec. The exception is:java.lang.StackOverflowError>
####<Jul 30, 2014 8:43:48 AM PDT> <Info> <RJVM> <example.com> <> <Thread-9> <> <> <> <1406735028770> <BEA-000570> <Network Configuration for Channel "AdminServer" Listen Address example.com:7002 (SSL) Public Address N/A Http Enabled true Tunneling Enabled false Outbound Enabled false Admin Traffic Enabled true ResolveDNSName Enabled false>
L'expression d'analyse doit être la suivante :
####<(\p{Upper}\p{Lower}{2})\s+([\d]{1,2}),\s+([\d]{4})\s+([\d]{1,2}):([\d]{2}):([\d]{2})\s+(\p{Upper}{2})(?:\s+(\w+))?>\s+<(.*?)>\s+<(.*?)>\s+<(.*?)>\s+<(.*?)>\s+<(.*?)>\s+<(.*?)>\s+<(.*?)>\s+<(.*?)>\s+<\d{10}\d{3}>\s+<(.*?)>\s+<(.*?)(?:\n(.*))?>\s*
Dans l'exemple précédent, voici certaines des valeurs capturées par l'expression d'analyse :
-
(\p{Upper}\p{Lower}{2})
: nom abrégé de 3 lettres du mois ; la première lettre majuscule est suivie de deux lettres minuscules -
([\d]{1,2})
: jour à 1 ou 2 chiffres -
([\d]{4})
: année à 4 chiffres -
([\d]{1,2})
: heures à 1 ou 2 chiffres -
([\d]{2})
: minutes à 2 chiffres -
([\d]{2})
: secondes à 2 chiffres -
(\p{Upper}{2})
: AM/PM à 2 lettres majuscules -
(?:\s+(\w+))
(facultatif, certaines entrées peuvent ne renvoyer aucune valeur) : plusieurs caractères alphanumériques pour le fuseau horaire -
(.*?)
(facultatif, certaines entrées peuvent ne renvoyer aucune valeur) caractères pour le niveau de gravité ; ici,<INFO>
-
(.*)
: détails supplémentaires et message
Modèles de recherche
Certains des modèles couramment utilisés sont expliqués dans le tableau suivant :
Modèle | Description | Exemple |
---|---|---|
. | Tout caractère sauf le saut de ligne | d.f correspond à def, daf, dbf, etc.
|
* | Zéro, une ou plusieurs fois | D*E*F* correspond à DDEEFF, DEF, DDFF, EEFF, etc.
|
? | Une ou zéro fois ; facultatif | colou?r correspond à la fois à colour et à color
|
+ | Au moins une fois | Stage \w-\w+ correspond à Stage A-b1_1, Stage B-a2, etc.
|
{2} | Exactement deux fois | [\d]{2} correspond à 01, 11, 21, etc.
|
{1,2} | Deux à quatre fois | [\d]{1,2} correspond à 1, 12, etc.
|
{3,} | Au moins trois fois | [\w]{3,} correspond à ten, hello, h2134, etc.
|
[ … ] | Un des caractères entre crochets | [AEIOU] correspond à une voyelle majuscule
|
[x-y] | Un des caractères de la plage allant de x à y | [A-Z]+ correspond à ACT, ACTION, BAT, etc.
|
[^x] | Un caractère qui n'est pas x | [^/d]{2} correspond à AA, BB, AC, etc.
|
[^x-y] | Un des caractères hors de la plage allant de x à y | [^a-z]{2} correspond à A1, BB, B2, etc.
|
[\d\D] | Un caractère représentant un chiffre ou non | [\d\D]+ correspond à n'importe quel caractère, y compris aux retours à la ligne, sans correspondance avec le point
|
\s | Un caractère non imprimable | (\S+)\s+(\d+) correspond à AA 123, a_ 221, etc.
|
\S | Un caractère qui n'est pas un caractère non imprimable | (\S+) correspond à abcd, ABC, A1B2C3, etc.
|
\n | Un retour à la ligne | (\d)\n(\w) correspond à ce qui suit :
1 A |
\w | Un caractère alphanumérique | [\w-\w\w\w] correspond à a-123, 1-aaa, etc.
|
\p{Lower} | Lettres minuscules | \p{Lower}{2} correspond à aa, ab, ac, bb, etc.
|
\p{Upper} | Lettres majuscules | \p{Upper} correspond à A, B, C, etc.
|
\ suivi de ?, [], *, . | Caractère d'échappement ; permet d'utiliser les caractères après \ en tant que littéraux | \? renvoie ?
|