Ethan Jarrell „egy kérdést tett fel” a felosztott eredmények listás hozzárendelésével kapcsolatban a hármas operátoron keresztül. A Perl effajta felfedezése, bár szórakoztató és rendkívül tanulságos, egyben része annak is, hogy a Perl az egyszer írható, vonalzajról híres. Ez azonban soha nem mentség arra, hogy ne osszam meg tapasztalataimat.
Ethan megkérdezte: "Ha valakinek van rálátása, azt megköszönném." és biztosan tudok válaszolni, hogy mi a probléma.
Három problémával találkozik. Az egyik a Perl listakiegyenlítő viselkedése, a másik kettő pedig a Perl vesszőoperátora és az osztott függvény működésének félreértése. Nézzük először a lista lapítását. Tudod, hogy ez működik:
my ($var1, $var2) = (100, 200);
és a következőket szeretné elérni:
my (@var3, @var4) = ( (something), (something) );
A Perl listasimító viselkedése azonban azt jelenti, hogy függetlenül attól, hogy mi van a jobb oldalon, minden egy nagy listába kerül, és mindez a @var3-hoz lesz hozzárendelve, és semmi sem kerül a @var4-be. A Perl nagyon szívesen ad üres tömböket, így nincs figyelmeztetés erre a viselkedésre.
Hivatkozásokat kell használnunk, hogy ez a bit működjön:
my ($var3, $var4) = ( [something], [something] )
Hivatkozások hozzáadása szinte azonnal megoldaná a problémát, de részben csak jó szerencsével, így a többi hibára is kitérek.
Először is a vessző operátor. Az esetek többségében az ember hibázik a vesszőoperátorok működésével kapcsolatban, és valamilyen figyelmeztetést kap, például: „A konstans („sáv”) haszontalan használata üres kontextusban a foo.pl 19. sorában. Ezt kapnád, ha valami ostobaságot csinálnál, például:
use warnings; print("foo"), "bar";
Az emberek általában azt feltételezik, hogy a vessző operátor az idő nagy részében „egy is”-ként működik. A felosztások nélküli hármasban ezt próbálja elérni:
my ($arr3, $arr4) = (index($str2, '-') != -1) ? ["partial 1", "partial 2"], ["partial 3", "partial 4"] : ["partial 1a", "partial 2a"], ["partial 3a", "partial 4a"];
Ez nem fordítható le, és az if és akkor opciók körüli zárójelek hiánya kényelmetlenül érzi magát, mert nem egyezik a sablonunkkal:
my ($var1, $var2) = (100, 200);
Tehát ezeket hozzá kell adnunk:
my ($arr3, $arr4) = (index($str2, '-') != -1) ? ( ["partial 1", "partial 2"], ["partial 3", "partial 4"] ) : ( ["partial 1a", "partial 2a"], ["partial 3a", "partial 4a"]); print "array ref 3[0] is: $arr3->[0]\n"; print "array ref 3[1] is: $arr3->[1]\n"; print "array ref 4[0] is: $arr4->[0]\n"; print "array ref 4[1] is: $arr4->[1]\n";
Ez most működik.
Ha csak a fentiek szerint járna el, kijavítaná a kódot, és boldog lenne, de szeretnék egy utolsó, könnyen kihagyható hibára felhívni a figyelmet… A kód a következőket tartalmazza:
split /-/,$str2, split /;/, $str4
A Perl split függvénye 3 argumentumot vehet fel, így biztos vagyok benne, hogy a Perl ezt így olvassa:
split(/-/, $str2, (split /;/, $str4))
Nem tudom, miért nem kapja meg az „Érv… nem numerikus felosztásban” figyelmeztetést, amit általában kap, de nem kap hasznos eredményt sem.
A kód félreértelmezésének ismerete megkönnyíti a fennmaradó javítást. További zárójelek hozzáadása:
(split /-/,$str2), (split /;/, $str4)
Tehát ezt a két javítást kombinálva (és felismerve, hogy most már elhagyhatjuk az extra belső zárójeleket), az egyszerű kezdeti hozzárendelési verzió a következő lesz:
my ($arr3, $arr4) = ( [split /-/,$str2], [split /;/, $str4] )
és ennek megfelelően a hármas megoldás a következő lesz:
my ($arr3, $arr4) = (index($str2, '-') != -1) ? ([split /-/,$str2], [split /;/, $str4]) : ([split /:/,$str2], [split /;/, $str4]);
a teljes megoldással:
use strict; use warnings; my $str2 = 'This string has two sentences - A dash separates them'; my $str4 = 'This string has different punctuation; a semicolon'; my ($arr3, $arr4) = (index($str2, '-') != -1) ? ([split /-/,$str2], [split /;/, $str4]) : ([split /:/,$str2], [split /;/, $str4]); print "array ref 3[0] is: $arr3->[0]\n"; print "array ref 3[1] is: $arr3->[1]\n"; print "array ref 4[0] is: $arr4->[0]\n"; print "array ref 4[1] is: $arr4->[1]\n";
Mindezek után biztosíthatom, hogy ez egy csúnya megoldás.
Az eredeti feltételes kijelentésed (@arr5 és @arr6 esetén) sokkal karbantarthatóbb megoldás (ami azt jelenti, hogy kedvesebb azokhoz, akik 5 év múlva hajnali 2-kor keresik a kódodat, és megpróbálják kijavítani, hogy elmenhessenek. vissza az ágyba…), ha több karakterlánc felosztása egy adott karaktert tartalmazó karakterlánctól függ. Alternatív megoldásként, mivel jelenleg ugyanazt csináljuk a $str4-el, ezt is megtehetjük:
my @arr3; my @arr4 = split /;/, $str4; if( ( @arr3 = split /-/, $str2 ) < 2 ) { @arr3 = split /;/, $str2; } print "array 3[0] is: $arr3[0]\n"; print "array 3[1] is: $arr3[1]\n"; print "array 4[0] is: $arr4[0]\n"; print "array 4[1] is: $arr4[1]\n";
A fenti kód legnagyobb előnye, hogy nem kell indexet hívnunk. Megpróbálhatjuk a felosztást, és ha csak 1 sort kapunk vissza, tudjuk, hogy a felosztás sikertelen volt. :)
Boldog perlinget!