Perlo „range“ operatorius

EnC manęs PHP forume paprašė paaiškint, kaip veikia Perlo „range“ operatorius. Nesinori PHP forumą teršti perliniais
dalykais, tad bandysiu tai paaiškinti čia. Beje, visa tai ką čia rašau galima rasti Perlo dokumentacijoje (konsolėje tereikia surinkt perldoc perlop).

Perlo „range“ operatorius žymimas dviem taškais, ir reiškia faktiškai du dalykus. Pirmoji reikšmė yra labai paprasta –
parašius 1..10 gausime reikšmių nuo 1 iki 10 sąrašą (list). Būtent ši operatoriaus reikšmė naudojama masyvų kontekste
(list context – kai reikia jog išraiška grąžintų masyvą, o ne skaliarą). Šitaip labai lengvai galima formuoti masyvus:

my @masyvas = 1..10;
# tas pats kaip @masyvas = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Tačiau pats populiariausias šio dalyko panaudojimo būdas yra cikluose, nes vietoj sunkiai įskaitomo

for($i = 1; $i <= 10; $i++) {
# ... kažką darom 10 kartų
}

galima parašyti trumpai ir aiškiai:

for(1..10) {
# ... kažką darom 10 kartų
}

Kitas dažnas šio operatoriaus panaudojimas tame pačiame kontekste yra masyvų dalijimas (slice):

my @foo = (1, 2, 3, 4, 5, 6);
my @bar = @foo[3..5];
# @bar dabar yra (4, 5, 6);
my @baz = @foo[3..$#foo];
# @bar dabar irgi yra (4, 5, 6);

„Range“ operatoriui galima perduot ne vien skaitmenis, bet ir simbolių eilutes (pagal tam tikrą algoritmą bus didinami simbolių eilutės ASCII kodai), tad šis Perlo sakinys atspausdins visą anglišką abėcėlę:

print for 'a'..'z';

Arba tiesiog:

print 'a'..'z';

Vienas geriausių šio operatoriaus pliusų yra tas, kad jis neužsigrobia daug atminties yra intervalo „neišplečia“ atmintyje jei to būtinai nereikia, tad for(1..1000000) {...} nesukuria laikinojo masyvo su milijonu įrašų.

Jei intervalų sudarymas iš simbolių eilučių atrodo ganėtinai magiškai, tai patys didžiausi stebuklai prasideda tada, kai
„range“ operatorius naudojamas skaliariniame kontekste (kai išraiška turi grąžinti skaliarą, o ne masyvą). Dažniausiai taip šis operatorius naudojamas if sąlygoje. Šis operatorius grąžina 0 (false) iki tol kol kairė šio operatoriaus pusė pradeda
grąžint true, tada grąžina true iki tol kol dešinė pusė pradeda grąžint true. Lengviausia turbūt suprast pavyzdžiu:

while(<>) {
print if /PRADZIA/../PABAIGA/;
}

Šis kodas skaito iš bylos eilutes, ir spausdina tik tas, kurios yra tarp eilučių, atitinkančių įpraiškas /PRADZIA/ ir
/PABAIGA/. Tarkime jei byla bus:

foo
bar
PRADZIA
kazkas
dar
PABAIGA
nu
gi

bus atspausdinama tik kazkas ir dar (nespausdina kol neatitinka įpraiškos /PRADZIA/, o tada spausdina iki tol kol atitinka įpraišką /PABAIGA/) Magija čia nesibaigia. Jei vietoj įpraiškos įrašysim skaičių, jis bus magiškai lyginamas su $., kuris reiškia eilutės numerį. Tad kodas

print if 101..200;

atspausdins antrąjį šimtą eilučių.