SEN1002 · 8. hafta · Strings, Characters and Regular Expressions

String, StringBuilder, Character ve düzenli ifadeler

String metotları ve değişmezlik, StringBuilder ile değiştirilebilir metin, Character sınıfı ve regex ile doğrulama, split, replaceAll. Kısa çıktı sorularıyla dolu bir konu.

StringimmutablesubstringindexOfcharAtcompareToStringBuilderappendinsertreverseCharacterregular expressionmatchessplitreplaceAllPatternMatcher

Metin işleme her programda var: kullanıcı adı doğrulamak, CSV satırı bölmek, kelime saymak. Sınavda bu konu kısa ama tuzaklı çıktı soruları olarak gelir: substring’in bitiş indeksi, String’in değişmezliği, char aritmetiği, split’in boş parçaları. Bir de “write a method” sorusu: palindrom, kelime sayma, büyük harfe çevirme.

Altın kurallar:

  1. String değişmezdir (immutable). Metotlar yeni String döndürür; atamazsan sonuç kaybolur.
  2. substring(a, b) b’yi almaz. Uzunluk b - a.
  3. char bir sayıdır. 'A' + 2 int verir (67); karakter istiyorsan cast et.
  4. Değişen metin için StringBuilder. Metotları aynı nesneyi değiştirir.
  5. Regex’te ters bölü Java String’inde iki kez yazılır: "\\d+".

String metotları

String s = "Object Oriented";
System.out.println(s.length());
System.out.println(s.charAt(7));
System.out.println(s.indexOf('e'));
System.out.println(s.lastIndexOf('e'));
System.out.println(s.indexOf("Or"));
System.out.println(s.indexOf('z'));
System.out.println(s.substring(7));
System.out.println(s.substring(0, 6));
System.out.println(s.substring(2, 4));
System.out.println(s.toUpperCase() + " " + s.toLowerCase());
System.out.println("[" + "  hi there ".trim() + "]");
System.out.println(s.replace('e', '3'));
System.out.println(s.startsWith("Obj") + " " + s.endsWith("ED") + " " + s.contains("ted"));
15
O
3
13
7
-1
Oriented
Object
je
OBJECT ORIENTED object oriented
[hi there]
Obj3ct Ori3nt3d
true false true
indeks:  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
karakter O b j e c t _ O r i e  n  t  e  d      (_ = boşluk)
substring(2, 4) → 2 ve 3 → "je"        substring(7) → 7'den sona → "Oriented"
MetotDönerNot
length()intDizide length alan, String’de metot
charAt(i)chari >= length() ise StringIndexOutOfBoundsException
indexOf(x) / lastIndexOf(x)intBulamazsa -1
substring(a, b)Stringa dahil, b hariç
equals, equalsIgnoreCasebooleanİçerik karşılaştırma
compareTointSözlük sırası, ilk farklı karakterin kod farkı
toUpperCase, toLowerCase, trimStringYeni String
replace(a, b)StringDüz metin değiştirme, hepsini
split(regex)String[]Parçalara böler
toCharArray()char[]Karakter dizisi
String.valueOf(x)StringSayıyı metne çevirir

TUZAK · sınırlar. "java".substring(2, 5) ve "java".charAt(4) çalışırken StringIndexOutOfBoundsException fırlatır. Ama "java".substring(4) hata vermez, boş String döner (isEmpty() true).

Değişmezlik (immutability)

String nesnesi bir kez yaratılınca içeriği değişmez. toUpperCase, concat, replace gibi metotlar yeni bir String üretir.

String t = "java";
t.toUpperCase();          // sonuç atanmadı, kayboldu
t.concat("!");            // aynı
System.out.println(t);
t = t.toUpperCase();      // t artık yeni nesneyi gösteriyor
System.out.println(t);
java
JAVA

Aynı sebeple String u = "A"; String v = u; v += "B"; sonrasında u hâlâ "A": += yeni nesne yaratıp v’ye atar. StringBuilder’da ise iki referans aynı nesneyi değiştirir (aşağıda).

Karşılaştırma

System.out.println("Java".equals("java") + " " + "Java".equalsIgnoreCase("java"));
System.out.println("Apple".compareTo("apple"));
System.out.println("cat".compareTo("car"));
System.out.println("ab".compareTo("abcd"));
false true
-32
2
-2

Character sınıfı ve char aritmetiği

char aslında 16 bitlik bir sayıdır (Unicode kodu). Aritmetik işleme girince int’e yükselir. Ezberle: '0' = 48, 'A' = 65, 'a' = 97; büyük ve küçük harf arası 32.

System.out.println('A' + 2);           // int
System.out.println((char) ('A' + 2));  // char
System.out.println("A" + 2);           // String birleştirme
char c = 'x';
c++;                                   // ++ char olarak kalır
System.out.println(c);
System.out.println('7' - '0');         // rakamın değeri
67
C
A2
y
7

Character sınıfının static metotları:

MetotÖrnekSonuç
isLetter(c)isLetter('B')true
isDigit(c)isDigit('7')true
isLetterOrDigit(c)isLetterOrDigit('_')false
isUpperCase(c) / isLowerCase(c)isUpperCase('b')false
isWhitespace(c)isWhitespace(' ')true
toUpperCase(c) / toLowerCase(c)toUpperCase('q')'Q'
getNumericValue(c)getNumericValue('8')8
String mix = "a1B2 c3!";
int letters = 0, digits = 0, upper = 0, spaces = 0;
for (int i = 0; i < mix.length(); i++) {
    char ch = mix.charAt(i);
    if (Character.isLetter(ch)) letters++;
    if (Character.isDigit(ch)) digits++;
    if (Character.isUpperCase(ch)) upper++;
    if (Character.isWhitespace(ch)) spaces++;
}
System.out.println(letters + " " + digits + " " + upper + " " + spaces);
3 3 1 1

StringBuilder

Metni parça parça kuruyorsan ya da sık değiştiriyorsan StringBuilder kullan. İçeriği değiştirilebilir (mutable); metotları aynı nesneyi değiştirip onu geri döndürür, bu yüzden zincirleme yazılır.

StringBuilder sb = new StringBuilder("code");
sb.append(42).append('!');
System.out.println(sb);
sb.insert(0, "my ");
System.out.println(sb);
sb.reverse();
System.out.println(sb);
sb.reverse().deleteCharAt(sb.length() - 1).setCharAt(0, 'M');
System.out.println(sb + " len=" + sb.length());

StringBuilder sb2 = new StringBuilder("abc");
sb2.replace(1, 2, "XYZ");     // 1 dahil, 2 hariç
System.out.println(sb2);
sb2.delete(0, 2);
System.out.println(sb2);
code42!
my code42!
!24edoc ym
My code42 len=9
aXYZc
YZc
StringStringBuilder
DeğişmezDeğişebilir
s = s + x her seferinde yeni nesnesb.append(x) aynı nesne
equals içerik karşılaştırırequals override edilmemiş: adres
reverse yokreverse() var
Literal ile yaratılır: "abc"new StringBuilder("abc")
StringBuilder x = new StringBuilder("hi"), y = new StringBuilder("hi");
System.out.println(x.equals(y));
System.out.println(x.toString().equals(y.toString()));

StringBuilder p = new StringBuilder("A");
StringBuilder q = p;
q.append("B");            // aynı nesne
System.out.println(p);
false
true
AB

TUZAK · başa ekleyen döngü. r = i + r; ve rb.insert(0, i); ikisi de her elemanı başa koyar. 0’dan 3’e döngüde ikisi de 3210 üretir. Sona ekleseydin 0123 olurdu.

Düzenli ifadeler (regular expressions)

Regex, bir metin kalıbını tarif eden küçük bir dildir. Java’da üç yerde kullanırsın: matches (doğrulama), split (bölme), replaceAll (değiştirme).

KalıpAnlamıÖrnek uyan
.herhangi bir karaktera, 7, !
\d / \Drakam / rakam olmayan5
\wharf, rakam ya da _x, _
\sboşluk karakteri (space, tab, newline)" "
[abc]a, b ya da cb
[a-z], [A-Z0-9]aralıkk, Q, 4
[^0-9]rakam olmayanx
X*X sıfır ya da daha çok"", XXX
X+X bir ya da daha çokX, XX
X?X olabilir de olmayabilir decolou?r → color, colour
X{n}, X{n,}, X{n,m}tam n, en az n, n ile m arası\d{9}

Java String’inde \ kaçış karakteri olduğu için regex’in her ters bölüsü iki kez yazılır: regex’te \d+, Java’da "\\d+". Nokta gibi özel bir karakteri düz anlamında aramak için de kaçırırsın: "\\.".

matches: doğrulama

matches metnin tamamının kalıba uyup uymadığını söyler.

System.out.println("202312345".matches("\\d{9}"));          // 9 haneli öğrenci no
System.out.println("20231234".matches("\\d{9}"));
System.out.println("abc123".matches("[a-z]+\\d+"));
System.out.println("abc123x".matches("[a-z]+\\d+"));
System.out.println("Ankara".matches("[A-Z][a-z]*"));        // büyük harfle başlayan kelime
System.out.println("ali@bau.edu.tr".matches("[\\w.]+@[\\w.]+\\.[a-z]{2,}"));
System.out.println("05321234567".matches("05\\d{9}"));      // cep telefonu
true
false
true
false
true
true
true

split ve replaceAll

System.out.println(Arrays.toString("a,b,,c,,".split(",")));
System.out.println("a,b,,c,,".split(",").length);
System.out.println(Arrays.toString(",x,y".split(",")));
System.out.println(Arrays.toString("  one   two three ".trim().split("\\s+")));
System.out.println(Arrays.toString("1.5.9".split("\\.")));
System.out.println("1.5.9".split(".").length);   // "." her karakter: hepsi ayırıcı
[a, b, , c]
4
[, x, y]
[one, two, three]
[1, 5, 9]
0
System.out.println("programming".replaceAll("[aeiou]", "*"));
System.out.println("a1b22c333".replaceAll("\\d+", "#"));
System.out.println("too    many   spaces".replaceAll(" +", " "));
System.out.println("2026-10-28".replaceAll("(\\d+)-(\\d+)-(\\d+)", "$3/$2/$1"));
System.out.println("x.y.z".replace(".", "-") + " " + "x.y.z".replaceAll(".", "-"));
pr*gr*mm*ng
a#b#c#
too many spaces
28/10/2026
x-y-z -----

Parantezler grup (group) oluşturur; değiştirme metninde grupları sırayla 1, 2, 3 numaralarıyla geri çağırabilirsin (yukarıdaki tarih örneği).

Pattern ve Matcher

Metnin içinde kalıba uyan bütün parçaları tek tek bulmak için:

Matcher m = Pattern.compile("\\d+").matcher("Room 12, floor 3, gate 104");
int sum = 0;
while (m.find()) {
    System.out.print(m.group() + " ");
    sum += Integer.parseInt(m.group());
}
System.out.println("sum=" + sum);
12 3 104 sum=119

matches bütün metni ister, find metnin içinde bir sonraki uyan parçayı arar.

Çözümlü yazma sorusu: palindrom

“A man, a plan, a canal: Panama” harf ve rakam dışındakiler atılıp küçük harfe çevrilince tersiyle aynı mı?

static boolean isPalindrome(String s) {
    StringBuilder clean = new StringBuilder();
    for (char c : s.toCharArray())
        if (Character.isLetterOrDigit(c)) clean.append(Character.toLowerCase(c));
    String fwd = clean.toString();               // reverse'ten ÖNCE kopyala
    return fwd.equals(clean.reverse().toString());
}
System.out.println(isPalindrome("A man, a plan, a canal: Panama"));
System.out.println(isPalindrome("Java"));
true
false

fwd’yi reverse’ten önce almak şart: reverse aynı nesneyi çevirir. clean.toString().equals(clean.reverse().toString()) da çalışır (soldaki önce değerlendirilir), ama ayrı değişken okunaklı.

Sık yapılan hatalar

Yanlış düşünceDoğrusu
s.toUpperCase(); s’yi değiştirirYeni String döner; s = s.toUpperCase();
substring(2, 4) 3 karakterb hariç: 2 karakter
s.lengthString’de metot: s.length()
'A' + 2 → C67; karakter için (char) ('A' + 2)
sb1.equals(sb2) içerik karşılaştırırStringBuilder’da adres; toString() ile karşılaştır
split(".") noktadan bölerRegex’te nokta her karakter; split("\\.")
split sondaki boş parçaları tutarAtar; baştakini tutar
matches("\\d+") metinde rakam var mı?Bütün metin rakam mı? İçinde aramak için Matcher.find
s.charAt(0) = 'b';Derlenmez; String değişmez
Döngüde s += x sorun değilHer adımda yeni nesne; StringBuilder kullan

Kendini test et

Sınavdaki gibi İngilizce sorular. Önce kâğıt kalemle çöz, sonra cevabı aç.

Soru 1kolay

What is printed?

String s = "Object Oriented";
System.out.println(s.indexOf('e') + " " + s.lastIndexOf('e'));
System.out.println(s.substring(2, 4) + s.substring(7, 8));
Cevabı göster
3 13 ve jeO

İndeksler 0'dan başlar: O0 b1 j2 e3 c4 t5 (boşluk)6 O7 r8 i9 e10 n11 t12 e13 d14. İlk 'e' 3'te, son 'e' 13'te. substring(2, 4) 2 ve 3'ü alır (bitiş hariç): "je". substring(7, 8) sadece 7: "O".

Soru 2orta

What is printed?

String t = "java";
t.toUpperCase();
t.concat("!");
System.out.println(t);
Cevabı göster
java

String değişmezdir (immutable). toUpperCase ve concat yeni bir String döndürür, t'nin gösterdiği nesneyi değiştirmez. Dönen değer bir yere atanmadığı için kaybolur. Doğrusu t = t.toUpperCase();.

Soru 3orta

What is printed?

System.out.println('A' + 2);
System.out.println((char) ('A' + 2));
System.out.println("A" + 2);
System.out.println('7' - '0');
Cevabı göster
67, C, A2, 7

char sayısal bir tiptir: 'A' + 2 int toplamıdır, 65 + 2 = 67. Sonucu char'a cast edersen 67 numaralı karakter: C. "A" String olduğu için + birleştirir: A2. Rakam karakterinden '0' çıkarmak rakamın değerini verir: 55 − 48 = 7.

Soru 4orta

What is printed?

StringBuilder sb = new StringBuilder("code");
sb.append(42).append('!');
sb.insert(0, "my ");
System.out.println(sb);
sb.reverse();
System.out.println(sb);
Cevabı göster
my code42! ve !24edoc ym

StringBuilder değiştirilebilir; metotlar aynı nesneyi değiştirir ve onu döndürür (zincirleme yazılabilir). "code" → "code42" → "code42!" → başa "my " ekle: "my code42!". reverse karakterleri ters çevirir: "!24edoc ym".

Soru 5zor

What is printed?

StringBuilder x = new StringBuilder("hi"), y = new StringBuilder("hi");
System.out.println(x.equals(y));
System.out.println(x.toString().equals(y.toString()));
Cevabı göster
false ve true

StringBuilder equals'ı override etmez; Object'in equals'ı adres karşılaştırır, iki ayrı nesne: false. İçeriği karşılaştırmak için önce String'e çevir: true. (Java 11'den beri x.compareTo(y) == 0 da çalışır.)

Soru 6zor

What is printed?

System.out.println(Arrays.toString("a,b,,c,,".split(",")));
System.out.println(Arrays.toString(",x,y".split(",")));
Cevabı göster
[a, b, , c] ve [, x, y]

İki virgül arası boş String üretir: a, b, "", c. Sondaki boş parçalar split tarafından atılır, bu yüzden dizi 4 elemanlı. Baştaki boş parça atılmaz: ilk eleman "".

Soru 7orta

What is printed?

System.out.println("202312345".matches("\\d{9}"));
System.out.println("20231234".matches("\\d{9}"));
System.out.println("abc123x".matches("[a-z]+\\d+"));
Cevabı göster
true, false, false

matches bütün String'in kalıba uymasını ister. \\d{9} tam 9 rakam: ilki 9 haneli, ikincisi 8 haneli. [a-z]+\\d+ harfler sonra rakamlar ile biter; sondaki x uymuyor. Java String'inde regex'in \d'si "\\d" diye iki ters bölüyle yazılır.

Soru 8zor

What is printed?

System.out.println("programming".replaceAll("[aeiou]", "*"));
System.out.println("a1b22c333".replaceAll("\\d+", "#"));
System.out.println("x.y.z".replace(".", "-") + " " + "x.y.z".replaceAll(".", "-"));
Cevabı göster
pr*gr*mm*ng, a#b#c#, x-y-z -----

[aeiou] herhangi bir sesli harf: o, a, i yıldız olur. \\d+ bir ya da daha çok ardışık rakam, her grup tek # olur. replace düz metin değiştirir, replaceAll ise regex alır: regex'te . her karakter demek, beş karakterin hepsi tire olur.

Soru 9kolay

What is printed?

String mix = "a1B2 c3!";
int letters = 0, digits = 0, upper = 0;
for (int i = 0; i < mix.length(); i++) {
    char ch = mix.charAt(i);
    if (Character.isLetter(ch)) letters++;
    if (Character.isDigit(ch)) digits++;
    if (Character.isUpperCase(ch)) upper++;
}
System.out.println(letters + " " + digits + " " + upper);
Cevabı göster
3 3 1

Harfler: a, B, c (3). Rakamlar: 1, 2, 3 (3). Büyük harf: B (1). Boşluk ve ! hiçbir sayaca girmez.

Soru 10zor

What is printed?

System.out.println("Apple".compareTo("apple"));
System.out.println("cat".compareTo("car"));
System.out.println("ab".compareTo("abcd"));
Cevabı göster
-32, 2, -2

İlk farklı karakterin kod farkı döner. 'A' (65) − 'a' (97) = −32: büyük harfler küçüklerden önce gelir. "cat"/"car": ilk fark t (116) − r (114) = 2. "ab" "abcd"'nin başıyla aynı; fark yoksa uzunluk farkı döner: 2 − 4 = −2.

Soru 11orta

Find the compile error(s).

String s = "cat";
s.charAt(0) = 'b';
StringBuilder sb = "hello";
char c = s.substring(0, 1);
Cevabı göster
Üç hata: charAt'e atama, String → StringBuilder, String → char

charAt bir değer döner, değişken değil: javac unexpected type; required: variable, found: value. String'in harfi değiştirilemez; s = "b" + s.substring(1); ya da StringBuilder'ın setCharAt'i kullanılır. StringBuilder'a literal atanamaz: new StringBuilder("hello"). substring her zaman String döner, char için s.charAt(0).

Soru 12zor

Write a method capitalizeWords(String text) that returns the words of text separated by single spaces, each with its first letter upper case and the rest lower case. capitalizeWords(" hello wORLD from java ") returns Hello World From Java.

Cevabı göster
trim + split("\\s+") + StringBuilder + Character.toUpperCase

Önce baştaki ve sondaki boşlukları at, sonra bir ya da daha çok boşluktan böl. Döngüde String birleştirmek yerine StringBuilder kullan:

public static String capitalizeWords(String text) {
    String[] words = text.trim().split("\\s+");
    StringBuilder sb = new StringBuilder();
    for (String w : words) {
        if (sb.length() > 0) sb.append(' ');
        sb.append(Character.toUpperCase(w.charAt(0)));
        sb.append(w.substring(1).toLowerCase());
    }
    return sb.toString();
}
trim yapılmasaydı split başta boş bir String üretirdi ve w.charAt(0) StringIndexOutOfBoundsException fırlatırdı.

Doğrulama: Tüm kod örnekleri ve cevaplar JDK 26 ile çalıştırıldı (java verify/SEN1002/W08.java, W08b.java); derleme hataları javac ile denendi (verify/SEN1002/err/E08a-c.java).

Deftere not kartı

String DEĞİŞMEZ: s.toUpperCase() tek başına bir şey yapmaz → s = s.toUpperCase(); İndeks 0'dan. length() metot (dizide length alan). charAt(i), son = length()-1. substring(a, b): a dahil, b HARİÇ, uzunluk b-a. substring(a): sona kadar. indexOf bulamazsa -1. lastIndexOf sondan arar. equals içerik, == adres. equalsIgnoreCase. compareTo: ilk farklı karakterin kod farkı. char sayıdır: 'A'+2=67, (char)('A'+2)='C', '7'-'0'=7, 'A'=65 'a'=97 '0'=48. Character: isLetter isDigit isLetterOrDigit isUpperCase isWhitespace toUpperCase. StringBuilder: append insert(i,x) reverse deleteCharAt delete(a,b) replace(a,b,s) setCharAt. StringBuilder metotları AYNI nesneyi değiştirir. equals override YOK → toString().equals. split(","): sondaki boşlar atılır, baştaki kalır. split("\\s+"), split("\\.") (nokta kaçır). matches BÜTÜN metni kontrol eder. \\d rakam \\w harf/rakam/_ \\s boşluk . her şey [abc] biri [a-z] aralık [^0-9] değil * 0+ + 1+ ? 0/1 {n} tam n {n,m} replace düz metin, replaceAll regex: "x.y".replaceAll(".", "-") → "---"