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 :

Substitution de la 2eme occurence d'un motif dans une chaine?


Sujet :

Langage Perl

  1. #1
    Membre à l'essai
    Inscrit en
    Février 2005
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2005
    Messages : 20
    Points : 13
    Points
    13
    Par défaut [RESOLU] Substitution de la 2eme occurence d'un motif dans une chaine?
    Hello,

    Me voilà avec une chaine de caractere suivante:

    $str="4561233030314563031456;

    En fait, ce que je voudrais, c'est substituer la 2eme chaine de caractere "3031" par une valeur 3032 par exemple (et non celle dans 303031)


    Sous Sed, j'ai vu que l'on peut cibler l'occurrence que l'on désire remplacer en ajoutant simplement un indice:
    Mais sous perl, comment faire la même chose avec l'opérateur ~s ?
    ~s ne propose que de substituer la 1er ou toute les occurrences?

    $str=~ s/3031/3032/;

    Merci

  2. #2
    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 : 44
    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
    Tu peux lui signaler que tu as 2 fois le motif mais que tu gardes le premier
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $str =~ s/(3031\d+)3031/$1 3032/;
    $str =~ s/ //;
    je ne sais pas comment séparer $1 de 3032 sans un espace nécessitant une substitution supplémentaire. Ca te donne une idée mais il doit y avoir mieux.
    -- Jasmine --

  3. #3
    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 : 58
    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
    Citation Envoyé par Jasmine80 Voir le message
    je ne sais pas comment séparer $1 de 3032 sans un espace nécessitant une substitution supplémentaire. Ca te donne une idée mais il doit y avoir mieux.
    Comme pour résoudre les problèmes d'interpolation avec une variable scalaire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $str =~ s/(3031\d+)3031/${1}3032/;
    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

  4. #4
    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 : 58
    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
    Sinon, il est également possible de compter les occurrences dans l'expression régulière :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $str =~ s/(3031)/++(my $count) == 2 ? "3032" : "$1"/ge;
    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

  5. #5
    Membre chevronné
    Avatar de I'm_HERE
    Homme Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 013
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 013
    Points : 1 991
    Points
    1 991
    Par défaut
    ou bien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    $str="4561233030314563031456";
    print "$str\n";
    $str=~s/(\d+3031\d+)(3031)(\d+)/$1$\3032$3/;
    print "$str";
    EDIT: mais je vois que les codes de Jasmine80 et Philou67430 sont plus performants

  6. #6
    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 : 44
    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
    ^^ C'est bien, j'apprends de nouvelles choses en essayant d'aider les autres
    -- Jasmine --

  7. #7
    Membre à l'essai
    Inscrit en
    Février 2005
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2005
    Messages : 20
    Points : 13
    Points
    13
    Par défaut
    Citation Envoyé par I'm_HERE Voir le message
    ou bien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    $str="4561233030314563031456";
    print "$str\n";
    $str=~s/(\d+3031\d+)(3031)(\d+)/$1$\3032$3/;
    print "$str";
    EDIT: mais je vois que les codes de Jasmine80 et Philou67430 sont plus performants
    Merci pour le code, mais comme je ne suis pas très à l'aise avec les expressions régulieres, est-ce que quelqu'un pourrait expliciter le code?


    A ce propose, cela a ses limitations, car si on prend la chaine de caractere suivante (qui est la même que l'autre, mais plus longue)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $str="647574187365727669636555303031206576656E755530312064757400"
    La, la subsitution ne marche plus sur la 2eme occurence de 3031 ??

  8. #8
    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 : 58
    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'expression régulière /(\d+3031\d+)(3031)(\d+)/$1$\3032$3/
    cherche le motif (chaque tiret correspond à une sous-chaine extraite, identifiée par la suite $1, $2, $3):
    $1 - au moins un chiffre suivi de 3031 suivi d'au moins un chiffre
    $2 - 3031
    $3 - au moins un chiffre
    et à remplacer cette suite de sous-motifs par :
    - $1 (donc inchangé)
    - 3032 (donc en remplacement de 3031)
    - $3 (donc la troisième partie)

    Mais cette expression régulière souffre de quelques limitations :
    - il faut impérativement que le premier 3031 soit précédé de chiffre (il ne peut pas être en début de chaine)
    - il faut impérativement des chiffres entre le premier et le deuxième 3031, ce qui ne permet pas de matcher "003031303100"
    - il faut impérativement des chiffres après le deuxième 3031 (il ne peut pas se trouver en fin de chaine).
    - suite à ton édition, je rajoute la limitation suivante : on présuppose que les motifs entre les 3031 ne sont composés QUE de chiffres
    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

  9. #9
    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 : 58
    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
    Je te conseille donc plutôt ma 2e proposition :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $str =~ s/(3031)/++(my $count) == 2 ? "3032" : "$1"/ge;
    qui ne subit pas ces limitations et qui est très "générique".
    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

  10. #10
    Membre à l'essai
    Inscrit en
    Février 2005
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2005
    Messages : 20
    Points : 13
    Points
    13
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Je te conseille donc plutôt ma 2e proposition :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $str =~ s/(3031)/++(my $count) == 2 ? "3032" : "$1"/ge;
    qui ne subit pas ces limitations et qui est très "générique".
    ok un grand merci avec ce code, effectivement cela marche
    T'es un champion!


    mais pourquoi malgré cela sur l'autre code:

    , ca ne marche pas avec la chaine

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $str="647574187365727669636555303031206576656E755530312064757400"
    print "$str\n";
    $str=~s/(\d+3031\d+)(3031)(\d+)/$1$\3032$3/;
    print "$str";
    Sinon, ca represente quelle option le e à la fin /ge; dans le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $str =~ s/(3031)/++(my $count) == 2 ? "3032" : "$1"/ge;
    g c'est pour globale, obtenir toute les occurrences, mais le e?

    Merci

  11. #11
    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 : 44
    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
    Citation Envoyé par filpinpin Voir le message
    mais pourquoi malgré cela sur l'autre code:

    , ca ne marche pas avec la chaine

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $str="647574187365727669636555303031206576656E755530312064757400"
    print "$str\n";
    $str=~s/(\d+3031\d+)(3031)(\d+)/$1$\3032$3/;
    print "$str";
    Primo \d ne reconnait que des chiffres or ta chaîne contient une lettre. Tu peux utiliser \w au lieu de \d qui reconnait les chiffres, lettres et l'underscore.
    Secundo, (\d+3031\d+) correspond à $1, (3031) à $2 et (\d+) à $3 ... je ne vois pas l'utilité du $2 et $3 dans ce cas-ci.


    Citation Envoyé par filpinpin Voir le message
    Sinon, ca represente quelle option le e à la fin /ge; dans le code:
    /g permet une recherche globale, donc de tous les cas.
    /e permet d'évaluer la partie droite de /// comme une expression.

    petit guide RegExp
    -- Jasmine --

  12. #12
    Membre à l'essai
    Inscrit en
    Février 2005
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2005
    Messages : 20
    Points : 13
    Points
    13
    Par défaut
    Hello,

    Je reviens sur cette histoire de code, donc bon, j'avais fait une petite fonction pour l'integrer à mon code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    sub updatehexevent_id()
    {
    	my ($str) = @_;
    	$str =~ s/(3031)/++(my $count) == 2 ? "$_[1]" : "$1"/ge;
    	return $str;
    }
    Donc tout marche bien lorsque je compile sous commande dos avec (activePerl 5.10.0 build 1005)

    Par contre, j'ai un serveur apache 2.2 sur la même machine et lorsque j'execute ce bout de code dans un script sous apache, la substitution ne marche plus ?

    C'est fou !
    Y a t'il une explication?
    Merci

  13. #13
    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 : 58
    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
    Es-tu certain que ton script s'exécute vraiment (par exemple, ajoute "TOTO" à la chaine $str avant de la retourner pour bien confirmer qu'il apparait) ?
    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

  14. #14
    Membre à l'essai
    Inscrit en
    Février 2005
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2005
    Messages : 20
    Points : 13
    Points
    13
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Es-tu certain que ton script s'exécute vraiment (par exemple, ajoute "TOTO" à la chaine $str avant de la retourner pour bien confirmer qu'il apparait) ?

    Oui oui le script s'executait bien comme j'affichais les traces en html!

    Alors en fait, je viens de trouver par hasard!
    Dans l'entêtre de mon script pertl , j'avais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #!c:/perl/bin/perl.exe -wT
    et en enlevant -wT, tout marche!!
    Bon pourquoi avoir mis -WT vous me dirait?
    Et bah c'était jute un copier-coller d'un exemple pris sur le net!

    Si quelqu'un sait exactement ce que veut dire ces options?

    -T permet de travailler en Taint mode mais w?


    Merci

  15. #15
    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 : 58
    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
    Le -w est l'équivalent de "use warnings", hautement recommandé (l'un ou l'autre).
    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

  16. #16
    Membre à l'essai
    Inscrit en
    Février 2005
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2005
    Messages : 20
    Points : 13
    Points
    13
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Le -w est l'équivalent de "use warnings", hautement recommandé (l'un ou l'autre).
    D'accord!
    Bon j'ai pas creusé la question , mais pourquoi le mode taint bloquait la substitution?

  17. #17
    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 : 58
    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
    Extrait de la doc :
    -T forces "taint" checks to be turned on so you can test them.
    Ordinarily these checks are done only when running setuid or
    setgid. It's a good idea to turn them on explicitly for programs
    that run on behalf of someone else whom you might not necessarily
    trust, such as CGI programs or any internet servers you might
    write in Perl. See perlsec for details. For security reasons,
    this option must be seen by Perl quite early; usually this means
    it must appear early on the command line or in the #! line for
    systems which support that construct.
    Il me semble raisonnable de laisser l'option dans le cas du CGI, et de comprendre pourquoi le script se comporte alors différemment.
    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

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

Discussions similaires

  1. nb occurences d'un caractere dans une chaine
    Par mariec007 dans le forum Langage SQL
    Réponses: 1
    Dernier message: 23/04/2008, 17h47
  2. remplacer les occurences d'un caractere dans une chaine par un autre
    Par lity7 dans le forum Shell et commandes GNU
    Réponses: 3
    Dernier message: 14/03/2008, 12h02
  3. Réponses: 6
    Dernier message: 14/08/2007, 16h44
  4. Premiere occurence d'un entier dans une chaine
    Par amika dans le forum Langage
    Réponses: 3
    Dernier message: 04/05/2006, 20h04
  5. Compter les occurences d'un car dans une chaine/variable
    Par sherlockfr dans le forum Windows
    Réponses: 2
    Dernier message: 10/11/2005, 07h48

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