2010-10-26 3 views
4

J'essaie de diviser une chaîne en utilisant la fonction split mais il n'y a pas toujours de valeur entre les tokens.Que retourne la fonction de partage Perl lorsqu'il n'y a pas de valeur entre les jetons?

Ex: ABC, 123 ,,,,,, XYZ

Je ne veux pas sauter les multiples jetons cependant. Ces valeurs sont dans des positions spécifiques dans la chaîne. Toutefois, lorsque je fais une division, puis que j'essaie de parcourir mon tableau résultant, j'obtiens des avertissements «Utilisation d'une valeur non initialisée». J'ai essayé de comparer la valeur en utilisant $splitvalues[x] eq "" et j'ai essayé d'utiliser defined($splitvalues[x]), mais je ne peux pas pour la vie de moi comprendre comment identifier ce que la fonction split est en train de mettre dans mon tableau quand il n'y a pas de valeur entre les jetons.

est ici l'extrait de mon code (maintenant avec bonté plus croquante):

my @matrixDetail =(); 

#some other processing happens here that is based on matching data from the 
#@oldDetail array with the first field of the @matrixLine array. If it does 
#match, then I do the split 
if($IHaveAMatch) 
{ 
    @matrixDetail = split(',', $matrixLine[1]); 
} 
else 
{ 
    @matrixDetail = ('','','','','','',''); 
} 

my $newDetailString = 
    (($matrixDetail[0] eq '') ? $oldDetail[0] : $matrixDetail[0]) 
. (($matrixDetail[1] eq '') ? $oldDetail[1] : $matrixDetail[1]) 
    . 
    . 
    . 
. (($matrixDetail[6] eq '') ? $oldDetail[6] : $matrixDetail[6]); 

parce que c'est seulement des extraits, j'ai laissé une partie de l'autre logique, mais l'instruction if est à l'intérieur d'un sous cela retourne techniquement le tableau @matrixDetail. Si je ne trouve pas de correspondance dans ma matrice et que je mets le tableau à égalité avec le tableau de chaînes vides manuellement, je n'obtiens aucun avertissement. C'est seulement lorsque le split remplit le @matrixDetail.

Aussi, je devrais mentionner, j'ai écrit du code depuis près de 15 ans, mais seulement très récemment j'ai eu besoin de travailler avec Perl. La logique dans mon script est solide (ou du moins, ça marche), je suis juste en train d'être anal pour nettoyer mes avertissements et essayer de comprendre cette petite nuance.

+1

@matrixDetail ou @oldDetail n'ont pas 7 éléments, ou @oldDetail a des éléments non définis. Déterminez lequel avec Data :: Dumper. Split renvoie des éléments définis si la chaîne d'origine est définie, c'est juste une question de nombre d'éléments. – runrig

+0

un nombre incorrect d'éléments dans mes tableaux semble être un thème commun. Mais je sais que j'ai les bons chiffres. Comme je l'ai mentionné. Le script fonctionne, j'obtiens la sortie désirée que j'utilise le split ou non. Mais si j'utilise le split, et qu'il y a des champs vides dans la chaîne que je partage, alors je reçois des avertissements. Je veux résoudre les avertissements. – MitchelWB

+2

Une chaîne vide ne vous donnera pas les avertissements de valeur non initialisée. Il y a quelque chose d'autre qui ne va pas dans votre programme et qui n'est pas lié à des chaînes vides ou aux valeurs renvoyées par 'split'. – CanSpice

Répondre

4
#!perl 

use warnings; 
use strict; 
use Data::Dumper; 

my $str = "ABC,123,,,,,,XYZ"; 
my @elems = split ',', $str; 
print Dumper \@elems; 

Cela donne:

$VAR1 = [ 
      'ABC', 
      '123', 
      '', 
      '', 
      '', 
      '', 
      '', 
      'XYZ' 
     ]; 

Il met dans une chaîne vide. Notez que le documentation for split() indique que "par défaut, les champs principaux vides sont préservés, et les champs vides vides sont supprimés". Ainsi, si votre chaîne est ABC,123,,,,,,XYZ,,,, alors votre liste retournée sera la même que l'exemple ci-dessus, mais si votre chaîne est ,,,,ABC,123, alors vous aurez une liste avec trois chaînes vides dans les éléments 0, 1 et 2 (en plus de 'ABC' et '123').

Éditez 2: Essayez de supprimer les tableaux @matrixDetail et @oldDetail. Il est probable que l'un de ceux-ci n'est pas la longueur que vous pensez que c'est. Vous pouvez également envisager de vérifier le nombre d'éléments dans ces deux listes avant d'essayer de les utiliser pour vous assurer que vous avez autant d'éléments que vous attendez.

+0

Ceci est essentiellement ce que je fais, voici un extrait de mon code: – MitchelWB

+0

Mettez le code dans votre question. – CanSpice

+0

apparemment, je ne peux pas utiliser la touche d'entrée? Je vais essayer de répondre différemment. C'est la première fois que j'utilise Stack Overflow – MitchelWB

0

Les éléments sans rien entre eux donnent des chaînes vides lorsqu'ils sont divisés. Les chaînes vides évaluent comme false dans un contexte booléen.

Si vous savez que votre entrée « détails » ne contiendra jamais « 0 » (ou un autre scalaire qui évalue false), cela devrait fonctionner:

my @matrixDetail = split(',', $matrixLine[1]); 
die if @matrixDetail > @oldDetail; 

my $newDetailString = ""; 
for my $i (0..$#oldDetail) { 
    $newDetailString .= $matrixDetail[$i] || $oldDetail[$i]; # thanks canSpice 
} 
say $newDetailString; 

(il y a probablement d'autres scalaires en plus une chaîne vide et zéro qui évalue à faux, mais je ne pouvais pas les nommer du haut de ma tête.)

TMTOWTDI:

$matrixDetail[$_] ||= $oldDetail[$_] for 0..$#oldDetail; 
my $newDetailString = join("", @matrixDetail); 

edit: pour les boucles vont maintenant 0-$#oldDetail au lieu de $#matrixDetail depuis fuite ",,," ne sont pas retournés par scission. Edit2: si vous ne pouvez pas être sûr que l'entrée réelle n'évaluera pas comme fausse, vous pouvez toujours tester la longueur de vos éléments séparés. C'est plus sûr, certes, mais peut-être moins élégant^_^

+0

Voir ma modification dans quelques minutes. Je vais ajouter plus à mon extrait. – MitchelWB

+1

C'est le moment idéal de mentionner l'opérateur defined-or, car vous n'avez pas besoin de vous préoccuper des chaînes vides ou des fausses valeurs, lorsque tout ce que vous recherchez est défini-ness. – CanSpice

+0

@CanSpice les chaînes vides renvoyées par split sont définies. – flies

0

Les champs vides au milieu seront ''. Les champs vides à la fin seront omis, sauf si vous spécifiez un troisième paramètre à fractionner suffisamment grand (ou -1 pour tous).

1

Je suggère d'utiliser Text::CSV de CPAN. C'est une solution prête à l'emploi qui couvre déjà tous les cas bizarres de bord de l'analyse des fichiers au format CSV.

Questions connexes