Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

prob sur regexp

15 réponses
Avatar
Sébastien Cottalorda
Bonjour =E0 tous.
Dans le cadre d'une application manipulant un protocole r=E9seau, je
dois splitter une trame comme suit.
exemple :

bonjour, comment =E7a va?{ETX}XJe vais bien. Et toi ?{ETX}X{ACK}{NACK}

Je doit splitter comme ceci:
phrase1: bonjour, comment =E7a 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 =3D> chr( hex('03'));
use constant ACK =3D> chr( hex('06'));
use constant NACK =3D> chr( hex('15'));
my $endcar =3D ACK.'|'.ETX.'.|'.NACK;
my $phrase =3D "bonjour, comment =E7a va?".ETX."XJe vais bien. Et
toi ?".ETX."X".ACK.NACK;
while ($phrase =3D~ s/([^($endcar(]*($endcar))//){
print "buf=3D$1\n";
}
print "r=E9sidu =3D $phrase\n";


mais j'obtiens:
buf=3DX
buf=3DX
buf=3D Et toi ?
buf=3D
r=E9sidu =3D bonjour, comment =E7a 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=E8re quelconque.

Je n'y arrive vraiment pas. C'est le double ETX+caract=E8re qui me
plombe tout.
Car si j'avais uniquement ACK, NACK et ETX, cela fonctionnerait
parfaitement

Merci de votre aide.
Sebastien

10 réponses

1 2
Avatar
Olivier Miakinen
Bonjour,

Le 18/11/2009 15:06, Sébastien Cottalorda a écrit :

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}



Ok.

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;



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;

my $phrase = "bonjour, comment ça va?".ETX."XJe vais bien. Et
toi ?".ETX."X".ACK.NACK;
while ($phrase =~ s/([^($endcar(]*($endcar))//){



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 « ( » !

print "buf=$1n";
}
print "résidu = $phrasen";



Je ne connais pas encore perl, mais de ce que je comprends de ton code
et de <http://www.perl.com/doc/manual/html/pod/perlre.html> ceci a des
chances de marcher :

my $noendcar = '[^' . ACK . ETX . NACK . ']';
my $endstring = '(' . ACK . '|' . ETX . '.|' . NACK . ')';
while ($phrase =~ s/$noendcar*$endstring//) {
print "buf=$&n";
}

mais j'obtiens:
buf=X
buf=X



J'avoue que je ne comprends pas pourquoi tu n'as que X au début.

buf= Et toi ?



Mais là, sais-tu pourquoi c'est coupé juste après le « . » ? C'est à
cause du « . » dans ton $endcar !

buf > résidu = bonjour, comment ça va?Je vais bien.



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 « . » !

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. [...]



À 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
Avatar
Sébastien Cottalorda
Merci de ta réponse .


[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]

 my $noendcar = '[^' . ACK . ETX . NACK . ']';
 my $endstring = '(' . ACK . '|' . ETX . '.|' . NACK . ')';
 while ($phrase =~ s/$noendcar*$endstring//) {
     print "buf=$&n";
 }



print "résidu = $phrasen";

[snip]


À 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.



Merci pour le lien, je ne le connaissais pas.

Cordialement,
--
Olivier Miakinen




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
Avatar
Olivier Miakinen
Le 18/11/2009 17:50, Sébastien Cottalorda m'a répondu :

my $noendcar = '[^' . ACK . ETX . NACK . ']';
my $endstring = '(' . ACK . '|' . ETX . '.|' . NACK . ')';
while ($phrase =~ s/$noendcar*$endstring//) {
print "buf=$&n";
}



J'ai essayé ceci:
my $endcar = ACK . ETX . NACK;
while ($phrase =~ s/([[:^cntrl:]]*($endcar))//){



Euh... tu es sûr d'avoir vraiment essayé ça ?

Ca a l'air de marcher impec,



Avec $endcar qui est juste la concaténation des trois caractères de
contrôle ???

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)



Oui. Et mon code ne te plaisait pas ? Peut-être n'as-tu pas vu que
j'avais aussi remplacé $1 par $& ?

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}



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
Avatar
Denis Dordoigne
Bonjour,

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}


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=LALR&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
Avatar
Sébastien Cottalorda
On 19 nov, 00:03, Olivier Miakinen <om+ wrote:
Le 18/11/2009 17:50, Sébastien Cottalorda m'a répondu :



>>  my $noendcar = '[^' . ACK . ETX . NACK . ']';
>>  my $endstring = '(' . ACK . '|' . ETX . '.|' . NACK . ')';
>>  while ($phrase =~ s/$noendcar*$endstring//) {
>>      print "buf=$&n";
>>  }

> J'ai essayé ceci:
> my $endcar = ACK . ETX . NACK;
> while ($phrase =~ s/([[:^cntrl:]]*($endcar))//){

Euh... tu es sûr d'avoir vraiment essayé ça ?



J'avais essayé ceci en fait.
my $endcar = ACK .'|'. ETX . '.|'. NACK;
while ($phrase =~ s/([[:^cntrl:]]*($endcar))//){

> Ca a l'air de marcher impec,

Avec $endcar qui est juste la concaténation des trois caractères de
contrôle ???

> 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)

Oui. Et mon code ne te plaisait pas ? Peut-être n'as-tu pas vu que
j'avais aussi remplacé $1 par $& ?



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.

> 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}

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 =



C'est super.

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



Topissime ....
Ca fonctionne impec.
Merci beaucoup.
Avatar
Paul Gaborit
À (at) Wed, 18 Nov 2009 06:06:44 -0800 (PST),
Sébastien Cottalorda écrivait (wrote):

[...]
use constant ETX => chr( hex('03'));
use constant ACK => chr( hex('06'));
use constant NACK => chr( hex('15'));


[...]

J'arrive un peu après la bataille alors je ne reprends que cette
partie de code. Pour coder directement des caractères de contrôles
dans une chaîne (ou dans une regexp), il y a plein de moyens. Ici par
exemple, je suggère l'emploi de x{..}. Ce qui donne :

use constant ETX => "x{03}";
use constant ACK => "x{06}";
use constant NAK => "x{15}"; # NAK est l'appellation traditionnelle

Il y a plein d'autres moyens de faire cela. Pour en savoir plus, il
faut lire perlrebackslash :

% perldoc perlrebackslash

(documentation qui n'est pas encore traduite.)

--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Perl en français - <http://perl.mines-albi.fr/>
Avatar
Jogo
Sur fr.comp.lang.perl, Olivier Miakinen disait :

while ($phrase =~ s/$beginstring(.*?$endstring)//) {
print "buf=$1n";
}



Je ne comprend pas l'utilisation de la substitution ici. Pourquoi ne
pas faire :

while ($phrase =~ /$beginstring(.*?$endstring)/g) {
print "buf=$1n";
}

--
Très honnetement, je crois que tant qu'on mettra de l'affectif dans
la gestion des forums et plus généralement dans la façon d'aborder
ce média, on ne pourra rien faire de bien.
-- Hervé Petit dans fufe --
Avatar
espie
In article ,
Jogo wrote:
Sur fr.comp.lang.perl, Olivier Miakinen disait :

while ($phrase =~ s/$beginstring(.*?$endstring)//) {
print "buf=$1n";
}



Je ne comprend pas l'utilisation de la substitution ici. Pourquoi ne
pas faire :

while ($phrase =~ /$beginstring(.*?$endstring)/g) {
print "buf=$1n";
}



Deja, ca ne va pas afficher la meme chose...
Avatar
Jogo
>>> while ($phrase =~ s/$beginstring(.*?$endstring)//) {
print "buf=$1n";
}



Je ne comprend pas l'utilisation de la substitution ici. Pourquoi
ne pas faire :

while ($phrase =~ /$beginstring(.*?$endstring)/g) {
print "buf=$1n";
}



Deja, ca ne va pas afficher la meme chose...



À part pour le résidu, si. Teste pour t'en convaincre.

--
AB>Je trouve consternant ce refus de réponse, et je joins donc mon
AB>indignation à celle de Philippe.
Ça me semble un peu disproportionné comme sanction.
-+- Greg in GNU : Seigneur, protégez neuneu de ses amis -+-
Avatar
espie
In article ,
Jogo wrote:
while ($phrase =~ s/$beginstring(.*?$endstring)//) {
print "buf=$1n";
}



Je ne comprend pas l'utilisation de la substitution ici. Pourquoi
ne pas faire :

while ($phrase =~ /$beginstring(.*?$endstring)/g) {
print "buf=$1n";
}



Deja, ca ne va pas afficher la meme chose...



À part pour le résidu, si. Teste pour t'en convaincre.


Ben non. Dans un cas tu affiches le seul element substitue, dans l'autre
cas, tu affiches le 1er de n elements. C'est pas du tout pareil.

Alors, si c'est ca que tu entends par "a part pour le residu".

Mais bon, en gros tu dis que "c'est pareil, sauf que c'est different..."
1 2