Mennyi az annyi?
A karakterláncok kezelése közben az egyik leggyakrabban használt információ a karakterlánc hossza. A REXX-ben ennek a megállapítására a LENGTH függvényt használhatjuk, amelynek visszatérési értéke a paraméterként megadott karakterlánc hossza:
hossz = LENGTH('A net.Times az OS/2 Times utoda')
A példában megadott hossz változó értéke 31 lesz a szerkezet kiértékelése után, mivel a REXX a szóközöket is beszámolja. A WORDS utasítással megszámolhatjuk a karakterláncban található szavakat. Ha a fenti példát a következôképpen módosítjuk, akkor viszont 6 lesz a hossz változó értéke:
hossz = WORDS('A net.Times az OS/2 Times utoda')
Rendelkezésre áll még a WORDLENGTH függvény is, amellyel egy karakterláncban található szó hosszát kérdezhetjük le:
/* Kinyomtatja a karakterlánc második szavának hosszát (9). */
SAY WORDLENGTH('A net.Times az OS/2 Times utoda', 2)
Karakterláncok alakítása
Az adatkonverzió, ezen belül pedig a szövegkonverzió az egyik leggyakrabban megvalósított programfunkció. A REXX nyelv nagyon alkalmas erre a feladatra, s ezt a jó tulajdonságát többek között a sokoldalú TRANSLATE funkciónak is köszönheti. Az alapértelmezés szerint a TRANSLATE nagybetûs alakra formálja át a paraméterként beadott karakterláncot, azonban megfelelôen definiált konverziós táblázatokkal ennél sokkal többre is képes. A szintakszis a következô:
TRANSLATE( karakterlánc [, kimeneti_táblázat, bemeneti_táblázat, pótkarakter])
A bemeneti és kimeneti táblázatok írják le, hogy mely karaktereket és mire akarjuk transzformálni. Ha a bemeneti táblázat ugyanazt a karaktert kétszer is tartalmazza, akkor a karakter elsô elôfordulása számít. Amikor mindkét tábla hiányzik, a nagybetûs konverzió történik. Ha csak a bemeneti tábla hiányzik, akkor az ugyanazt jelenti, mintha a bemeneti táblának az összes karaktert megadtuk volna. Amennyiben a kimeneti tábla hiányzik, akkor az egy üres karakterlánccal lesz helyettesítve és szükség esetén megtoldódik egy, a pótkarakterekbôl álló karakterlánccal. A pótkarakter alapértelmezés szerinti értéke a szóköz. Lássunk néhány példát a TRANSLATE használatára:
/* Nagybetûs konverzió */
SAY TRANSLATE('A net.Times az OS/2 Times utoda')
/* A szóközöket kicseréljük kötôjelre */
SAY TRANSLATE('A net.Times az OS/2 Times utoda', '-', ' ')
/* A jelszó helyett csillagokat jelenítünk meg */
SAY TRANSLATE('password', , , '*')
A ki és bemeneti táblázatok készítésére nagyon alkalmas az XRANGE függvény, amely egy karakterláncot tölt fel:
/* Az összes nagybetû */
input = XRANGE('A', 'Z')
/* Az összes kisbetû */
output = XRANGE('a', 'z')
Gyakran találkozunk olyan karakterláncokkal, amelyek szóköz karakterekkel kezdôdnek, vagy végzôdnek. A STRIP függvénnyel eltávolíthatjuk ôket, ha zavaróak:
SAY STRIP(' abcd ', 'Leading') /* Eredmény: 'abcd ' */
SAY STRIP(' abcd ', 'Trailing') /* Eredmény: ' abcd' */
SAY STRIP(' abcd ', 'Both') /* Eredmény: 'abcd' */
A Leading, Trailing és Both paramétereknek elég csak a kezdôbetûjét megadni. Ha nem adunk meg semmit, akkor az alapértelmezés szerinti érték a B (Both) lép életbe. A szóközön kívül más karaktereket is levághatunk a karakterlánc elejérôl vagy végérôl, ha a levágandó karaktert a harmadik paraméterként definiáljuk:
SAY STRIP('xxxxabcdxxxx', 'B', 'x') /* Eredmény: 'abcd' */
Sokkal ritkábban van szükségünk a REVERSE függvényre, amely tükrözve adja vissza a bemeneti karakterláncot. Valószínûleg sokan nem is tudják elképzelni, hogy erre a függvényre szükség lehet, pedig nagyon jól jön akkor, ha pl. egy karakterlánc utolsó karaktereit kell manipulálni.
Decimális és hexadecimális konverzió
A számítógépek többsége numerikus formában tárolja a karaktereket. A legtöbb PC-n az ASCII (American Standard Code for Information Interchange) kódolás használatos. Bármilyen ASCII karaktert megjeleníthetünk, ha lenyomva tartjuk az ALT billentyût és a numerikus billentyûk segítségével begépeljük a karakter ASCII kódját. Az ALT-65 bevitele pl. az A betût jeleníti meg. Jó néhány beépített REXX függvény létezik, melyekkel a karakterek és kódok közötti átalakítás elvégezhetô. Talán a leggyakrabban használt konverzió a D2C, amely segítségével tizes számrendszerû kódokat alakíthatunk karakterekké. A Hello szót pl. az alábbi bonyolult módon is kiírathatjuk a D2C felhasználásával:
SAY D2C(72) D2C(101) D2C(108) D2C(108) D2C(111)
A fordított irányú konverzióra a C2D függvény használható. Hasonló a funkciót valósítanak meg az X2C és C2X függvények, csak ezek éppen hexadecimális (16-os számrendszer alapú) kódok alapján mûködnek. Az alábbi táblázatban összefoglaltuk a karakterkonverziós függvényeket.
| Konverzió: | Függvény: | Példa: | Eredmény: |
| Karakter decimális kóddá | C2D | C2D('a') | 97 |
| Decimális kód karakterré | D2C | D2C(97) | a |
| Karakter hexakóddá | C2X | C2X('a') | 61 |
| Hexakód karakterré | X2C | X2C('61') | a |
A következô program segítségével megtudhatjuk a begépelt karakterek decimális és hexadecimális kódját:
/* Példaprogam a kódok visszafejtésére */ PARSE ARG karakter IF karakter = '' THEN DO SAY 'Elfelejtetted begépelni a karaktert!' EXIT END SAY 'A(z) 'karakter' decimális és hexadecimális kódjai:' C2D(karakter) C2X(karakter) EXIT
Karakterláncok összeadása
Minden kicsit is komolyabb REXX programban szükség lehet karakterláncok összeadására. Erre több lehetôség is van a REXX-ben. A legegyszerûbbet már tanultuk. Ha két karakterlánc egymás mellett áll egy szerkezetben, akkor a REXX ezeket automatikusan összeadja, azonban a két karakterlánc közé betesz egy szóközt is:
l1 = 'Helló' 'világ' l2 = 'Helló' 'világ' SAY l1 /* Eredmény: Helló világ */ SAY l2 /* Eredmény: Helló világ */
Ha a két karakterláncot úgy akarjuk összeadni, hogy ne legyen közöttük szóköz, akkor használhatjuk az illesztési technikát vagy a || operátort. Az illesztési technika egyszerûen azt jelenti, hogy a karakterláncokat közvetlenül egymás mellé kell helyezni, hogy szóköz nélkül toldja ôket a REXX egybe. Mivel az értelmezônek fel kell ismernie, hogy két eredetileg különálló karakterláncot akarunk egybeolvasztani, ez a konstrukció nem használható azonos formában megadott karakterláncok összeadására. Ilyen esetben a || operátor segítségével lehet a problémát áthidalni. Most pedig lássunk néhány példát:
| Összetoldás: | Eredmény: |
| 'net.' 'Times' | net. Times |
| 'net.' 'Times' | net. Times |
| 'net.''Times' | net.'Times |
| 'net.' || 'Times' | net.Times |
| xxx = 'net.'; xxx'Times | net.Times |
| xxx = 'net.'; yyy = 'Times; xxxyyy | XXXYYY |
| (1 || 2) / 3 | 4 |
A relációs operátorok és a karakterláncok
Amikor a REXX értelmezô két karakterláncot hasonlít össze, akkor elhagyja a karakterláncokból az esetlegesen elôforduló kezdô szóközöket, majd a rövidebb karakterláncot kipótolja szóközökkel, és csak ezután hajtja végre az összehasonlítást karakterenként, balról jobbra haladva. Ez azt jelenti pl. hogy a 'Times ' = ' Times' összehasonlítás értéke igaz. A nagy és kisbetûk természetesen különbözônek számítanak, így pl. egy változó értékének ellenôrzése esetén erre külön figyelni kell:
IF valasz = 'OK' | valasz = 'ok' | valasz = 'Ok' | valasz = 'oK' THEN
Ez persze egyszerûben is megoldható az elôbb tanult TRANSLATE függvénnyel:
IF TRANSLATE(valasz) = 'OK' THEN
Ha pontos összehasonlításra van igényünk, akkor azt a szigorú összehasonlítási operátorokkal tehetjük meg, amelyeket közönséges megduplázással nyerünk a közönséges összehasonlítási operátorokból:
| Operátor: | Jele: | Példa: |
| szigorúan egyenlô | == | a == b |
| szigorúan nem egyenlô | \==, ª== | a \== b |
| szigorúan nagyobb | >> | a >> b |
| szigorúan kisebb | << | a << b |
| szigorúan nagyobb vagy egyenlô | >>= | a >>= b |
| szigorúan kisebb vagy egyenlô | <<= | a <<= b |
| nem szigorúan nagyobb | \>>, ª>> | a ª>> b |
| nem szigorúan kisebb | \<<, ª<< | a ª<< b |
Természetesen az összetoldáshoz és a szigorú összehasonlításhoz használt operátorok is elhelyezhetôk az operátorok kiértékelési sorrendjét tartalmazó táblázatban, amelyik ezután válik teljessé:
| Operátor csoport | Példák | Sorrend |
| unáris operátorok | - + \ ª | Legelsô |
| hatványozás | ** | |
| szorzás, osztás | * / % // | |
| összeadás, kivonás | + - | |
| összetoldás | || illesztés | |
| összehasonlítás | = <> \> >= == \== \>> <<= | |
| logikai és | & | |
| vagy, kizáró vagy | | && | Legutolsó |
Karakterláncok feldarabolása
Az összetoldás ellentéte a feldarabolás. Erre a feladatra is jó néhány függvény létezik a REXX-ben, amelyek két fô csoportba oszthatóak. Az elsô csoportba azok a függvények tartoznak, amelyekkel karakter alapon lehet a darabolást elvégezni. A SUBSTR függvénnyel például a karakterpozíciók megadásával lehet a bemeneti karakterláncból egy részt kivágni:
SAY SUBSTR('Az OS/2 Times utóda a net.Times', 23, 3)
A kiértékelés után a 'net' szó fog megjelenni a képernyôn, mivel a 23 3 paraméterekkel azt kérjük a SUBSTR-tôl, hogy vágja ki a bemeneti karakterláncból a 23. karakternél kezdôdô részt 3 karakter hosszan. Ha a második paramétert elhagyjuk, akkor a kimeneti karakterlánc a 23. karaktertôl az eredeti lánc végéig fog terjedni (net.Times). Ha a kimeneti lánc hosszát meghatározó érték nagyobb, mint amennyi a bemeneti láncból kitelik, akkor a maradék hely pótkarakterrel töltôdik fel. Az alapértelmezés szerinti pótkarakter a szóköz, de ha másra van szükségünk, akkor azt megadhatjuk a parancs negyedik paramétereként:
SAY SUBSTR('Az OS/2 Times utóda a net.Times', 23, 20, '!')
/* Eredmény: net.Times!!!!!!!!!!! */
A SUBSTR közeli rokonai a LEFT és RIGHT függvények. Ezek is a bemeneti karakterláncokat darabolják, azonban automatikusan a lánc bal (LEFT), vagy pedig jobb (RIGHT) oldalából indulnak ki. A második paraméterként megadott szám a kimeneti lánc hosszát szabályozza, s az eredmény szükség esetén kiegészülhet pótkarakterekkel is:
SAY LEFT('Az OS/2 Times utóda a net.Times', 20)
/* Eredmény: Az OS/2 Times utóda */
SAY RIGHT('Az OS/2 Times utóda a net.Times', 11)
/* Eredmény: a net.Times */
A szavakon alapuló daraboló függvények egyike a SUBWORD. Mûködése nagyon hasonlít a SUBSTR-éhez, csak itt éppen a pozíciószámok nem a karakterek, hanem a bemeneti karakterláncban található szavak pozícióját illetve darabszámát jelentik:
SAY SUBWORD('Az OS/2 Times utóda a net.Times', 1, 4)
/* Eredmény: Az OS/2 Times utóda */
SAY SUBWORD('Az OS/2 Times utóda a net.Times', 5)
/* Eredmény: a net.Times */
Egy másik, ugyanebbe a csoportba tartozó függvény a WORD, amely a második paraméterként megadott pozíciójú szót adja vissza. Ez tulajdonképpen a SUBWORD egyik speciális esete:
SAY WORD('tere fere csere bere', 3) /* Eredmény: csere */
SAY SUBWORD('tere fere csere bere', 3, 1) /* Eredmény: csere */
Keresés
Jogosan vetôdik fel a fenti függvények kapcsán, hogy mi van akkor, ha nem tudjuk a pozícióját a kérdéses láncrészletnek vagy szónak. Ebben az esetben keresnünk kell a karakterláncban, és erre kiválóan megfelelnek a POS és LASTPOS függvények. A POS függvény balról jobbra, a LASTPOS pedig jobbról balra haladva keres és találat esetén a felfedezett karakter pozícióját adja vissza:
/* Az elsô \ pozíciója a c:\system\config.sys karakterláncban */
POS('\', 'c:\system\config.sys') /* Eredmény: 3 */
/* Az utolsó \ pozíciója a c:\system\config.sys karakterláncban */
LASTPOS('\', 'c:\system\config.sys') /* Eredmény: 10 */
Egy opcionálisan megadható paraméterrel azt is szabályozhatjuk, hogy hányadik karaktertôl kezdôdjön a keresés:
POS('\', 'c:\system\config.sys', 4) /* Eredmény: 10 */
Egy az egyben így mûködik a WORDPOS függvény is, csak ez éppen a szavak pozíciójával foglalkozik:
/* Keressük Shakespeare szövegében a 'be' szót a 3. szótól kezdve */
WORDPOS('be', 'To be or not to be', 3) /* Eredmény: 6 */
Karakterláncok kielemzése
A karakterláncok manipulálásának egyik leghatékonyabb eszköze a PARSE utasítás. A 7. leckében már volt szó a PARSE ARG és a PARSE PULL utasításokról. Most a PARSE VALUE és a PARSE VAR utasításokat ismerjük meg, amelyekkel egyetlen lépésben lehet elvégezni ugyanazt, amihez több SUBSTR utasításra lenne szükség. A PARSE VAR segítségével egy változó tartalmát értékeljük ki egy minta alapján és az eredmény a minta részét képezô változókban kerül eltárolásra:
PARSE [UPPER] VAR változó minta
A PARSE VALUE egy kifejezés eredményét értékeli ki:
PARSE [UPPER] VALUE kifejezés WITH minta
A PARSE VAR esetében a változó, a PARSE VALUE esetében pedig a kifejezést nevezzük a forrás-karakterláncnak. A PARSE utasítás a forrásláncot darabolja fel és rendeli hozzá a mintában megadott változókhoz. A darabolás legegyszerûbb esete, amikor a minta csak a változókat tartalmazza. Ekkor a PARSE a forrásláncot a szóközkarakterek mentén darabolja fel és rendeli hozzá a változókhoz. A mintában azonban szerepelhetnek általunk megadott karakterlánc-részletek is, amelyekkel a darabolást befolyásolhatjuk. Ebben az esetben a PARSE a megadott láncrészletek mentén darabolja a forrásláncot. A mintában pozíciószámokat is megadhatunk. Ekkor a pozíciók alapján fog történni a darabolás. Lássunk néhány példát:
file = 'C:\OS2\BACKUP.EXE' PARSE VAR file drive ':\' path '\' filename '.' extension
Ebben az esetben a file változó értékét értékeljük ki és daraboljuk fel a mintakarakterek (:\, \ és .) mentén. A végeredmény a drive, path filename és extension változókban található meg és a következô értékeket tartalmazza:
drive = 'C' path = 'OS2' filename = 'BACKUP' extension = 'EXE'
Vegyük észre, hogy a darabolást meghatározó mintakarakterek nem szerepelnek a végeredményben! A mintakarakterek és szóközök mentén történô szétválasztást kombinálni is lehet:
name = 'Gates, Bill IX' PARSE VAR name lastname ',' firstname number /* Eredmény: lastname = Gates */ /* firstname = Bill, number = IX */
Ha több változó szerepel a mintában, mint amennyi részre a forrásláncot daraboljuk, akkor a felesleges változók értéke üres karakterlánc lesz. Ha több darab keletkezik, mint ahány változó van, akkor az utolsó változó fogja tárolni a maradékot. Ha ezt nem akarjuk, vagy pedig ki akarunk hagyni egy részdarabot, akkor azt a mintában egy pont megadásával jelezhetjük:
name = 'Gates, Bill IX' PARSE VAR name lastname ',' firstname . /* Eredmény: lastname = Gates, firstname = Bill */
Most pedig lássunk egy példát a pozíciók alapján történô darabolásra:
PARSE VALUE 'BillGates' WITH szo1 5 szo2
Ebben az esetben az 5. pozíció elôtt álló rész a szo1-be, az az utáni rész pedig a szo2-be kerül, tehát szo1 = Bill és szo2 = Gates lesz a végeredmény. Egynél több pozíciószámot is megadhatunk a mintaváltozók között, s ezzel azt is meghatározhatjuk, hogy hol kezdôdjön a következô karakterlánc-részlet. Ez arra is lehetôséget ad, hogy visszaugorjunk a forrásláncban! Az alábbi példa pl. a Red Rose szöveget jeleníti meg, igaz, kissé fura módon:
PARSE VALUE 'Rosebud' WITH first 5 1 second 2 4 third 5 7 fourth SAY second || third || fourth first /* Eredmény: Red Rose */
A pozíciószámok relatívek is lehetnek; a + - jelekkel a jobbra illetve a balra pozícionálást jelöljük:
PARSE VALUE 'Rosebud' WITH first +4 -4 second +1 +2 third +1 +2 fourth SAY second || third || fourth first /* Eredmény: Red Rose */
A PARSE VAR és VALUE utasítások esetében megismert mintaszabályok a PARSE PULL és ARG utasítások esetében is ugyanígy mûködnek.
REXX GYÍK:
K1. Hogyan jeleníthetem meg egy karakter bináris ábrázolását?
V1. Ez két lépésben történhet. Elsô lépésben hexadecimálisra kell konvertálni a karaktert a C2X függvénnyel. Az eredményül kapott hexa értéket aztán binárissá alakíthatjuk az X2B függvénnyel.
Gyakorlatok:
1. Mi az eredmény?
a. 'moon' || 'light'
b. val = 'hope'; val'chest'
c. 'This' 'time' 'tomorrow'
d. "This time " || 'tomorrow'
2. Készítsen egy programot, amely a bevitt decimális kód alapján megjeleníti a kódhoz tartozó karaktert!
| Kádár Zsolt 1998. 03. 15. | [ Elôzô lecke | Következô lecke | Tartalom ] |