Το πρόγραμμα PalindromeCheck είναι μια κονσολάτη εφαρμογή σε C#, που ζητάει από τον χρήστη να πληκτρολογήσει ένα κείμενο και του απαντά αν είναι παλίνδρομο (palindrome) ή όχι.
Παλίδρομο είναι μια λέξη ή φράση που διαβάζεται ίδια προς τα εμπρός και προς τα πίσω — π.χ.
“ΑΝΝΑ”, “κακό”, ή στα Αγγλικά “madam”, “racecar”.
Το πρόγραμμα:
Διαβάζει είσοδο από τον χρήστη.
Αν ο χρήστης γράψει exit, το πρόγραμμα σταματά.
Διαφορετικά, καθαρίζει τη συμβολοσειρά (αφαιρεί κενά, σημεία στίξης, πεζοποιεί) και ελέγχει αν είναι παλίνδρομη.
Δημιουργούμε ένα console app:
Program.cs
namespace PalindromeCheck
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("PalindromeCheck - Εισάγετε κείμενο (γράψτε 'exit' για έξοδο):");
while (true)
{
Console.Write("> ");
string? input = Console.ReadLine();
if (input == null) break;
if (input.Trim().Equals("exit", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine("Έξοδος. Καλή συνέχεια!");
break;
}
bool isPal = PalindromeService.IsPalindrome(input);
Console.WriteLine(isPal ? "Είναι palindrome." : "Δεν είναι palindrome.");
}
}
}
}
PalindromeService.cs
🔹 1. Η γραμμή:
if (input.Trim().Equals("exit", StringComparison.OrdinalIgnoreCase))
Αναλυτικά τι κάνει:
- input → είναι το κείμενο που έγραψε ο χρήστης.
- Trim() → αφαιρεί κενά από την αρχή και το τέλος του κειμένου. Π.χ. " exit ".Trim() → "exit".
- .Equals("exit", StringComparison.OrdinalIgnoreCase) → συγκρίνει το καθαρισμένο κείμενο με τη λέξη "exit".
Η παράμετρος StringComparison.OrdinalIgnoreCase σημαίνει:
Κάνε τη σύγκριση χωρίς διάκριση πεζών/κεφαλαίων, χρησιμοποιώντας τη γρήγορη, binary (Ordinal) μέθοδο.
✅ Δηλαδή, αν ο χρήστης γράψει EXIT, Exit, ExIt ή exit, θα θεωρηθεί το ίδιο και θα γίνει έξοδος από το πρόγραμμα.
using System.Text;
namespace PalindromeCheck
{
static class PalindromeService
{
public static bool IsPalindrome(string s)
{
if (string.IsNullOrEmpty(s)) return true;
var cleaned = CleanString(s);
int i = 0, j = cleaned.Length - 1;
while (i < j)
{
if (cleaned[i] != cleaned[j]) return false;
i++; j--;
}
return true;
}
private static string CleanString(string input)
{
StringBuilder sb = new StringBuilder(input.Length);
foreach (char c in input)
{
if (char.IsLetterOrDigit(c))
sb.Append(char.ToLowerInvariant(c));
}
return sb.ToString();
}
}
}
🔹 2. Το κομμάτι:
var cleaned = CleanString(s);
int i = 0, j = cleaned.Length - 1;
while (i < j)
{
if (cleaned[i] != cleaned[j]) return false;
i++; j--;
}
return true;
Τι κάνει συνολικά:
Αυτό είναι ο πυρήνας του ελέγχου palindrome.
var cleaned = CleanString(s);
Καλεί μια βοηθητική μέθοδο (θα την εξηγήσουμε μετά) που καθαρίζει τη συμβολοσειρά — αφαιρεί σημεία στίξης και κενά, και τη μετατρέπει σε πεζά.
Π.χ.
"A man, a plan, a canal: Panama" → "amanaplanacanalpanama"
int i = 0, j = cleaned.Length - 1;
Δημιουργεί δύο δείκτες:
i ξεκινά από την αρχή της συμβολοσειράς,
j από το τέλος.
while (i < j)
Όσο ο δείκτης i είναι πριν από τον j, συνεχίζουμε να συγκρίνουμε.
if (cleaned[i] != cleaned[j]) return false;
Αν βρεθεί ένα μόνο ζευγάρι χαρακτήρων που δεν είναι ίδιο (π.χ. ‘a’ ≠ ‘b’), τότε δεν είναι palindrome — οπότε σταματά αμέσως και επιστρέφει false.
i++; j--;
Αν οι χαρακτήρες ταιριάζουν, προχωράμε προς το κέντρο — αυξάνουμε i, μειώνουμε j.
Όταν ο βρόχος τελειώσει (δηλαδή συγκρίθηκαν όλα τα ζεύγη χωρίς διαφορά),
→ return true; — σημαίνει ότι το κείμενο είναι palindrome.
🔹 3. Το κομμάτι:
private static string CleanString(string input)
{
StringBuilder sb = new StringBuilder(input.Length);
foreach (char c in input)
{
if (char.IsLetterOrDigit(c))
sb.Append(char.ToLowerInvariant(c));
}
return sb.ToString();
}
Αναλυτική εξήγηση:
Αυτή η μέθοδος καθαρίζει τη συμβολοσειρά πριν τον έλεγχο — είναι η “προεπεξεργασία”.
StringBuilder sb = new StringBuilder(input.Length);
Δημιουργεί ένα “δοχείο” για να χτίσουμε σταδιακά τη νέα συμβολοσειρά.
Είναι πιο αποδοτικό από την απλή σύνθεση string με +.
foreach (char c in input)
Περνάει κάθε χαρακτήρα του αρχικού κειμένου, έναν-έναν.
if (char.IsLetterOrDigit(c))
Ελέγχει αν ο χαρακτήρας είναι γράμμα ή αριθμός.
➜ Αγνοεί κενά, κόμματα, τελείες, θαυμαστικά κ.λπ.
sb.Append(char.ToLowerInvariant(c));
Αν είναι αποδεκτός χαρακτήρας, τον μετατρέπει σε πεζό (ToLowerInvariant) και τον προσθέτει στο StringBuilder.
Invariant σημαίνει ότι η μετατροπή δεν εξαρτάται από το σύστημα ή το locale.
Π.χ. σε τουρκικά ή ελληνικά locales μπορεί να διαφέρουν τα αποτελέσματα αν δεν το χρησιμοποιήσεις.
return sb.ToString();
Μετατρέπει το StringBuilder πίσω σε κανονικό string και το επιστρέφει.
Ο StringBuilder είναι μια από τις πιο χρήσιμες κλάσεις της C# όταν δουλεύεις με πολλά string, γιατί λύνει ένα βασικό πρόβλημα:
τα string στην C# είναι immutable (δηλαδή δεν αλλάζουν ποτέ αφού δημιουργηθούν).
💡 Τι σημαίνει ότι τα string είναι immutable
Όταν γράφεις κάτι σαν:
string s = "Hello";
s += " world!";
στην πραγματικότητα δεν τροποποιείται η ίδια μεταβλητή s.
Η C# δημιουργεί ένα νέο string στη μνήμη που περιέχει "Hello world!", και η παλιά "Hello" μένει εκεί μέχρι να την καθαρίσει το garbage collector.
Αυτό δεν είναι πρόβλημα για λίγες πράξεις,
αλλά αν έχεις χιλιάδες επαναλήψεις (π.χ. for loop που κάνει += κάθε φορά),
τότε δημιουργούνται χιλιάδες προσωρινά string αντικείμενα,
που επιβαρύνουν τη μνήμη και επιβραδύνουν την εφαρμογή.
🧱 Εδώ μπαίνει ο StringBuilder
Η κλάση System.Text.StringBuilder επιτρέπει να χτίζεις strings “κομμάτι-κομμάτι”,
χωρίς να δημιουργείται νέο αντικείμενο κάθε φορά.
Παράδειγμα:
StringBuilder sb = new StringBuilder();
sb.Append("Hello");
sb.Append(" ");
sb.Append("world!");
string result = sb.ToString();
➡️ Εδώ ο StringBuilder διατηρεί ένα εσωτερικό buffer (πίνακα χαρακτήρων).
Κάθε Append() προσθέτει χαρακτήρες σε αυτόν τον buffer.
Όταν τελειώσεις, το ToString() παράγει το τελικό string μία και μόνο φορά.
⚙️ Πώς δουλεύει εσωτερικά
Μπορείς να το φανταστείς σαν “δυναμικό πίνακα χαρακτήρων”:
- Ο StringBuilder ξεκινά με έναν εσωτερικό πίνακα (π.χ. 16 χαρακτήρες).
- Όταν γεμίσει, μεγαλώνει αυτόματα (συνήθως διπλασιάζει τη χωρητικότητα).
- Δεν ξαναδημιουργεί ολόκληρη τη συμβολοσειρά κάθε φορά — απλώς γράφει χαρακτήρες στο τέλος του buffer.
- Όταν καλέσεις ToString(), φτιάχνει ένα κανονικό string από το περιεχόμενο.
Αυτό κάνει τη διαδικασία πολύ πιο γρήγορη και αποδοτική όταν δουλεύεις με πολλές προσθήκες, ειδικά σε loops.
🧮 Παράδειγμα Απόδοσης
Χωρίς StringBuilder:
string text = "";
for (int i = 0; i < 10000; i++)
{
text += i.ToString() + " ";
}
→ Δημιουργεί 10.000 νέα string αντικείμενα!
→ Καταναλώνει πολλή μνήμη και χρόνο.
Με StringBuilder:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
sb.Append(i).Append(" ");
}
string text = sb.ToString();
→ Δημιουργεί μόνο ένα StringBuilder και ένα τελικό string στο τέλος.
→ Πολύ πιο αποδοτικό.
🧰 Κύριες Μέθοδοι του StringBuilder
Μέθοδος | Περιγραφή |
---|---|
Append(string) |
Προσθέτει string στο τέλος. |
AppendLine(string) |
Προσθέτει string και νέα γραμμή (\\n ). |
Insert(int index, string value) |
Εισάγει string σε συγκεκριμένη θέση. |
Remove(int start, int length) |
Αφαιρεί χαρακτήρες από το buffer. |
Replace(string oldValue, string newValue) |
Αντικαθιστά κείμενο μέσα στο buffer. |
Clear() |
Καθαρίζει το περιεχόμενο (χωρίς να δημιουργεί νέο αντικείμενο). |
ToString() |
Επιστρέφει το τελικό string. |
🧠 Παράδειγμα Χρήσης σε PalindromeCheck
Στο πρόγραμμά σου:
StringBuilder sb = new StringBuilder(input.Length);
foreach (char c in input)
{
if (char.IsLetterOrDigit(c))
sb.Append(char.ToLowerInvariant(c));
}
return sb.ToString();
Εδώ:
- Δημιουργείς έναν StringBuilder με αρχικό μέγεθος όσο το μήκος του input.
- ➜ Έτσι αποφεύγεις επαναλαμβανόμενες αυξήσεις του buffer.
- Προσθέτεις μόνο τους επιτρεπτούς χαρακτήρες (Append).
- Τους πεζοποιείς με ToLowerInvariant.
- Τελικά, με ToString() παίρνεις το “καθαρισμένο” κείμενο.
Έτσι αποφεύγεις να δημιουργείς ένα νέο string σε κάθε επανάληψη του foreach.
Είναι πολύ πιο αποδοτικό και σωστός τρόπος για τέτοια επεξεργασία.
🧭** Πότε να χρησιμοποιείς (και πότε όχι) StringBuilder**
✅ Χρησιμοποίησε StringBuilder όταν:
- Χτίζεις ένα string σταδιακά (π.χ. σε loop).
- Κάνεις πολλές “συναρμολογήσεις” string.
- Επεξεργάζεσαι μεγάλο κείμενο (όπως logs, αρχεία, HTML, SQL queries κ.λπ.).
🚫 Δεν χρειάζεται αν:
- Ενώνεις λίγα string (2–3 κομμάτια).
- Κάνεις string interpolation (π.χ. $\"Hello {name}\").
*Συνοψίζοντας *
- StringBuilder = ένας mutable builder για strings.
- Προσφέρει ταχύτητα και χαμηλή κατανάλωση μνήμης.
- Χρησιμοποιεί εσωτερικό buffer αντί να δημιουργεί νέα string.
- Τελικό αποτέλεσμα δίνεται με .ToString().
Top comments (0)