IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Perl Discussion :

expression régulière complexe


Sujet :

Langage Perl

  1. #1
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut expression régulière complexe
    Bonjour à tous,


    J'a un fichier excel, contenant plusieurs lignes que je lis et peux ensuite placer dans un array, ou un string, peu importe, ce qui est le plus simple.

    J'ai trois valeurs possibles, fixes :
    777
    888
    999

    Disons que j'appelle V si la valeur est une des ces 3 possibilités et X si c'est autre chose.

    Je voudrais vérifier que la ligne est de type différent de XXXXVVVVVVVVVVVVVVVVVVVVVVVVV ou XXVVVVVVVVVVVVVVVVVVVVVVVVVVV en bref (X)i(V)j avec i+j inconstant car les dernières valeurs des lignes peuvent être manquantes. Je veux ne garder que les lignes de type : XXXXVVVVXVVVVVXVVVVVXVVVVV ... où les V sont espacés par au moins un X (et aucun V ça convient également).

    La ligne commence toujours par quelques X, lesquels suivis soit que de X, que de V, ou d'un mélange des 2. Une ligne ne contenant que des X est à garder.

    X peut-être n'importe quoi, alphanumérique, des caractères de ponctuation, des espaces. C'est parfois même quelques phrases.

    Si X est en fin de ligne, il peut être vide (ligne plus courte de 1 ou plusieurs valeurs).

    Exemple de données :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ID	Schedule	Diagnosis	Subject age (days)	BAIYOUTHSELF[1]	BAIYOUTHSELF[2]	BAIYOUTHSELF[3]	BAIYOUTHSELF[4]	BAIYOUTHSELF[5]	BAIYOUTHSELF[6]	BAIYOUTHSELF[7]	BAIYOUTHSELF[8]	BAIYOUTHSELF[9]	BAIYOUTHSELF[10]	BAIYOUTHSELF[11]	BAIYOUTHSELF[12]	BAIYOUTHSELF[13]	BAIYOUTHSELF[14]	BAIYOUTHSELF[15]	BAIYOUTHSELF[16]	BAIYOUTHSELF[17]	BAIYOUTHSELF[18]	BAIYOUTHSELF[19]	BAIYOUTHSELF[20]	Total Score	Anxiety Score	TT
    3.25322E+11	A	TX	9886	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	999		
    8.48677E+11	A	UVSX	8497	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	999		
    5.88049E+11	B	UVSX	4414	0	1	0	0	1	2	0	0	0	1	1	0	0	0	1	0	0	0	1	0	8	40	32
    3.96869E+11	B	TX	5753	0	0	0	0	0	1	0	0	0	0	0	0	0	0	0	1	0	0	0	0	2	40	62
    1.45898E+11	A	UVSX	8783	777	0	777	777	1	777	777	777	0	777	777	777	777	777	777	777	777	777	777	777	999	21	7
    7.08755E+11	B	UVSX	4525	0	1	0	1	0	0	1	0	0	1	1	0	0	0	0	3	0	1	0	0	9	41	48
    7.84342E+11	B	TX	6049	0	0	0	0	0	1	1	0	1	0	0	0	0	0	0	0	0	0	0	0	3	41	4
    3.96186E+11	A	UVSX	10064	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	999		
    4.94384E+11	A	UVSX	10065	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	999
    J'ai laissé les en-têtes que ce soit plus simple à comprendre. Il y a 2 dernières colonnes, optionnelles, qui ont été ajoutées et contiennent 'Total Score Anxiety Score' et 'TT'. Dans cet exemple, je voudrais supprimer les 2 premières et les 2 dernières lignes. J'ai beaucoup de fichiers à traiter, la majorité n'a pas ces colonnes optionnelles. Dans cet exemple, les lignes à supprimer n'ont pas de dernières valeurs, mais je ne sais pas si c'est toujours le cas.

    Autre exemple de fichier : il ne faut supprimer que la 9ième ligne.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    3.25322E+11	TUIT	A	ASD	8739	1	2	2	1	1	2	2	2	1	2	2	2	1	1	1	1	2	2	777	4	4	777	777	4	6	4	777	4	4	4	777	777	777	777	7	7	1	777	Y	777	777
    8.48677E+11	TUIT	A	ASD	8857	0	1	2	2	0	0	0	2	1	1	1	1	0	0	0	1	2	2	777	777	14	17	777	777	777	16	777	777	777	777	777	777	777	777	10	12	1	Y	Y	Y	Y
    5.88049E+11	TUIT	A	ASD	10779	2	2	2	1	1	2	2	2	1	2	2	2	2	2	2	2	2	2	5	5	28	777	777	28	15	20	777	5	5	5	5	5	15	15	20	15	1	Y	Y	Y	Y
    3.96869E+11	TUIT	A	ASD	9134	1	1	1	0	1	2	0	1	1	1	1	0	0	2	0	0	1	1	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	-2	777	777	777	777
    1.45898E+11	TUIT	A	TD	9797	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	0	777	777	777	777
    7.08755E+11	LCG	A	TD	8860	1	1	1	1	1	0	0	1	1	1	0	0	1	1	1	1	0	0	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	0	777	777	Y	777
    7.84342E+11	LCG	A	TD	7732	1	1	1	0	0	1	1	1	1	1	0	0	1	0	0	1	0	0	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	-2	Y	Y	777	Y
    3.96186E+11	LCG	A	TD	7785	1	0	0	0	1	0	0	0	1	1	0	0	0	0	1	1	0	0	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	0	777	777	777	777
    4.94384E+11	LCG	A	TD	7525	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777
    9.27091E+11	LCG	A	ASD	10064	0	1	2	0	0	0	0	1	1	1	0	0	0	0	0	1	0	0	777	777	20	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	-2	777	777	Y	777
    1.38536E+11	LCG	A	ASD	10065	1	2	0	2	2	1	1	2	2	3	1	2	1	2	1	1	0	0	777	14	777	14	19	777	777	14	19	3	777	3	777	3	777	777	777	777	1	777	777	Y	Y
    Avez-vous des suggestions sur comment procéder ? Qu'est-ce qui serait le plus simple ? Est-ce possible par une seule expression régulière ou plus simple par une boucle testant les valeurs de la ligne une à une ?

    Merci beaucoup pour votre aide,
    -- Jasmine --

  2. #2
    Membre chevronné Avatar de vttman
    Homme Profil pro
    Développeur Mainframe
    Inscrit en
    décembre 2002
    Messages
    1 034
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur Mainframe
    Secteur : Industrie

    Informations forums :
    Inscription : décembre 2002
    Messages : 1 034
    Points : 2 058
    Points
    2 058
    Par défaut
    Bêtement, si l'on substitue / remplace tous les "777","888","999", par rien (ou "") dans notre chaine à analyser
    puis que l'on compare ce résultat à "" : Si "" je vire sinon je garde ?
    Chevronné, chevronné ... plutôt dans le développement depuis FORT FORT longtemps, c'est mon job, ça oui
    A part ça ... Il ne pleut jamais en Moselle !

  3. #3
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    Merci pour ta réponse, mais je ne pense pas que ça fonctionnerait, vu que les lignes ne seront jamais vide à cause des valeurs des X en début de ligne toujours présentes. A moins que je ne supprime toutes les premières valeurs différentes de V et que je coupe ma ligne de donnée pour ne gardé que la fin. je vais y réfléchir.

    Sinon, j'ai changé mon script, toutes mes lignes ont maintenant le même nombre de données, car les cellules vides en fin de tableau (excel) sont remplacée par ''.
    -- Jasmine --

  4. #4
    Membre chevronné Avatar de vttman
    Homme Profil pro
    Développeur Mainframe
    Inscrit en
    décembre 2002
    Messages
    1 034
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur Mainframe
    Secteur : Industrie

    Informations forums :
    Inscription : décembre 2002
    Messages : 1 034
    Points : 2 058
    Points
    2 058
    Par défaut
    On peut avoir ce script ?
    Chevronné, chevronné ... plutôt dans le développement depuis FORT FORT longtemps, c'est mon job, ça oui
    A part ça ... Il ne pleut jamais en Moselle !

  5. #5
    Expert confirmé Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    mars 2009
    Messages
    2 456
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : mars 2009
    Messages : 2 456
    Points : 5 431
    Points
    5 431
    Par défaut
    Tu peux essayer avec ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    perl -ne'print if (/(?:\t(?:777|888|999))++\t\S/ or !/\t(?:777|888|999)(?:\t|$)/)' file
    la première condition vérifie qu'il y a au moins une séquence de 777,888,999 suivie d'autre chose (garanti par le quantificateur possessif), la deuxième consiste juste à accepter les lignes ne contenant aucun 777,888,999.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  6. #6
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    L'algorithme est relativement "complexe", et dans un premier temps, avant de voir s'il est possible de factoriser les traitements, je procèderais ainsi :
    - lecture de tout le fichier dans un tableau de tableaux (en excluant la première ligne avec les entêtes)
    - pour chaque ligne, j'ajoute une colonne (0) par exemple qui contiendra join "", map /777|888|999/ ? "V", "X", @{$table[no_ligne]}[4..32]
    - pour chaque ligne, effectuer le filtrage avec les VX sur le premier élément de la ligne

    Par contre, je ne suis pas sûr d'avoir bien compris le filtrage des lignes avec les VX ...
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  7. #7
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    Merci beaucoup pour toutes vos réponses, je vais voir un peu tout cela et je reviens vers vous !
    -- Jasmine --

  8. #8
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : mai 2012
    Messages : 3 612
    Points : 12 465
    Points
    12 465
    Billets dans le blog
    1
    Par défaut
    Et en ne vérifiant que la fin de la ligne, avec un nombre minimum (à déterminer par toi) de groupes de 777, 888 ou 999:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    print unless /(777|888|999){10,}\s*$/;
    (Ici, j'ai choisi 10 groupes au minimum, à toi d'adapter à tes données.)

  9. #9
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    Mes données sont placées dans un tableau de tableau : $all_values[$col][$row]= $val;

    J'ai suivi le conseil très avisé de Philou et analysé mes fichiers de données, mais je n'ai pas utilisé le map suggéré.

    5 fixes - XV var - 0-33 opt

    1) toujours 5 premières colonnes fixes
    2) puis nombre variable de colonnes avec les 777/888/999 à analyser afin de savoir si je garde ou non la ligne
    3) 0 à 33 dernières colonnes 'optionnelles', généralement vides dans les colonnes à rejeter, mais pas toujours parfois : 777, 999, 0 ou X

    Si je supprime les 5 premières valeurs de la ligne, je dois donc vérifier que j'ai ce motif (lignes à exclure) = {777|888|999}n{777|999|0|X}[0-33]

    Je vais quand même revoir également vos idées et vérifiser que je n'ai pas raté quelque chose d'important. Merci à vous tous.
    -- Jasmine --

  10. #10
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    my $line = '7.08755E+11	LCG	A	TD	8860	1	1	1	1	1	0	0	1	1	1	0	0	1	1	1	1	0	0	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	0	777	777	Y	777';
    print join "", map /777|888|999/ ? "V" : "X", split ("\t", $line)[5..10];
    En utilisant [5..10], le code ci-dessus ne fonctionne plus.
    Comment faire pour prendre toutes les valeurs de l'array sauf les 5 premières ?

    Merci.
    -- Jasmine --

  11. #11
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Il faut écrire : @array[5 .. $#$array]
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  12. #12
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    my $line = '7.08755E+11	LCG	A	TD	8860	1	1	1	1	1	0	0	1	1	1	0	0	1	1	1	1	0	0	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	777	0	777	777	Y	777';
    my @tab = split ("\t", $line);
    print join "", map /777|888|999/ ? "V" : "X", @tab[5 .. $#tab];
    A oui, sur deux lignes ça fonctionne, merci Philou.
    -- Jasmine --

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Expression régulière complexe
    Par framelet dans le forum Algorithmes et structures de données
    Réponses: 4
    Dernier message: 27/02/2015, 15h56
  2. Recherche de chaîne avec une expression régulière complexe
    Par mdriesbach dans le forum Général Python
    Réponses: 4
    Dernier message: 28/07/2009, 23h46
  3. Expression régulière complexe
    Par HappyTreeFred dans le forum Général JavaScript
    Réponses: 14
    Dernier message: 17/06/2009, 12h24
  4. Expressions réguliéres
    Par Tooms dans le forum Langage
    Réponses: 4
    Dernier message: 06/12/2002, 19h42
  5. Réponses: 5
    Dernier message: 11/06/2002, 16h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo