2019. május 29., szerda

karakterláncok ábrázolása

megvalósítás:
(1) a karakterláncok vagy stringek karaktereit mindkét osztály egy private char value[]; karaktertömbben tárolja;
(2) a karakterek számát az osztályok egy private int count; mezõben tartják nyilván, amely megfelel a karakterlánc hosszának, és nem feltétlenül azonos a tömb hosszával.

String osztály (ebben az osztályban a karakterláncok karaktereit tároló tömb mérete és tartalma nem változtatható, vagyis a String osztály konstans stringek tárolására alkalmas; értékadáskor rendszerint egy új karaktertömb jön létre új tartalommal, a nem használt memóriaterületet pedig a Java un. szemétgyûjtõ algoritmusa felszabadítja)
konstans stringek létrehozása
String s=new String(); (üres string létrehozása, amely megfelel az s=""; értékadásnak; egy 0 elemszámmal rendelkezõ 0 hosszúságú karaktertömb létrehozását jelenti)
String s=new String("alma"); (megadott tartalommal rendelkezõ string létrehozása, amely megfelel az s="alma"; értékadásnak; a példa egy 4 elemszámmal rendelkezõ, 4 karakter hosszú karaktertömb létrehozását jelenti)
más típusok konstans stringgé konvertálása (részletesebben lásd a konverziós függvények alkalmazása címszónál)
elemi típusokra pl. String.valueOf(4) módon (a függvény értéke "4" lesz)
osztálytípusokra pl. obj.toString(); módon (ahol obj egy tetszõleges osztálytípus egy példánya)
konstans stringek konvertálása más típusokká (részletesebben lásd a konverziós függvények alkalmazása címszónál)
elemi típusokra a megfelelõ csomagoló osztály konverziós függvényével, pl. Integer.parseInt("3") módon (a függvény értéke 3 lesz)
elemi típusok csomagoló osztályaira az adott csomagoló osztály konverziós függvényével, pl. Integer.valueOf("3") módon
egyes osztálytípusokra az adott osztály megfelelõ konstruktorfüggvényével, pl. Float f=new Float("3.14"); vagy StringBuffer s=new StringBuffer("hello"); módon
StringBuffer osztály (ebben az osztályban a karakterláncok karaktereit tároló tömb mérete, a tömb un. kapacitása valamivel mindig nagyobb, mint a tárolandó karakterek tényleges száma, és a tömb tartalma is változtatható, így a StringBuffer osztály változó tartalmú stringek tárolására alkalmas; egy értékadáskor csak akkor jön létre egy új karaktertömb az új tartalommal, ha a string bõvülésére fenntartott szabad tömbkapacitás nem elegendõ az új karakterek tárolására)
változó stringek létrehozása
StringBuffer s=new StringBuffer(); (üres változó string létrehozása; egy 0 elemszámmal rendelkezõ 16 karakter hosszúságú karaktertömb létrehozását jelenti)
StringBuffer s=new StringBuffer(255); (üres változó string létrehozása; egy 0 elemszámmal rendelkezõ 255 karakter hosszúságú karaktertömb létrehozását jelenti)
StringBuffer s=new StringBuffer("alma"); (megadott tartalommal rendelkezõ változó string létrehozása; a példa egy 4 elemszámmal rendelkezõ, 4+16=20 karakter hosszú karaktertömb létrehozását jelenti)
konstans stringek változó stringgé konvertálása
kezdõértékadáskor a konstruktorfüggvénnyel, pl. StringBuffer s=new StringBuffer("alma"); módon
hozzáfûzéskor az append() metódussal, pl. s.append("fa"); módon (ha s.toString() értéke "alma" volt, a hozzáfûzés után "almafa" lesz)
megjegyzés: az append() metódus aktuális paramétereként nemcsak konstans string, hanem bármilyen típusú (elemi) érték megadható
változó stringek konstans stringgé konvertálása
a toString() metódussal, pl. s.toString() módon
a String osztály megfelelõ konstruktorfüggvényének hívásával, pl. StringBuffer sb=new StringBuffer("Hello"); esetén a String s=new String(sb); utasítás után az s változó értéke "Hello" lesz
megjegyzés: a Java a String típusú értékekre alkalmazható + konkatenációs mûveletet a StringBuffer osztály segítségével valósítja meg; pl. az s ="alma"+"fa"; értékadás megfelel az
s=new StringBuffer().append("alma").append("fa").toString(); értékadásnak

Tipp: ha egy program a következõ fázisokat tartalmazza: (1) beolvasunk egy karakterláncot, majd (2) változtatjuk a tartalmát, és (3) miután megkaptuk a karakterlánc "végleges" tartalmát, kiiratjuk (vagy olyan mûveleteket végzünk rajta, amelyek csak konstans stringekre alkalmazhatóak, pl. konvertáljuk valamilyen elemi típusra), a következõképpen célszerû eljárnunk:
a beolvasást konstans stringekre végezzük
alakítsuk át a konstans stringeket változó stringekké, és végezzük el a megfelelõ módosító mûveleteket (a StringBuffer osztály erre jóval több és hatékonyabb lehetõséget kínál!)
alakítsuk vissza a változó stringeket konstans stringekké.


karakterláncok összefûzése ("konkatenációja"); például
'Buda'+'pest' (TP; értéke 'Budapest' lesz)
"Buda"+"pest" (J; értéke "Budapest" lesz)
s.append("pest"); (J; ellentétben az eddigi legtöbb metódussal, append() metódus eljárásként (is) használható; ha a StringBuffer típusú s nevû változó értéke "Buda", akkor az eljárás végrehajtása után s értéke megváltozik, és "Budapest" lesz)
megjegyzés: az append() eljárás aktuális paramétereként nemcsak karakterlánc, hanem gyakorlatilag bármilyen típusú (elemi) érték vagy változó megadható

karakterlánc hosszának lekérdezése; például
Length(s) (TP; ha a string típusú s nevû változó értéke 'abc', akkor értéke 3)
Ord(s[0]) (TP; a string típusú s nevû változó hosszát a változó nulladik karaktere tartalmazza karakter típusú változóként, azaz a nulladik karakter kódja adja a string hosszát, lásd egyszerû adattípusok)
s.length() (J; ha a String vagy StringBuffer típusú s nevû változó értéke "abc", akkor értéke 3)

karakterláncok összehasonlítása; például
s < t (TP; ha pl. s = 'Buda' és t = 'Budapest' vagy t = 'Firenze', akkor értéke True)
s = 'Budapest' (TP; ha s = 'Budapest', akkor értéke True, egyébként False)
s.compareTo("Buda") (J; egyfajta "lexikografikus különséget" számít ki a String típusú s nevû változó aktuális értéke és a zárójelekben megadott karakterlánc között; ha s értéke "nagyobb", mint a paraméterben megadott karakterlánc, a különbség pozitív, ha megegyeznek, akkor 0, egyébként a különbség negatív)
az s.compareTo() függvény által visszaadott értékek
példa: min() és max() függvények definiálása String típusú paraméterekkel
s.equals("Debrecen") (J; ha a String típusú s nevû változó értéke "Debrecen", akkor értéke true, egyébként false; megjegyzés: az equals() függvény használható ugyan StringBuffer típusú változókra is, de ilyenkor csak formális egyezéskor ad vissza true értéket (tehát pl. s.equals(s) esetén), így sok gyakorlati haszna nincs)
s.equalsIgnoreCase("Debrecen") (J; ha a String típusú s nevû változó értéke kis- vagy nagybetûkkel írva "Debrecen", pl. "DEBRECEN", akkor értéke true, egyébként false)
s.startsWith("Buda") (J; ha a String típusú s nevû változó értéke "Buda"-val kezdõdik, pl. "Budapest", akkor értéke true, egyébként false)
s.endsWith("pest") (J; ha a String típusú s nevû változó értéke "pest"-re végzõdik, pl. "Budapest", akkor értéke true, egyébként false)

az s.compareTo("Buda") függvény által visszaadott értékek (a String típusú, s nevû változó különbözõ értékei mellett)
"@Hello" esetén -2, azaz negatív (64-66)
"Arad" esetén -1, azaz negatív (65-66)
"Buda" esetén 0
"Bt" esetén -1, azaz negatív (116-117)
"Buta" esetén 16, azaz negatív (116-100)
...
"Budai" esetén 1, azaz pozitív ("Buda"+1 karakter)
"Budapest" esetén 4, azaz pozitív ("Buda"+4 karakter)
"Budapesti" esetén 5, azaz pozitív ("Buda"+5 karakter)
...
"Cegled" esetén 1, azaz pozitív (67-66)
"Debrecen" esetén 2, azaz pozitív (68-66)
...
"Zahony" esetén 24, azaz pozitív (90-66), stb.)

példa: min() és max() függvények definiálása String típusú paraméterekkel
public class Parameterek {
    public static String min(String s,String t) {
        return (s.compareTo(t)<0 ? s : t);
        }
    public static String max(String s,String t) {
        return (s.compareTo(t)>0 ? s : t);
        }
public static void main(String[] args) {
    String s=new String();
    String t=new String();
    String u=new String();
    if (args.length>2) {
        s=min(args[0],args[1]);
        t=max(args[0],args[1]);
        u=args[2];
        System.out.println("A legkisebb parameter:  "+min(s,u));
        System.out.println("A kozepso parameter:    "+min(t,u));
        System.out.println("A legnagyobb parameter: "+max(t,u));
        }
    else System.out.println("Maskor adjon meg harom parancssori parametert!");
    }
}



karakterlánc egy adott karakterének lekérdezése; például
s[1] (TP; ha a string típusú s nevû változó értéke 'alma', akkor értéke 'a', mivel az elsõ karakter indexe 1)
s.charAt(3) (J; ha a String vagy StringBuffer típusú s nevû változó értéke "alma", akkor értéke 'a', mivel az elsõ karakter indexe 0)
példák
szöveg karaktereinek kiírása szóközökkel elválasztva (Turbo Pascal)
szöveg karaktereinek kiírása szóközökkel elválasztva (Java)

szöveg karaktereinek kiírása szóközökkel elválasztva (Turbo Pascal)
program Kiemel;
uses crt;
var s,t:string;
       i:integer;
BEGIN
write('Irjon valamit: '); readln(s);
t:='';
for i:=1 to length(s)-1 do
    t:=t+s[i]+' ';
t:=t+s[length(s)];
writeln(t);
END.



szöveg karaktereinek kiírása szóközökkel elválasztva (Java)
public class Kiemel {
public static String kiemel(String s) {
    StringBuffer sb=new StringBuffer();
    int i;
    for(i=0; i<s.length(); i++) {
        sb.append(s.charAt(i)).append('_');    /*az s String típusú változó minden karaktere után egy '_' karakter beszúrása; az utasítás két utasítással is megadható a következõképpen: sb.append(s.charAt(i)); sb.append('_'); */
        }
    sb.setLength(2*s.length()-1);    /*az utolsó '_' karakter levágása*/
    return sb.toString();
    }
public static void main(String[] args) {
    if (args.length>0) {
        System.out.println(kiemel(args[0]));
        }
    else System.out.println("Maskor adjon meg egy parancssori parametert!");
   /*a program futásának eredménye itt látható*/
    }
}

String, avagy minden, amit begépelhetsz (vagy nem)
A Java programozási nyelvben, mint megtudhattad, többféle változótípus létezik. Ezek egy része egyszerű (primitív) típus, de vannak összetett, komplexebb típusok, ezek minden esetben objektumok. Ezek egyike a karakterlánc, más nevén String.

Mint a neve is mutatja, ez egy osztály. Ez honnan látszik? Nagy kezdőbetűvel írtam a nevét. Nem csak én, már az alap program main programrészében is láthattad számtalanszor:

public static void main( String[] args )
A Stringek karakterekből állnak, melyek egymás után meghatározott sorrendben karakterláncot alkotnak. A Stringek nem csak kiíratható karaktereket tartalmazhatnak, olyanok is lehetnek benne, amelyek nem látszanak, ezekről majd később szót ejtek.

String deklaráció és értékadás
A String deklarációja a következőképpen néz ki:

String s;
A Stringnek meglehetősen sokféle módon adható kezdőérték, ebből lássunk egyet, igaz, ez a forma nem túl gyakori, létrehozok egy s nevű Stringet:

String s = new String();
Létrehoztam egy új, üres Stringet. Ezt mondjuk gyakran nem így használjuk. A new kulcsszóval egy új objektumot tudok létrehozni, ami az adott osztályból egy új példány. Az előző, tömbökről szóló anyag után ez már nagy meglepetést talán nem jelent, hiszen ott is ilyesmit írtunk, de a new-ról és szerepéről az Osztályok és objektumok témakörben olvashattál részletesebben. A String mérete is állandó, csakúgy, mint a tömböké.

A String a Java nyelvben megváltozhatatlan!

Ha egyszer beállítottad az értékét, akkor az attól kezdve mindig ugyanaz marad. Nézzünk akkor pár másik értékadási lehetőséget:

String s1 = "abcd";

char data[] = {'a', 'b', 'c'};
String str = new String(data);

String str2 = new String("xyz"); // ezt azért kerüljük..

String s2 = s1 + "efgh";
Az első esetben a String formai megjelenésének megfelelően adok meg egy értéket. A második esetben létrehozok egy karakterekből álló tömböt, amit odaadok a new-val létrehozandó String objektumnak, hogy abból állítsa elő magát. A harmadik esetben szinten new-val hozok létre egy új String objektumot, és odaadom neki egy literálként azt a karakterláncot, ami a tartalma legyen. Az utolsó példában egy Stringet egy másik bővítésével hozok létre, itt a + operátor mint az összefűzés műveleti jele szerepel.

A következő példa kicsit fura lehet:

String s = "abcd";
System.out.println( s ); // abcd

s += "efgh";
System.out.println( s ); // abcdefgh
Azt mondtam, hogy a String megváltoztathatatlan. Itt mégis hozzáfűztem valamit és az s-nek látszólag tényleg megváltozik a tartalma. És még működik is! Igen ám, de a háttérben nem ez történik:

Létrehozunk egy String objektumot, beállítjuk a kezdőértékét, és a címét hozzárendeljük az s változóhoz.
Amikor az s-hez hozzáfűzünk valamit, létrejön egy új String objektum a háttérben.
Ennek értéke az eredeti String objektum tartalma és az “efgh” literál összefűzéséből kialakított karakterlánc lesz.
Az s változóhoz az új objektum címe lesz hozzárendelve.
Az eredeti s-hez rendelt objektum meg változó nélkül marad, hiszen a változóhoz már egy új címet rendeltünk.
A változóhoz nem rendelt objektumot emiatt hamarosan kitakarítják a kupacból (de addig is foglalja a memóriát!)
Speciális String literálok
Amikor egy Stringnek értéket szeretnénk adni, léteznek bizonyos speciális karakterek. Ezek megadásához szükségünk lehet a backslash karakterre, ami a \ (visszaper jel). Ezen speciális karakterekre példa:

\n (sordobás)
\t (tabulátor)
\” (idézőjel karakter)
\\ (maga a backslash karakter)
Mi van akkor, ha a Stringben szeretnék idézőjeleket megjeleníteni?

Michael "Air" Jordan
Ebben az esetben a következő dolgot tehetjük:

String s = "Michael \"Air\" Jordan\n";
Itt a normál módon megadott idézőjelek a literál elejét és végét jelentik. Viszont a Stringben szeretnénk idézőjelet szerepeltetni, ezért a backslash (kivétel) karaktert tesszük elé, így tudni fogja a Java, hogy az Air szó előtti és utáni idézőjelek nem a String határait jelzik, hanem a String részei! A végén a \n pedig egy sordobást tesz a név végére.

És mi van akkor, ha magát a \ karaktert szerepeltetnénk a Stringben? Önmaga hogy lesz kivétel? Ezt szeretnénk megjeleníteni:

Gondolkodom, tehat vagyok. \Descartes\
Itt a String része lenne az a karakter, amivel a kivételeket szoktuk jelezni, de itt önmagát akarjuk megjeleníteni. Akkor hogy oldjuk meg, hogy a \ jelet a String részeként kezelje? Ekkor a következő a teendő:

String s = "Gondolkodom, tehat vagyok. \\Descartes\\";
Egyszerűen a \ jel elé kell egy másik, ami ezáltal önmagát teszi kivétellé. És mi van akkor, ha ez a String végén szerepel: \\” ? Ez sem gond, mert ezt nem egy kivételes idézőjelnek \” fogja tekinteni, hanem az első \ jel teszi kivétellé a második \ jelet, így az idézőjel normál módon a String literál végét jelenti.

String metódusok
Lássuk akkor, hogy mit kezdhetünk a Stringekkel. Amikor egy String típusú változót használunk, valójában egy objektummal dolgozunk. A változó csak az objektumra mutat. Az objektumoknak, mint a már említett Osztályok és objektumok témakörből megtudhattad változói és metódusai vannak. A Stringek változóiról nem kell tudnod, de a metódusairól, mellyel magát a Stringet kezelheted, annál többet! Lássuk akkor ezeket példákon keresztül, hogy mire is használhatók. A felsorolás nem lesz teljes, de a legfontosabbakat úgy gondolom, hogy tartalmazza.

Stringek egyenlőségének vizsgálata – equals()
A Stringek objektumok, és két objektum csak akkor egyenlő, ha az valójában ugyanaz az objektum.

Objektumok között az == operátorral végzett egyenlőség vizsgálat nem használható!

Itt egy példa, ami ennek látszólag ellentmond. Az s1 és s2 Stringek ugyanazt az értéket kapják meg kezdőértékként, és az == működik. Itt nagy valószínűséggel a háttérben a Java fordítóprogram csal egy kicsit, látva azt, hogy a két String egyforma, ezért valószínűleg ugyanazt az objektumot rendeli hozzá mindkettőhöz:

String s1 = "abcd";
String s2 = "abcd";

System.out.println(s1 == s2); // true (???)
Rögtön kibukik azonban a következő példánál az, hogy miért is emeltem ki azt, hogy == operátorral nem hasonlítunk össze objektumokat. Nézzük a következő példát:

String s1 = "abcd";
String s2 = new String("abcd");

System.out.println(s1 == s2); // false (!!)
Itt már valóban különbözik egymástól a két String. De akkor hogyan nézhetjük meg, hogy a két String egyenlő-e, ha az objektumok nem azok? Két Stringet akkor tekintünk egyenlőnek, ha ugyanaz a tartalmuk, vagyis ugyanazt a karakterláncot tartalmazzák. Ezt az összehasonlítást egy metódussal oldották meg.

String s1 = "abcd";
String s2 = new String("abcd");

System.out.println( s1.equals(s2) ); // true
Az equals() metódust egy String objektumban (formailag az objektum címét tároló változóban) kell meghívni, és oda kell adni neki azt a másik Stringet, aminek a tartalmát szeretnénk a sajátjával összehasonlítani. A feladat szempontjából teljesen mindegy, hogy melyiket hasonlítjuk melyikhez, az s1.equals(s2) helyett az s2.equals(s1) is használható.

Stringek összefűzése – concat()
Előfordulhat, hogy egy Stringet bővítenünk kell. Hozzá akarunk fűzni valamit. Emlékszel, azt mondtam, hogy a String megváltoztathatatlan. Amikor bővítjük, akkor egy újat hozunk létre, melynek a hivatkozását átállítjuk az eredeti változóban.

Mégis rendelkezésre áll egy metódus, concat() néven, mellyel Stringeket lehet összefűzni. Még egyszer hangsúlyozom, csak Stringeket.

String s = "Indul";
s = s.concat(" a");
s = s.concat(" gorog");
s = s.concat(" aludni");
System.out.println(s);
Amennyiben nem csak Stringeket szeretnénk összefűzni, minden további nélkül használhatjuk a + operátort. Ez a nem String változókat String változóra konvertálva végzi el az összefűzést. Ez az operátor, azonban lassabb, mint a concat() metódus, ezért ha több összefűzésről van szó és csak String típusúakat szeretnél összefűzni, akkor érdemesebb a concat()-ot használni.

A sebesség mérések alapján egyébként a concat() metódus úgynevezett StringBuilder-t használ a háttérben, vagyis a fordító trükköket vet be a sebesség és memóriakímélés érdekében, és ezeket a felhasználó tudta nélkül oldja meg.

Stringek hossza – length()
Bármely String méretét (hosszát) megkaphatjuk, ha meghívjuk a length() metódusát:

s.length()
String adott karaktere – charAt()
Egy adott String bármelyik karakterét megkaphatjuk a charAt(i) metódussal, ahova az i helyére írjuk be, hogy hányadik karaktert szeretnénk megkapni. A karakterek indexelése a tömbökhöz hasonlóan 0-val kezdődik. Fontos, hogy ez egy karakter típust ad vissza! Bármely String első karaktere az s.charAt(0), az utolsó pedig az s.charAt( s.length()-1 )

s.charAt(3) // a 4. karakter (3-as index!)
s.charAt(0) // első karakter (üres Stringre indexelési hiba!)
s.charAt( s.length()-1 ) // utolsó karakter
Stringek összehasonlítása rendezés miatt – compareTo()
A Stringek összehasonlításán már túl vagyunk, de van egy másik típus is, amely fontos, ez pedig a betűrend.

Két String összehasonlítása rendezési szempontból a compareTo() metódussal történik. Ezt hasonlóan az equals() metódushoz mindkét Stringre meg lehet hívni a másikat odaadva paraméterként, de itt már nem mindegy a sorrend! A compareTo() egy számot ad vissza eredményül. Ha a szám pozitív, akkor az a String amelyikre meghívtuk a metódust a paraméterben megadott String mögött található az abc rendnek megfelelően. Ha a szám negatív, akkor előtte. 0 esetén a két String tartalma egyforma. Ezt a metódust használhatjuk akkor, ha az a feladat, hogy Stringeket rendezzünk sorba.

Az összehasonlítás megkülönbözteti a kis és nagybetűket!

String s1 = "Geza";
String s2 = "Bela";
System.out.println( s1.compareTo(s2) ); // 5
/* Az eredmény pozitív, ez azt jelenti, hogy az s1 String (amire a
 * metódust meghívtuk) a paraméterben szereplő s2 Stringhez képest
 * hátrébb található rendezési szempontból. Maga az 5-ös érték azt
 * jelenti, hogy annál a pontnál, ahol a két String különbözik
 * a két összehasonlított karakter távolsága 5 (B-G)
 */

String s3 = "Geza";
String s4 = "bela";
System.out.println( s3.compareTo(s4) ); // -27
/* Az eredmény negatív, ez azt jelenti, hogy az s3 Stringhez képest
 * az s4 String hátrébb(!) található. Ez azért van, mert a kódtáblában
 * a nagybetűk megelőzik a kisbetűket, és a compareTo() figyelembe
 * veszi ezt. Ez kiküszöbölhető a következő metódussal:
 */

System.out.println( s3.compareToIgnoreCase(s4) ); // 5
/* a compareToIgnoreCase() metódus úgy hasonlítja össze a Stringeket,
 * hogy figyelmen kívül hagyja a kis és nagybetűk közötti különbségeket.
 */
Stringek kis-nagybetűs átalakítása – toLowerCase() és toUpperCase()
A Stringeket egyszerűen átalakíthatunk csupa nagybetűssé, vagy kisbetűssé. Erre szolgálnak az s.toUpperCase() és s.toLowerCase() metódusok.

String nev = "Miko Csaba";
System.out.println( nev.toUpperCase() ); // "MIKO CSABA"
System.out.println( nev.toLowerCase() ); // "miko csaba"
Keresés Stringben – indexOf(), lastIndexOf()
Egyszerűen kereshetünk a Stringekben. Kíváncsiak vagyunk, hogy egy karakter vagy szövegrészlet megtalálható-e benne, sőt arra is, hogy hol található. Erre szolgál az s.indexOf() metódus.

String s = "abrakadabra";
System.out.println( s.indexOf("rak") ); // 2
//  A 2. indexű (3. karakternél) található a rak szócska.

System.out.println( s.indexOf("br") ); // 1
/* Az 1. indexű (2. karakternél) található a br rész
 * Fontos, hogy az indexOf() mindig az első találat helyét adja meg!
 */

System.out.println( s.indexOf("Br") ); // -1
/* Egy nem létező indexet adott eredményül, vagyis a keresett
 * részlet nem található meg a Stringben.
 */

System.out.println( s.lastIndexOf("br") ); // 8
/* A 8. indexű (9. karakternél) található a br rész, de most a
 * keresést hátulról kezdte, és onnan adja vissza az első találatot!
 */
Az indexOf() és lastIndexOf() metódusok alaphelyzetben mindig a String elejéről/végéről kezdik a keresést, de meg lehet adni nekik, hogy adott karaktertől kezdjék: indexOf(mit, honnan) Ehhez kapcsolódó feladat lehet, hogy adjuk meg, hol található a második ‘r’ betű a szóban:

String s= "abrakadabra";
int elso = s.indexOf("r");

System.out.println( s.indexOf("r", elso+1 ) );
/* Először megkeressük az első 'r' betűt, majd amikor a másodikat
 * akarjuk megkeresni, akkor megadjuk, hogy az első utáni pozíciótól
 * induljunk. Ezt a két lépést akár össze is vonhatjuk:
 */
System.out.println( s.indexOf("r", s.indexOf("r")+1 ) );

System.out.println( s.lastIndexOf("br", s.lastIndexOf("br")-1 ) );
/* Ha ugyanezt hátulról végezzük, akkor figyelni kell arra, hogy
 * az első találat előtt kell folytatni, vagyis itt -1
 * kell az első találat helyéhez képest, mivel visszafelé keresünk
 */
String kezdete és vége – startsWith(), endsWith()
Egyszerűen megvizsgálhatjuk, hogy a String egy adott karaktersorozattal kezdődik vagy végződik. Erre szolgálnak a startsWith() és endsWith() metódusok. Ezek is kis-nagybetű érzékenyek, vagyis megkülönböztetik őket.

String s = "abrakadabra";
System.out.println( s.startsWith("ab") ); // true
System.out.println( s.endsWith("ab") ); // false
System.out.println( s.startsWith("Ab") ); // false(!)
Hogy vehetem figyelmen kívül a kis-nagybetű különbséget? Nincs startsWithIgnoreCase() metódus. A trükk annyi, hogy a String kisbetűs verzióját kell összehasonlítani a keresett kezdőrésszel.

String s = "Abrakadabra";
System.out.println( s.startsWith("ab") ); // false, nem meglepő
System.out.println( s.toLowerCase().startsWith("ab") ); // true!
String karaktereinek cseréje – replace(), replaceFirst()
Egy Stringben kicserélhetünk karaktereket. Erre szolgál a replace() metódus. Ezzel egy tetszőleges karakter minden előfordulását kicseréljük egy másikra. Az is előfordulhat, hogy csak az elsőt kell kicserélni, erre szolgál a replaceFirst().

String s = "abrakadabra";
System.out.println( s.replace("a","A") ); // AbrAkAdAbrA
System.out.println( s.replace("z","A") ); // abrakadabra
// Nem volt mit cserélni, maradt az eredeti.

System.out.println( s.replaceFirst("a","A") ); // Abrakadabra
// Kicserélte az elsőt, ahogy vártuk.

s = "Abrakadabra";
System.out.println( s.replaceFirst("a","A") ); // AbrAkadabra(??)
/* Láthatod, hogy az eredeti szó már nagybetűvel kezdődött. Ekkor az
 * első betű, amit cserélni tudott nyilván a második 'a' betű lesz,
 * de itt sem felejtetted el: kis-nagybetű érzékeny metódus!
 */
String részének kinyerése – substring()
Előfordulhat, hogy egy Stringből ki kell szednünk egy kisebb részletet. Erre szolgál a substring() metódus.

Amikor egy részt akarunk kinyerni egy Stringből, akkor meg kell mondanunk, hogy milyen karakter határokhoz (indexek) viszonyítva akarom ezt megkapni. Melyiktől kezdjük, és melyik előtt fejezzük be. Ha csak a kezdő pozíciót adjuk meg, akkor onnantól a String végéig az egészet megkapjuk. A substring() mindig String típusú eredményt ad vissza.

String s = "abrakadabra";
System.out.println( s.substring(0,5) ); // abrak
System.out.println( s.substring(2,5) ); // rak
System.out.println( s.substring(5,8) ); // ada
System.out.println( s.substring(6) );   // dabra
System.out.println( s.substring(s.length()) ); // mindig üres String
A String tartalmazza-e? – contains()
Megtudhatjuk, hogy a String tartalmaz-e egy keresett részt a contains() metódus segítségével. Ez minden esetben logikai eredményt ad. True ha benne van, false ha nincs. Az utolsó trükk meg már ismerős.

String s = "Abrakadabra";
System.out.println( s.contains("rak") ); // true
System.out.println( s.contains("Rak") ); // false
System.out.println( s.contains("abra") ); // true (a vegen van!)
System.out.println( s.contains("abrak") ); // false
System.out.println( s.toLowerCase().contains("abrak") ); // true(!)
Egyébként a contains() kiváltható akár egy indexOf() metódussal is, annyi a különbség, hogy az önmagában nem logikai eredményt ad:

String s = "Abrakadabra";
System.out.println( s.indexOf("rak") > -1 ); // true
System.out.println( s.indexOf("Rak") > -1 ); // false
String szétdarabolása – split()
Több feladat esetén előfordulhat, hogy egy Stringet azért kell darabokra szedni, mert valamilyen elválasztó karakterekkel határolva több adatot tartalmaznak. Erre a darabolásra szolgál a split() metódus. A split() minden esetben egy String tömböt ad eredményül, melynek elemei a megadott karakternél széttört String darabjai lesznek. Láthatod majd a példákból, hogy csak meg kell adni a split() metódusnak, milyen karakter mentén törje szét a Stringet. Az eredmény azonnal eltárolható egy String tömbben.

Az utolsó példa kicsit furcsa. Ne lepjen meg, hogy van benne egy üres String. Mivel a String elején volt egy töréspont, ezért a bevezető ‘a’ betűnél is eltöri a Stringet, és az előtte lévő semmit is eltárolja egy üres String darabként. Ha a töréspont a String végén található, akkor azt nem veszi figyelembe, és nincs nyoma az eredménytömbben sem. Alaphelyzetben a String végén elhelyezkedő töréspontokat a split() figyelmen kívül hagyja. Legalábbis ez a verziója.

String nevsor = "Geza Eva Pal";
String[] nevek = nevsor.split(" "); // { "Geza", "Eva", "Pal" }

String nevsor2 = "Geza,Eva,Pal";
String[] nevek2 = nevsor2.split(","); // { "Geza", "Eva", "Pal" }

String s = "abrakadabra";
String[] tomb = s.split("a"); // { "", "br", "k", "d", "br" }
Nem csak egy karakter adható meg töréspontként, akár karaktersorozatot is használhatsz. Itt is igaz az, hogy elől lévő töréspont miatt üres Stringgel kezdődik az eredménytömb, a végén lévővel itt sem foglalkozna, ha lenne 🙂

String s = "abrakadabra";
String[] tomb = s.split("ab"); // { "", "rakad", "ra" }
A split() metódus másik formája két paramétert vár. Itt egy limitet lehet megadni, hogy hány elemű eredménytömböt kapjak. A metódus a következő:

s.split(töréspont,n);
Itt többféle eredmény is lehet. Az n-nel jelölt szám értéke többféle lehet, ennek megfelelő a végeredmény is.

Ha n > 0,akkor n valójában azt jelenti, hogy hány darabra törje a Stringet. (vagyis n-1 esetben töri). Ha a kívánt darabok száma több, mint amennyi lehetséges, akkor a lehetséges maximumot kapjuk. Az “abrakadabra” szót nem törhetem az ‘a’ betűknél 100 részre. Mivel összesen 5 ‘a’ betű van benne, de ebből egy a végén, így maximum 6 darabra törhető. És ha az előző szónál 3 a limit? Akkor kétszer töri el a szót az elejétől kezdve, és 3 darabunk lesz. Az utolsó darabban viszont benne marad az összes olyan töréspont, ameddig a limit miatt nem jutott el.
Ha n == 0, az gyakorlatilag az alap split() metódus eredményét hozza. Vagyis, a String elején lévő töréspontokat figyeli, a végén lévőket nem, és annyi darabra töri, amennyire ennek megfelelően lehetséges.
Ha n < 0, akkor annyi darabra töri, amennyire csak tudja n értékétől függetlenül. És itt figyelembe veszi a String végén lévő töréspontokat is! Ilyenkor a darabok és a töréspontok ismeretében bármikor helyreállítható az eredeti String!
String s = "abrakadabra";
String[] tomb;
// n > 0
tomb = s.split("a", 1); // { "abrakadabra" } 1 darab
tomb = s.split("a", 3); // { "", "br", "kadabra" } 3 darab
tomb = s.split("a", 5); // { "", "br", "k", "d", "bra" } 5 darab
tomb = s.split("a", 8); // { "", "br", "k", "d", "br", "" } 6 darab,
                        // de nem 8, mert nincs annyi töréspont!

// n == 0
tomb = s.split("a", 0); // { "", "br", "k", "d", "br" } mint split("a")

// n < 0
tomb = s.split("a", -1); // { "", "br", "k", "d", "br", "" } hátsók is!
Speciális határolók

Vannak olyan speciális karakterek, melyeket nem lehet csak úgy odaadni a split-nek. Nem tudom, hogy a lista teljes-e, de ha valamelyik határoló esetén a split nem jó eredményt ad, érdemes majd az alább ismertetett módon megpróbálni.

String s = "abra.kad.abra";
String[] tomb;
tomb = s.split("."); // hibás!
tomb = s.split("\\."); // { "abra", "kad", "abra" }

s = "abra|kad|abra";
tomb = s.split("|"); // hibás!
tomb = s.split("\\|"); // { "abra", "kad", "abra" }

s = "abra\\kad\\abra"; // már a megadáskor ügyelni kell a \ jelre!
tomb = s.split("\"); // hibás!
tomb = s.split("\\"); // hibás!!!
tomb = s.split("\\\\"); // { "abra", "kad", "abra" }
Az utolsó példa esetleg kis magyarázatot igényel. Itt határoló karakternek szeretnénk megadni a \ jelet. A splitnek ha \\ módon adjuk meg a határolókat, azt sem dolgozza fel, mert ő ezt egy \ jelnek veszi. Itt a helyes megoldás a \\\\, amiből literálként \\ marad, és ő ezt dolgozza fel \ jelként. Ha egy fájlból beolvasott Stringben vannak ilyen jelek, akkor nem kell kivételként megadni, tehát a fájlban elég, ha így szerepel:

abra\kad\abra
Literálként viszont a \ jel önmagában nem adható meg, így Stringként megadva ebből ez lesz:

s = "abra\\kad\\abra";
Csak zárójelben jegyzem meg, hogy a split()-nek megadandó töréspont nem csak String lehet, hanem egy úgynevezett reguláris kifejezés is. Ez egy nagyon jól paraméterezhető illesztési minta, amivel teljesen átláthatóvá tudunk tenni összetett mintákat is.

Több határoló együttes használata

Előfordulhat olyan feladat, amelynél egy adott Stringet úgy kell több darabra törni, hogy nem csak egyféle határolót használunk. Nyilván meg lehetne oldani az eddig leírtak alapján is, de az meglehetősen körülményes lenne. Tegyük fel adott egy String, ami így néz ki:

String s = "123a4a56b78b9a0";


Ebben a sorban olyan Stringet látunk, ahol az egyes darabokat (a leendő sázmokat) betűk választják el egymástól. A helyzet azonban az, hogy nem csak egyfajta betű jelenik meg határolóként. Split-nél eddig azt tanultuk, hogy meg kell adni azt a határolót, aminél szét akarjuk törni a Stringet. A határoló állhat több karakterből is, de ez akkor is csak egyetlen darab lesz. Lássuk hogy lehet megoldani azt, hogy a fenti String-et a betűknél tördelve megkapjuk a benne lévő számokat:

String s = "123a4a56b78b9a0";
String[] darabok = s.split("a|b|c");

for( int i = 0; i < darabok.length; i++ )
{
  System.out.println(darabok[i]);
}
Ha lefuttatod a fenti kódot, akkor láthatod, hogy valóban az összes számot megkaptuk, és egyetlen betűt sem találunk a darabokban. Gyakorlatilag annyi a teendőnk, hogy egy | jellel elválasztottuk egymástól a határolókat egy felsorolásban. Ez a | jel valójában egy vagy műveletnek, de ez nem a logikai vagy, ne keverjük vele, csak egyetlen jelből áll. Ha tehát több határolónál kell egy Stringet darabolnunk, akkor használjuk bátran. Egy jó példa erre az emelt informatika érettéségi feladatok fehérje nevű feladata (2006 május).

Stringet karakterekre bontása – toCharArray()
Előfordulhat, hogy egy Stringet szét kell bontani karaktereire.

String s = "hokusz";
char[] tomb = s.toCharArray(); // { 'h', 'o', 'k', 'u', 's', 'z' }
String feladatok
Akkor kombináljuk az eddig tanultakat, nézzük meg a metódusok használatát komplexebb feladatok esetén.

Írjuk ki a nevünket vízszintesen kicsit széthúzva (tegyünk a nevünk betűi közé plusz szóközöket):

String nev = "Miko Csaba";
for (int i = 0; i < nev.length(); i++)
{
  System.out.print(nev.charAt(i)+" ");
}
Adjuk meg a nevünket, írjuk ki egy oszlopba:

String nev = "Miko Csaba";
for( int i = 0; i < nev.length(); i++ )
{
  System.out.println( nev.charAt(i) );
}
Számoljuk meg, hány a betű található a nevünkben:

String nev = "Miko Csaba";
int adb = 0;
for( int i = 0; i < nev.length(); i++ )
{
  if( nev.charAt(i) == 'a' )
  {
    adb++;
  }
}
System.out.println( "A nevben "+adb+" darab 'a' betu talalhato." );
Írjuk ki, hányszor szerepel a mondatban ‘a’ névelő. Kis és nagybetűs változat is számít!

String nev = "A Java tanulasa nem egyszeru feladat, "+
             "de a szorgalom meghozza gyumolcset.";
String[] tomb = nev.toLowerCase().split(" ");
int adb = 0;
for( int i = 0; i < tomb.length; i++ )
{
  if( tomb[i].equals("a") )
  {
    adb++;
  }
}
System.out.println( "A nevben "+adb+" darab 'a' nevelo talalhato." );

Karakterek és sztringek
8.1. A Character osztály
Egy Character típusú objektum egyetlen karakter értéket tartalmaz. A Character objektumot az egyszerű char változó helyett használjuk, amikor objektum szükséges, például: amikor átadunk egy karakter értéket egy metódusnak, ami megváltoztatja az értéket, vagy amikor egy karakter értéket helyezünk el egy adattárolóban, mint például egy ArrayList-ben, ami objektumokat tud csak tárolni, primitív értékeket nem.

Megjegyzés: a burkoló (csomagoló) osztályokról a következő fejezetben lesz szó.

A következő példaprogram (CharacterDemo) létrehoz néhány Character objektumot, és megjelenít róluk néhány információt. A Character osztályhoz tartozó kód az alábbiakban látható:

public class CharacterDemo {
    public static void main(String args[]) {
        Character a = new Character('a');
        Character a2 = new Character('a');
        Character b = new Character('b');

        int difference = a.compareTo(b);

        if (difference == 0) {
            System.out.println("a is equal to b.");
        } else if (difference < 0) {
            System.out.println("a is less than b.");
        } else if (difference > 0) {
            System.out.println("a is greater than b.");
        }
        System.out.println("a is "
            + ((a.equals(a2)) ? "equal" : "not equal")
            + " to a2.");
        System.out.println("The character " + a.toString()
            + " is " + (Character.isUpperCase(a.charValue()) ?
                 "upper" : "lower")
            + "case.");
    }
}
A program kimenete a következő lesz:

a is less than b.
a is equal to a2.
The character a is lowercase.
A fenti példában a Character.isUpperCase(a.charValue()) függvény adja az a nevű Character objektum kódját. Ez azért van, mert az isUppercase metódus char típusú paramétert vár. Ha a JDK 5.0-t vagy újabb fejlesztőkörnyezetet használunk, akkor ennek a metódusnak megadhatjuk a Character típusú objektumot is:

Character.isUpperCase(a)

A CharacterDemo program a Character osztály alábbi konstruktorait, illetve metódusait hívja meg:

Character(char): A Character osztály egyetlen konstruktora, amely létrehoz egy Character objektumot, melynek értékét a paraméterben adjuk meg, létrehozás után a Character objektum értéke nem változhat.
compareTo(Character): Összehasonlít két Character objektumban tárolt értéket, azt az objektumot, ami meghívta (a példában a), és azt, ami a paraméterben van (b). Visszaad egy egész számot, ami jelzi, hogy az objektum értéke kisebb, egyenlő, vagy nagyobb, mint a paraméterben megadott érték.
equals(Object): 2 Character objektumot hasonlít össze. True értékkel tér vissza, ha a két érték egyenlő.
toString(): Stringgé konvertálja az objektumot, a sztring 1 karakter hosszú lesz, és a Character objektum értékét tartalmazza.
charValue(): Megadja az objektum értékét egyszerű char értékként.
isUpperCase(char): Meghatározza, hogy az egyszerű char érték nagybetű-e.
A Character osztály néhány további fontosabb tagfüggvénye :

boolean isUpperCase(char)
boolean isLowerCase(char)
char toUpperCase(char)
char toLowerCase(char)
boolean isLetter(char)
boolean isDigit(char)
boolean isLetterOrDigit(char)
boolean isWhitespace(char)
boolean isSpaceChar(char)
boolean isJavaIdentifierStart(char)
boolean isJavaIdentifierPart(char)
8.2. String, StringBuffer és StringBuilder osztály
A Java platform a kezdetektől fogva biztosított két osztályt, melyekkel tárolhatunk, illetve manipulálhatunk sztringeket, ezek a String és a StringBuffer. A String osztályban olyan sztringeket tárolunk, melyek értéke nem fog változni. A StringBuffer osztályt akkor használjuk, ha a szövegen szeretnénk változtatni, ezt elsősorban dinamikus karakterlánc készítésekor (pl. fájlból olvasás) használjuk. A StringBuffer-ek használata biztonságos több szálas környezetben. A StringBuilder osztályt a JDK 5.0-tól vezették be, ami gyorsabb, mint a StringBuffer, de csak egy szálon használható biztonságosan.

A következő irányelvek alapján döntsünk, hogy melyik osztályt használjuk:

Ha a szöveg nem fog változni, használjuk a String-et.
Ha a szöveg változni fog, és csak egy szálon keresztül fogjuk elérni, használjuk a StringBuilder-t.
Ha a szöveg változni fog és több szálon keresztül fogjuk elérni StringBuffer-t használjuk.
A következő példaprogram neve StringsDemo, amely megfordítja egy sztring karaktereit. A program használja a String és StringBuilder osztályokat is. Ha a JDK 5.0-ás változatánál régebbit használ, a StringBuilder előfordulásait le kell cserélni StringBuffer-re, és a program működni fog.

public class StringsDemo {
    public static void main(String[] args) {
        String palindrome = "Dot saw I was Tod";
        int len = palindrome.length();
        StringBuilder dest = new StringBuilder(len);
        for (int i = (len - 1); i >= 0; i--) {
            dest.append(palindrome.charAt(i));
        }
        System.out.println(dest.toString());
    }
}
A program kimenete a következő lesz:

doT saw I was toD

Megjegyzés: Érdemes még a példán megfigyelni, hogy a StringBuilder (és StringBuffer) osztály példányosításakor az előre látható méretet meg lehet adni. Ez gyorsabb futást eredményez.

8.2.1. Sztring objektumok létrehozása
A sztringet gyakran egy sztring konstansból, egy karaktersorozatból készítjük. A StringsDemo program is ezt a módszert használja, hogy létrehozzon egy sztringet, amire a palindrome változóval hivatkozik:

String palindrome = "Dot saw I was Tod";

String-eket úgy is előállíthatunk, min bármilyen más Java objektumot: a new kulcsszó és a konstruktor segítségével. A String osztály több konstruktort szolgáltat, amelyekkel beállíthatjuk a String kezdőértékét, különböző forrásokat használva, mint például karakter tömböt, byte tömböt, StringBuffert, vagy StringBuildert.

A következő lista a String osztály konstruktorait tartalmazza:

String() Üres String-et hoz létre.
String(byte[]) String(byte[], int, int) String(byte[], int, int, String) String(byte[], String) Bájttömb tartalma alapján jön létre. Lehetőség van egy egész kezdőindex és hossz megadására részintervallum figyelembevételéhez, illetve meg lehet adni karakterkódolást is.
String(char[]) String(char[], int, int) Karaktertömb egésze vagy csak egy része alapján jön létre.
String(String) Másik String másolatát hozza létre.
String(StringBuffer) StringBuffer tartalma alapján jön létre.
String(StringBuilder) StringBuilder tartalma alapján jön létre.

Egy példa arra, amikor karaktertömbből készítünk sztringet:

char[] helloArray = { 'h', 'e', 'l', 'l', 'o' };
String helloString = new String(helloArray);
System.out.println(helloString);
A kódrészlet utolsó sora ezt írja ki:

hello

Ha StringBuffer-t, vagy StringBuilder-t hozunk létre, mindig használnunk kell a new operátort. Mivel a két osztálynak azonosak a konstruktorai, a következő lista csak a StringBuffer osztály konstruktorait tartalmazza:

StringBuffer()
StringBuffer(CharSequence)
StringBuffer(int)
StringBuffer(String)
A StringsDemo programban egy dest nevű StringBuildert hozunk létre, azt a konstruktort használva, amely a puffer kapacitását állítja be:

String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
StringBuilder dest = new StringBuilder(len);
A kód létrehoz egy StringBuildert, melynek kezdeti kapacitása megegyezik a palindrome nevű String hosszával. Ez csak a memóriafoglalást biztosítja a dest számára, mert ennek mérete pontosan elegendő lesz a bemásolandó karakterek számára. A StringBuffer vagy StringBuilder kapacitásának inicializálásával egy elfogadható méretre minimalizálhatjuk a memóriafoglalások számát, amivel sokkal hatékonyabbá tehetjük programunkat, mert a memóriafoglalás elég költséges művelet.

Megjegyzés: Ha egy StringBuilder vagy StringBuffer objektum méret növelése során a szabad kapacitása elfogy, akkor egy új, kétszer akkora memóriaterület kerül lefoglalásra, ahová a régi tartalom átmásolásra kerül. Ebből is látszik, hogy ha tudjuk, érdemes pontosan (vagy legalább becsülten) megadni a szükséges kapacitást.

8.2.2. A Stringek hossza
Azon metódusokat, amelyeket arra használunk, hogy információt szerezzünk egy objektumról, olvasó (vagy hozzáférő) metódusoknak nevezzük. Egy ilyen String-eknél, StringBuffer-eknék és StringBuilder-eknél használható metódus a length, amely visszaadja az objektumban tárolt karakterek számát. Miután az alábbi két sor végrehajtódik, a len változó értéke 17 lesz:

String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
A length mellett StringBuffer és StringBuilder osztályok esetén használhatjuk még a capacity metódust is, amely a lefoglalt terület méretét adja vissza, és nem a használt területet. Például a dest nevű StringBuilder kapacitása a StringDemo programban nem változik, míg a hossza minden karakter beolvasása után nő egyel. A következő ábra mutatja a dest kapacitását és hosszát, miután kilenc karakter hozzá lett fűzve.

StringBuilder kapacitás

A StringBuffer vagy StringBuilder hossza a benne tárolt karakterek száma, míg kapacitása az előre lefoglalt karakterhelyek száma. A String osztály esetén a capacity metódus nem használható, mert a String tartalma nem változhat meg.

8.2.3. Stringek karaktereinek olvasása
A megfelelő indexű karaktert megkapjuk a String-en, StringBuffer-en vagy a StringBuilder-en belül, ha meghívjuk a charAt függvényt. Az első karakter indexe 0, az utolsó karakteré pedig a length()-1.

Például az alábbi forráskódban a 9. indexű karaktert kapjuk meg a String-ben:

String anotherPalindrome = "Niagara. O roar again!";
char aChar = anotherPalindrome.charAt(9);
Az indexelés 0-val kezdődik, tehát a 9-es indexű karakter az ’0’, mint ahogy a következő ábra is mutatja:

charAt

Használjuk a charAt függvényt, hogy megkapjuk a megfelelő indexű karaktert.

Az ábra is mutatja, hogy hogyan lehet kiszámítani egy String-ben az utolsó karakter indexét. Ki kell vonni a length() függvény visszatérési értékéből 1-et.

Ha több, mint egy karaktert szeretnénk megkapni a String-ből, StringBuffer-ből vagy StringBuilder-ből, akkor a substring függvényt kell használni. A substring-nek két fajtája van, amit az alábbi táblázat is mutat:

String substring(int)
String substring(int, int)
Visszatérési érték egy új String, ami az eredeti sztring részének másolata. Az első paraméter az első karakter indexe (ahonnan kérjük a karaktereket), a második int paraméter pedig az utolsó karakter indexe (ameddig kérjük)-1. A substring hosszát megkapjuk, ha a második paraméter értékből kivonjuk az első paraméter értékét. Ha nem adjuk meg a második paramétert, akkor az eredeti String végéig történik a másolás.

Az alábbi forráskód a Niagara tükörmondatból ad vissza egy részletet, ami a 11. indextől a 15. indexig tart, ez pedig a „roar” kifejezés:

String anotherPalindrome = "Niagara. O roar again!";
String roar = anotherPalindrome.substring(11, 15);
substring

8.2.4. Karakter vagy String keresése Stringben
A String osztály két függvényt nyújt, amelyek pozícióval térnek vissza: indexOf és a lastIndexOf. A következő lista e két függvény alakjait mutatja be:

int indexOf(int), int lastIndexOf(int) Visszaadja az első (utolsó) előforduló karakter indexét.
int indexOf(int, int), int lastIndexOf(int, int) Visszaadja az első (utolsó) előfordulókarakter indexét, az indextől előre (visszafele) keresve.
int indexOf(String), int lastIndexOf(String) Visszaadja az első (utolsó) előforduló String indexét.
int indexOf(String, int), int lastIndexOf(String, int) Visszaadja a String első (utolsó) előfordulásának indexét, a megadott indextől előre (visszafele) keresve.

A StringBuffer és a StringBuilder osztályok nem támogatják az indexOf és a lastIndexOf függvényeket. Ha használni szeretnénk ezeket a metódusokat, először String-gé kell konvertálnunk az objektumot a toString függvény segítségével.

Megjegyzés: A metódusok az alábbi Filename osztályban nem minden hibát kezelnek, és feltételezik, hogy az paraméter tartalmazza a teljes könyvtár útvonalat, és a fájlnevet kiterjesztéssel.

public class Filename {
    private String fullPath;
    private char pathSeparator, extensionSeparator;
    public Filename(String str, char sep, char ext) {
        fullPath = str;
        pathSeparator = sep;
        extensionSeparator = ext;
    }
    public String extension() {
        int dot = fullPath.lastIndexOf(extensionSeparator);
        return fullPath.substring(dot + 1);
    }
    public String filename() {
        int dot = fullPath.lastIndexOf(extensionSeparator);
        int sep = fullPath.lastIndexOf(pathSeparator);
        return fullPath.substring(sep + 1, dot);
    }
    public String path() {
        int sep = fullPath.lastIndexOf(pathSeparator);
        return fullPath.substring(0, sep);
    }
}
A következő program létrehoz egy Filename objektumot, és meghívja a metódusait:

public class FilenameDemo {
    public static void main(String[] args) {
        final String FPATH = "/home/mem/index.html";
        Filename myHomePage = new Filename(FPATH,
                                           '/', '.');
        System.out.println("Extension = " +
             myHomePage.extension());
        System.out.println("Filename = " +
             myHomePage.filename());
        System.out.println("Path = " +
             myHomePage.path());
    }
}
A program kimenete:

Extension = html
Filename = index
Path = /home/mem
Ahogy a fenti példa is mutatja, az extension metódus a lastIndexOf függvényt használja, hogy megtalálja az utolsó pontot a fájlnévben. Ha a fájlnévben nincs pont, a lastIndexOf visszatérési értéke -1, és a substring metódus StringIndexOutOfBoundsException kivételt dob.

Ha a pont karakter (.) az utolsó karakter a String-ben, akkor ez egyenlő a String hosszával, ami egyel nagyobb, mint a legnagyobb index a String-ben (mivel az indexelés 0-val kezdődik).

8.2.5. Sztringek és rész-sztringek összehasonlítása
A String osztálynak van néhány függvénye a sztringek és a rész-sztringek összehasonlítására. Az alábbi lista ezeket a függvényeket mutatja be:

boolean endsWith(String), boolean startsWith(String), boolean startsWith(String, int) Visszatérési értéke igaz, ha a String a paraméterben megadott szóval kezdődik, vagy végződik. Az int paraméterben az eltolási értéket adhatjuk meg, hogy az eredeti String-ben hanyadik indextől kezdődjön a keresés.

int compareTo(String), int compareTo(Object), int compareToIgnoreCase(String) Két String-et hasonlít össze ABC szerint, és egy egész számmal tér vissza, jelezve, hogy ez a String nagyobb (eredmény>0), egyenlő (eredmény=0), illetve kisebb (eredmény<0), mint a paraméter. A compareToIgnoreCase nem tesz különbséget a kis-és nagybetűk között.

boolean equals(Object), boolean equalsIgnoreCase(String) Visszatérési értéke igaz, ha a String ugyanazt a karaktersorozatot tartalmazza, mint a paramétere. Az equalsIgnoreCase függvény nem tesz különbséget kis- és nagybetűk között; így ’a’ és ’A’ egyenlő.

8.2.6. Sztringek módosítása
A String osztály sokféle metódust tartalmaz a String-ek módosításához. Természetesen a String objektumokat nem tudja módosítani, ezek a metódusok egy másik String-et hoznak létre, ez tartalmazza a változtatásokat. Ezt követhetjük az alábbi listában.

String concat(String) A String végéhez láncolja a String paramétert. Ha az paraméter hossza 0, akkor az eredeti String objektumot adja vissza.
String replace(char, char) Felcseréli az összes első paraméterként megadott karaktert a második paraméterben megadottra. Ha nincs szükség cserére, akkor az eredeti String objektumot adja vissza.
String trim() Eltávolítja az elválasztó karaktereket a String elejéről és a végéről.
String toLowerCase() String toUpperCase() Konvertálja a String-et kis, vagy nagybetűsre. Ha nincs szükség konverzióra, az eredeti String-et adja vissza.
Íme egy rövid program (BostonAccentDemo), ami a replace metódussal egy String-et fordít Bostoni dialektusra:

public class BostonAccentDemo {
    private static void bostonAccent(String sentence) {
        char r = 'r';
        char h = 'h';
        String translatedSentence = sentence.replace(r, h);
        System.out.println(translatedSentence);
    }
    public static void main(String[] args) {
        String translateThis =
            "Park the car in Harvard yard.";
        bostonAccent(translateThis);
    }
}
A replace metódus kicseréli az összes r-t h-ra a mondatokban.

A program kimenete:

Pahk the cah in Hahvahd yahd.

8.2.7. A StringBuffer-ek módosítása
A StringBuffer-ek tartalma módosítható. A következő lista összefoglalja a StringBuffer-ek módosításához használható metódusokat. Azonos metódusokat tartalmaz a StringBuilder osztály is, de StringBuilder-eket is ad vissza, ezért ezeket külön nem soroljuk fel.

StringBuffer append(boolean)
StringBuffer append(char)
StringBuffer append(char[])
StringBuffer append(char[], int, int)
StringBuffer append(double)
StringBuffer append(float)
StringBuffer append(int)
StringBuffer append(long)
StringBuffer append(Object)
StringBuffer append(String)
Hozzáfűzi a megadott paramétert a StringBuffer-hez. Az adat String-gé konvertálódik, mielőtt a hozzáfűzés megtörténne.

StringBuffer delete(int, int)
StringBuffer deleteCharAt(int)
Törli a megadott karaktereket a StringBuffer-ből.

StringBuffer insert(int, boolean)
StringBuffer insert(int, char)
StringBuffer insert(int, char[])
StringBuffer insert(int, char[], int, int)
StringBuffer insert(int, double)
StringBuffer insert(int, float)
StringBuffer insert(int, int)
StringBuffer insert(int, long)
StringBuffer insert(int, Object)
StringBuffer insert(int, String)
A StringBuffer-hez ad egy új paramétert. Az első egész típusú paraméter jelzi az adat indexét, ahova a beillesztés történik. Az adat String-gé konvertálódik, mielőtt a beillesztés megtörténik.

StringBuffer replace(int, int, String)
void setCharAt(int, char)
Kicseréli a megadott karaktereket a StringBuffer-ben.

StringBuffer reverse()
Felcseréli a karakterek sorrendjét a StringBuffer-ben.

Az append metódusra már láttunk példát a StringsDemo programban, a fejezet elején. Az alábbi InsertDemo program bemutatja az insert metódus használatát. Beilleszt egy String-et a StringBuffer-be:

public class InsertDemo {
    public static void main(String[] args) {
        StringBuffer palindrome = new StringBuffer(
            "A man, a plan, a canal; Panama.");
        palindrome.insert(15, "a cat, ");
    System.out.println(palindrome);
    }
}
A program kimenete:

A man, a plan, a cat, a canal; Panama.

Az általunk megadott index utáni helyre kerül beillesztésre az adat. A StringBuffer elejére való beillesztéshez a 0 indexet kell használni. A végéhez való beillesztés esetén az index értéke megegyezik a StringBuffer jelenlegi hosszával, vagy használjuk a hozzáfűzést (append) is.

Ha a művelet miatt túlságosan megnő a StringBuffer mérete, akkor az több memóriát fog lefoglalni. Mivel a memória lefoglalás költséges, ezért lehetőleg úgy kell elkészíteni a kódot, hogy megfelelően be legyen állítva a StringBuffer mérete.

8.2.8. A String-ek és a fordító
A fordító felhasználja a String és a StringBuffer osztályokat a háttérben, hogy a String-literálokat és különböző összefűzéseket kezelje. A String-et idézőjelek között adhatjuk meg:

"Hello World!"

String-literálokat bárhol használhatunk String példányként. Példaként, a System.out.println paraméterének String-literált adunk meg:

System.out.println("Might I add that you look lovely today.");

Használhatunk String metódust közvetlenül a String-literálból hívva:

int len = "Goodbye Cruel World".length();

Használhatjuk a String-literált String inicializálásra:

String s = "Hola Mundo";

A következő példa egyenértékű az előzővel, de nem olyan hatékony. Két azonos String-et készít, használata kerülendő:

String s = new String("Hola Mundo"); //ne használjuk

Használható a + operátor a String-ek összefűzésére:

String cat = "cat";
System.out.println("con" + cat + "enation");
Az előző példa alapján a fordító a StringBuffer-eket használja az összefűzés végrehajtására:

String cat = "cat";
System.out.println(new StringBuffer().append("con").
append(cat).append("enation").toString());
Használható a + operátor az összefűzésre:

System.out.println("You're number " + 1);

A fordító konvertálja a nem String értéket (a példában int 1-et) String objektummá, mielőtt az összefűzést elvégzi.

8.3. Sztringek darabolása
A java.util.StringTokenizer osztály hasznos lehet, ha egy String-et adott elválasztó karakter(ek) mentén szét kell bontani. A következő egyszerű példa bemutatja a használat módját:

StringTokenizer st = new StringTokenizer("this is a test");
while (st.hasMoreTokens()) {
    System.out.println(st.nextToken());
}
A kód a következő eredményt írja ki:

this
is
a
test
A StringTokenizer objektum nyilván tartja, hogy a feldolgozás a String melyik pontján jár. A konstruktornak megadhatunk a szövegen kívül egy elválasztó-karaktereket tartalmazó String-et is, ekkor az alapértelmezett "\t\n\r\f" elválasztók helyett ezt fogja az objektum figyelembe venni.

8.4. Ellenőrző kérdések
Mi a karakter?
Hányféle jelet képes tárolni a Java char típusa?
Hogy hívják a Java által támogatott karaktertípust?
Mi a karaktersorozat (sztring?)
Mit jelent, hogy a String nem megváltoztatható?
Hogyan lehet egy String-nek kezdőértéket adni?
Mire való a String indexOf metódusa?
Mire való String substring metódusa?
Mi a különbség a StringBuilder, a StringBuffer és a String között?
Melyik kifejezés értéke lesz logikailag igaz?
"john" == "john"
"john".equals("john")
"john" = "john"
"john".equals(new Button("john"))
Melyik fordul le?
"john" + " was " + " here"
"john" + 3
3 + 5
5 + 5.5
Mit ír ki a következő kódrészlet?
String s = new String("Bicycle");
int iBegin=1;
char iEnd=3;
System.out.println(s.substring(iBegin, iEnd));
Bic
ic
icy
fordítási hiba miatt nem indul el
Ha a ”Java” tartalmú s String-ben keressük a ’v’ betű pozícióját (a 2-t), akkor melyik metódushívással kapjuk ezt meg?
mid(2,s);
s.charAt(2);
s.indexOf('v');
indexOf(s,'v');
A következő deklarációk esetén melyik művelet érvényes?
String s1 = new String("Hello")
String s2 = new String("there");
String s3 = new String();
s3=s1 + s2;
s3=s1 - s2;
s3=s1 & s2;
s3=s1 && s2

A megfelelő indexű karaktert megkapjuk a String-en, StringBuffer-en vagy a StringBuilder-en belül, ha meghívjuk a charAt függvényt. Az első karakter indexe 0, az utolsó karakteré pedig a length()-1.

Például az alábbi forráskódban a 9. indexű karaktert kapjuk meg a String-ben:

String anotherPalindrome = "Niagara. O roar again!";
char aChar = anotherPalindrome.charAt(9);
Az indexelés 0-val kezdődik, tehát a 9-es indexű karakter az ’0’, mint ahogy a következő ábra is mutatja:

charAt
charAt


Használjuk a charAt függvényt, hogy megkapjuk a megfelelő indexű karaktert.

Az ábra is mutatja, hogy hogyan lehet kiszámítani egy String-ben az utolsó karakter indexét. Ki kell vonni a length() függvény visszatérési értékéből 1-et.

Ha több, mint egy karaktert szeretnénk megkapni a String-ből, StringBuffer-ből vagy StringBuilder-ből, akkor a substring függvényt kell használni. A substring-nek két fajtája van, amit az alábbi táblázat is mutat:

String substring(int)
String substring(int, int)
Visszatérési érték egy új String, ami az eredeti sztring részének másolata. Az első paraméter az első karakter indexe (ahonnan kérjük a karaktereket), a második int paraméter pedig az utolsó karakter indexe (ameddig kérjük)-1. A substring hosszát megkapjuk, ha a második paraméter értékből kivonjuk az első paraméter értékét. Ha nem adjuk meg a második paramétert, akkor az eredeti String végéig történik a másolás.

Az alábbi forráskód a Niagara tükörmondatból ad vissza egy részletet, ami a 11. indextől a 15. indexig tart, ez pedig a „roar” kifejezés:

String anotherPalindrome = "Niagara. O roar again!";
String roar = anotherPalindrome.substring(11, 15);
substring
substring


Nincsenek megjegyzések:

Megjegyzés küldése