prob sur regexp
Le
Sébastien Cottalorda
Bonjour à tous.
Dans le cadre d'une application manipulant un protocole réseau, je
dois splitter une trame comme suit.
exemple :
bonjour, comment ça va?{ETX}XJe vais bien. Et toi ?{ETX}X{ACK}{NACK}
Je doit splitter comme ceci:
phrase1: bonjour, comment ça va?{ETX}X
phrase2: Je vais bien. Et toi ?{ETX}X
phrase3: {ACK}
phrase{NACK}
j'ai fait comme ceci, mais cela ne marche pas.
use constant ETX => chr( hex('03'));
use constant ACK => chr( hex('06'));
use constant NACK => chr( hex('15'));
my $endcar = ACK.'|'.ETX.'.|'.NACK;
my $phrase = "bonjour, comment ça va?".ETX."XJe vais bien. Et
toi ?".ETX."X".ACK.NACK;
while ($phrase =~ s/([^($endcar(]*($endcar))//){
print "buf=$1";
}
print "résidu = $phrase";
mais j'obtiens:
buf=X
buf=X
buf= Et toi ?
buf=
résidu = bonjour, comment ça va?Je vais bien.
Je ne m'en sort pas.
Je doit splitter ma ligne en fonction:
* soit des ACK,
* soit des NACK,
* soit des ETX suivi d'un caractère quelconque.
Je n'y arrive vraiment pas. C'est le double ETX+caractère qui me
plombe tout.
Car si j'avais uniquement ACK, NACK et ETX, cela fonctionnerait
parfaitement
Merci de votre aide.
Sebastien
Dans le cadre d'une application manipulant un protocole réseau, je
dois splitter une trame comme suit.
exemple :
bonjour, comment ça va?{ETX}XJe vais bien. Et toi ?{ETX}X{ACK}{NACK}
Je doit splitter comme ceci:
phrase1: bonjour, comment ça va?{ETX}X
phrase2: Je vais bien. Et toi ?{ETX}X
phrase3: {ACK}
phrase{NACK}
j'ai fait comme ceci, mais cela ne marche pas.
use constant ETX => chr( hex('03'));
use constant ACK => chr( hex('06'));
use constant NACK => chr( hex('15'));
my $endcar = ACK.'|'.ETX.'.|'.NACK;
my $phrase = "bonjour, comment ça va?".ETX."XJe vais bien. Et
toi ?".ETX."X".ACK.NACK;
while ($phrase =~ s/([^($endcar(]*($endcar))//){
print "buf=$1";
}
print "résidu = $phrase";
mais j'obtiens:
buf=X
buf=X
buf= Et toi ?
buf=
résidu = bonjour, comment ça va?Je vais bien.
Je ne m'en sort pas.
Je doit splitter ma ligne en fonction:
* soit des ACK,
* soit des NACK,
* soit des ETX suivi d'un caractère quelconque.
Je n'y arrive vraiment pas. C'est le double ETX+caractère qui me
plombe tout.
Car si j'avais uniquement ACK, NACK et ETX, cela fonctionnerait
parfaitement
Merci de votre aide.
Sebastien

Poser une question


Le 18/11/2009 15:06, Sébastien Cottalorda a écrit :
Ok.
Pour utiliser dans une classe de caractères, ce serait plutôt :
my $endcar = ACK.ETX.NACK
Quant au test de fin de ligne, vu qu'un {ETX} est suivi d'un X, ce
sera :
my $endcar = ACK.'|'.ETX.'X|'.NACK;
Mais bien sûr, si cela peut être n'importe quel caractère à la place
du X il faut bien, comme tu l'as écrit :
my $endcar = ACK.'|'.ETX.'.|'.NACK;
Seulement, pour bien distinguer ce « . » du caractère de concaténation,
ce serait plus clair avec des espaces (d'ailleurs au début je ne l'avais
pas vu). Donc :
my $endcar = ACK . '|' . ETX . '.|' . NACK;
Euh... ta classe de caractères [^($endcar(] a vraiment une drôle de
gueule. Non seulement elle contient des « | » et un « . » en trop à
cause de la façon dont tu as défini $endcar, mais en plus tu lui
rajoutes deux « ( » !
Je ne connais pas encore perl, mais de ce que je comprends de ton code
et de chances de marcher :
my $noendcar = '[^' . ACK . ETX . NACK . ']';
my $endstring = '(' . ACK . '|' . ETX . '.|' . NACK . ')';
while ($phrase =~ s/$noendcar*$endstring//) {
print "buf=$&n";
}
J'avoue que je ne comprends pas pourquoi tu n'as que X au début.
Mais là, sais-tu pourquoi c'est coupé juste après le « . » ? C'est à
cause du « . » dans ton $endcar !
Et ça, c'est pour la même raison. Dans [^($endcar(], en plus des
caractères ACK, ETX et NACK, tu avais deux caractères « | », deux
caractères « ( » et un caractère « . » !
À tout hasard, je te signale l'existence du forum fr.comp.lang.regexp
qui pourrait convenir aussi, à condition de ne pas avoir trop de code
perl en plus des regexp.
Cordialement,
--
Olivier Miakinen
[snip]
use constant ETX => chr( hex('03'));
use constant ACK => chr( hex('06'));
use constant NACK => chr( hex('15'));
my $phrase = "bonjour, comment ça va?".ETX."XJe vais bien. Et
toi ?".ETX."X".ACK.NACK;
[snip]
print "résidu = $phrasen";
[snip]
Merci pour le lien, je ne le connaissais pas.
J'ai essayé ceci:
my $endcar = ACK . ETX . NACK;
while ($phrase =~ s/([[:^cntrl:]]*($endcar))//){
Ca a l'air de marcher impec, mais j'ai un autre soucis, c'est que le
problème est juste un tout petit peu plus compliqué.
Une vrai trame (in my real life) est comme ceci :
{STX}bonjour, comment ça va?{ETX}X{STX}Je vais bien. Et toi ?{ETX}X
{ACK}{NACK}
(nota: en fait le X qui fait suite à chaque ETX est un checksum
calculé : il est différent à chaque fois)
Là, en appliquant le while j'obtiens:
bonjour, comment ça va?{ETX}X
Je vais bien. Et toi ?{ETX}X
{ACK}
{NACK}
mais j'arrive à un résidu égal à : {STX}{STX}
Si tu vois comment m'en sortir, j'en serai ravi.
Cordialement
Sébastien
Euh... tu es sûr d'avoir vraiment essayé ça ?
Avec $endcar qui est juste la concaténation des trois caractères de
contrôle ???
Oui. Et mon code ne te plaisait pas ? Peut-être n'as-tu pas vu que
j'avais aussi remplacé $1 par $& ?
Avec ma proposition initiale, tu devrais obtenir :
{STX}bonjour, comment ça va?{ETX}X
{STX}Je vais bien. Et toi ?{ETX}X
{ACK}
{NACK}
et un résidu vide.
Si en outre tu veux supprimer les {STX}, alors tu peux essayer ceci :
use constant STX => chr( hex('02'));
use constant ETX => chr( hex('03'));
use constant ACK => chr( hex('06'));
use constant NACK => chr( hex('15'));
my $phrase = STX . "bonjour, comment ça va?" . ETX . "X"
. STX . "Je vais bien. Et toi ?" . ETX . "X"
. ACK . NACK;
my $beginstring = STX . '?';
my $endstring = '(' . ACK . '|' . ETX . '.|' . NACK . ')';
while ($phrase =~ s/$beginstring(.*?$endstring)//) {
print "buf=$1n";
}
print "résidu = $phrasen";
Tu devrais obtenir :
buf=bonjour, comment ça va?{ETX}X
buf=Je vais bien. Et toi ?{ETX}X
buf={ACK}
buf={NACK}
résidu
Enfin, si tu veux aussi supprimer les {ETX}X, {ACK} et {NACK], il suffit
de déplacer une parenthèse :
s/$beginstring(.*?)$endstring//
Cordialement,
--
Olivier Miakinen
Si vous avez des connaissances en manipulations de grammaires, vous
pouvez utiliser une des nombreuses bibliothèques les manipulant :
http://search.cpan.org/search?query...p;mode=all
Comme vous n'avez visiblement pas besoin d'avoir un historique de plus
d'un caractère vous également faire un simple mini-parser en une dizaine
de lignes.
--
Denis Dordoigne
Membre de l'April - promouvoir et défendre le logiciel libre - april.org
Rejoignez maintenant plus de 5 000 personnes, associations,
entreprises et collectivités qui soutiennent notre action
J'avais essayé ceci en fait.
my $endcar = ACK .'|'. ETX . '.|'. NACK;
while ($phrase =~ s/([[:^cntrl:]]*($endcar))//){
Ton code m'allait bien, mais cette expression régulière fait partie
d'un module de gestion de socket que j'ai développé.
Chaque programme utilise plusieurs fois la méthode en lui transmettant
seulement le $endcar, mais pas le $noendcar.
Je ne voulais pas avoir à rechercher tous les appels à la méthode pou r
leur faire transmettre $noendcar en plus.
C'est pourquoi je n'ai pas utilisé tout de suite ta méthode.
Puis, j'ai finalement fini par extraire $noendcar à partir de $endcar.
Comme cela, je n'ai pas besoin de le transmettre.
C'est super.
Topissime ....
Ca fonctionne impec.
Merci beaucoup.