OVH Cloud OVH Cloud

Problème découpage chaine de caractères

3 réponses
Avatar
Sébastien Cottalorda
Bonjour,

J'ai un soucis avec ce script:

-----------------------------------------------
#!/usr/bin/perl -w
use strict;
my $endcar = pack ('C',2);
my $phrase = "Salut seb comment$endcar";
$phrase .= "vas-tu ?$endcar";
$phrase .= "moi, je vais bien\nEt toi ?$endcar";
my $ligne;
my $cpt=0;
while ( $phrase =~ s/(.*$endcar)// ){
$ligne = $1;
print "OUT>$cpt-|$ligne|\n";
$cpt++;
}
print "OUT>'$phrase'\n";
exit;
------------------------------------------------

Je voudrais obtenir:
OUT>0-|Salut seb comment|
OUT>1-|vas-tu ?|
OUT>2-|moi, je vais bien
Et toi?|
OUT>''
A la fin, $phrase devrait être égal à une chaine vide


Mais j'obtiens en fait:
OUT>0-|Salut seb commentvas-tu ?|
OUT>1-|Et toi ?|
OUT>'moi, je vais bien
'

Quelqu'un a t'il une idée ?
Cela vient sûrement de ma boucle while, mais je ne sais comment régler cela.

Merci de toute aide.

Sébastien

3 réponses

Avatar
Nicolas George
Sébastien Cottalorda wrote in message
<4486c83b$0$13053$:
while ( $phrase =~ s/(.*$endcar)// ){


Tu as ici deux phénomènes qui se combinent pour rendre le résultat assez
compréhensible :

- Par défaut, .* va bouffer aussi loin que possible, y compris le endcar.
Pour remédier à ça, on peut utiliser .*?, qui bouffe le plus court
possible à la place, ou bien expliciter [^$endcar]*.

- Mais par défaut toujours, . ne peut pas reconnaître un n, ce qui fait que
dans le cas présent, le premier passage bouffe tout du début au dernier
endcar avant le retour à la ligne, le second passage bouffe tout du retour
à la ligne à la fin, et il reste le bout avant le retour à la ligne.

En corrigeant le tout on obtient :

while($phrase =~ s/([^$endcar]*$endcar)//) {

ou :

while($phrase =~ s/(.*?*$endcar)//s) {

Quelques remarques :

- Personnellement, je mettrais un ^ pour forcer. Même si tel quel ce n'est
pas nécessaire, c'est plus explicite, donc robuste aux erreurs de
programmation.

- Il serait intéressant d'ajouter le flag o, puisque endcar est constant.

- Est-ce voulu que le endcar soit inclus dans la chaîne capturée ?

- Il serait probablement plus efficace d'utiliser une capture globale ou un
découpage :

for my $subphrase (split $endcar, $phrase)

ou

for my $subphrase ($phrase =~ /([^$endcar]*$endcar)/g)

Avatar
Sébastien Cottalorda
Sébastien Cottalorda wrote in message
<4486c83b$0$13053$:

while ( $phrase =~ s/(.*$endcar)// ){



Tu as ici deux phénomènes qui se combinent pour rendre le résultat assez
compréhensible :

- Par défaut, .* va bouffer aussi loin que possible, y compris le endcar.
Pour remédier à ça, on peut utiliser .*?, qui bouffe le plus court
possible à la place, ou bien expliciter [^$endcar]*.

- Mais par défaut toujours, . ne peut pas reconnaître un n, ce qui fait que
dans le cas présent, le premier passage bouffe tout du début au dernier
endcar avant le retour à la ligne, le second passage bouffe tout du retour
à la ligne à la fin, et il reste le bout avant le retour à la ligne.

En corrigeant le tout on obtient :

while($phrase =~ s/([^$endcar]*$endcar)//) {

ou :

while($phrase =~ s/(.*?*$endcar)//s) {

Quelques remarques :

- Personnellement, je mettrais un ^ pour forcer. Même si tel quel ce n'est
pas nécessaire, c'est plus explicite, donc robuste aux erreurs de
programmation.

- Il serait intéressant d'ajouter le flag o, puisque endcar est constant.

- Est-ce voulu que le endcar soit inclus dans la chaîne capturée ?

- Il serait probablement plus efficace d'utiliser une capture globale ou un
découpage :

for my $subphrase (split $endcar, $phrase)

ou

for my $subphrase ($phrase =~ /([^$endcar]*$endcar)/g)


Salut,

La solution:

while($phrase =~ s/([^$endcar]*$endcar)//) { ...

me convient parfaitement. En fait, $phrase est un buffer de socket.

J'ai donc besoin de découper la réception en fonction de mon caractère
de fin, mais il faut que je "vide" également $phrase afin de pas traiter
plusieurs fois le même message.

Voilà pourquoi j'avais une substitution dans la boucle while.

Merci pour ton aide.

Sébastien


Avatar
cmic
Hello, Sebastien.


Sébastien Cottalorda wrote in message
<4486c83b$0$13053$:

while ( $phrase =~ s/(.*$endcar)// ){



Tu as ici deux phénomènes qui se combinent pour rendre le résulta t assez
compréhensible :

- Par défaut, .* va bouffer aussi loin que possible, y compris le end car.
Pour remédier à ça, on peut utiliser .*?, qui bouffe le plus co urt
possible à la place, ou bien expliciter [^$endcar]*.

- Mais par défaut toujours, . ne peut pas reconnaître un n, ce qui fait que



Ben moi j'aurais fait comme ça (mais je ne suis un Perl Guru...) Le
/ms pour pouvoir
reconnaitre les sauts de ligne dans la chaine. Le *? pour faire en
sorte qu"on "ne bouffe pas jusqu'a la fin de chaine" comme dit Nicolas.
...
while ( $phrase =~ s/(.*?)$endcar//ms ){
...

--
Michel Marcon aka cmic

dans le cas présent, le premier passage bouffe tout du début au d ernier
endcar avant le retour à la ligne, le second passage bouffe tout du retour



...