# Κλάσεις χαρακτήρων Μια κλάση χαρακτήρων ταιριάζει με ακριβώς έναν χαρακτήρα, επιλεγμένο από ένα σύνολο που ορίζετε. Ενώ ένα κυριολεκτικό `a` ταιριάζει μόνο με `a`, η κλάση `[abc]` ταιριάζει με οποιονδήποτε από τους `a`, `b`, ή `c`. ```perl /cat/; # matches 'cat' /[bcr]at/; # matches 'bat', 'cat', or 'rat' /item[0123456789]/; # matches 'item0' through 'item9' ``` Η κλάση εξακολουθεί να καταναλώνει έναν χαρακτήρα της συμβολοσειράς. Το `[bcr]at` ποτέ δεν ταιριάζει με `at` (δεν υπάρχει γράμμα) και ποτέ δεν ταιριάζει με `brat` (δύο γράμματα ενώ η κλάση περιμένει ένα). ## Εύρη Μέσα στα `[…]`, μια παύλα ανάμεσα σε δύο χαρακτήρες δηλώνει ένα συνεχές εύρος στο υποκείμενο σύνολο χαρακτήρων: ```perl /[0-9]/; # any ASCII digit /[a-z]/; # any ASCII lowercase letter /[a-zA-Z]/; # any ASCII letter /[0-9a-fA-F]/; # any hex digit ``` Τα εύρη μπορούν να συνδυαστούν με μεμονωμένους χαρακτήρες: ```perl /[0-9bx-z]aa/; # matches '0aa'..'9aa', 'baa', 'xaa', 'yaa', 'zaa' ``` Μια παύλα που βρίσκεται πρώτη ή τελευταία μέσα στην κλάση είναι κυριολεκτική: ```perl /[-ab]/; # matches '-', 'a', or 'b' /[ab-]/; # same ``` ## Άρνηση Ένα `^` ως πρώτος χαρακτήρας μέσα στα `[…]` αντιστρέφει την κλάση: ```perl /[^a]/; # any character except 'a' /[^0-9]/; # any non-digit ``` Ένα `^` οπουδήποτε αλλού είναι κυριολεκτικό: ```perl /[a^]/; # matches 'a' or '^' ``` Μια αρνημένη κλάση εξακολουθεί να ταιριάζει με *έναν* χαρακτήρα — το `[^a]` δεν ταιριάζει με την κενή συμβολοσειρά· απαιτεί έναν χαρακτήρα διαφορετικό από `a`. ## Ειδικοί χαρακτήρες μέσα σε κλάση Μέσα στα `[…]` το ειδικό σύνολο συρρικνώνεται σε `- ] \ ^ $` (και στο διαχωριστικό του μοτίβου). Οι υπόλοιποι — `.`, `*`, `+`, `?`, `(`, `)`, `{`, `}`, `|` — είναι κυριολεκτικοί μέσα σε κλάση: ```perl /[.+*]/; # matches a literal '.', '+', or '*' /[()]/; # matches '(' or ')' ``` Για να ταιριάξετε `]` μέσα στην κλάση, είτε διαφεύγετέ το είτε τοποθετήστε το πρώτο (μετά από τυχόν αρχικό `^`): ```perl /[\]]/; # matches ']' /[]ab]/; # matches ']', 'a', or 'b' ``` Τα `$` και `\` είναι ελαφρώς δύσχρηστα επειδή αλληλεπιδρούν με την παρεμβολή και τη διαφυγή: ```perl my $x = 'bcr'; /[$x]at/; # matches 'bat', 'cat', or 'rat' — interpolated /[\$x]at/; # matches '$at' or 'xat' — '$' is literal /[\\$x]at/; # matches '\at' plus interpolation of $x ``` Το `\b` μέσα σε κλάση χαρακτήρων σημαίνει *backspace* (`\x08`), όχι «όριο λέξης». Εκτός κλάσης είναι η διεκδίκηση ορίου λέξης. Αυτή είναι η συχνότερη παγίδα διπλής σημασίας στη σύνταξη regex — δείτε το κεφάλαιο [anchors and assertions](anchors-and-assertions.md) για τη μορφή ορίου. ## Συντομογραφικές κλάσεις Αρκετές συνηθισμένες κλάσεις έχουν συντομογραφικά ονόματα που χρησιμοποιούνται τόσο μέσα όσο και έξω από τα `[…]`: | Συντομογραφία | Ταιριάζει με | |-----------------|---------------------------------------------------------------------| | `\d` | ένα ψηφίο | | `\D` | ένα μη ψηφίο | | `\w` | έναν χαρακτήρα λέξης (αλφαριθμητικό ή `_`) | | `\W` | έναν χαρακτήρα μη λέξης | | `\s` | λευκό χαρακτήρα (διάστημα, στηλοθέτη, `\r`, `\n`, `\f`, και άλλους) | | `\S` | μη λευκό χαρακτήρα | | `\h` | οριζόντιο λευκό χαρακτήρα (διάστημα, στηλοθέτη, Unicode) | | `\H` | μη οριζόντιο λευκό χαρακτήρα | | `\v` | κάθετο λευκό χαρακτήρα (`\n`, `\r`, `\f`, …) | | `\V` | μη κάθετο λευκό χαρακτήρα | | `\R` | αλλαγή γραμμής: `\r\n`, `\n`, `\v`, `\f`, `\x{85}`, … | | `\N` | οποιονδήποτε χαρακτήρα εκτός από `\n` (ανεξαρτήτως `/s`) | Υπό Unicode (η προεπιλογή), τα `\d`, `\w`, `\s` ταιριάζουν με περισσότερα από μόνο ASCII. Το `\d` ταιριάζει με οποιοδήποτε ψηφίο Unicode (ψηφία Ντεβανάγκαρι, αραβο-ινδικά ψηφία, και πολλά άλλα), το `\w` ταιριάζει με οποιοδήποτε γράμμα σε οποιαδήποτε γραφή συν σημάδια και συνδετική στίξη, και το `\s` προσθέτει χαρακτήρες διαστήματος Unicode όπως το αδιάσπαστο διάστημα. Για να τα περιορίσετε σε ASCII, προσθέστε τον τροποποιητή `/a` ή χρησιμοποιήστε ρητά εύρη όπως `[0-9]` και `[A-Za-z_0-9]`. ```perl "item0" =~ /\w\w\w\w\d/; # matches "abc\x{0660}" =~ /\w\w\w\d/; # matches: U+0660 is an Arabic-Indic zero "abc\x{0660}" =~ /\w\w\w\d/a;# does not match under /a ``` Το `\R` είναι η συντομογραφία αλλαγής γραμμής — ταιριάζει με οποιαδήποτε από τις αναγνωρισμένες ακολουθίες αλλαγής γραμμής ως μία μονάδα. Χρήσιμο για την ανάλυση κειμένου που μπορεί να έχει εναλλακτικά CRLF, LF, ή σπανιότερους τερματιστές γραμμής. Σε αντίθεση με μια κλάση, το `\R` μπορεί να ταιριάξει με *δύο* χαρακτήρες (η περίπτωση CRLF) και έτσι δεν μπορεί να εμφανιστεί μέσα στα `[…]`. Το `\N` (κεφαλαίο) σημαίνει «οποιονδήποτε χαρακτήρα εκτός από `\n`», και *δεν* επηρεάζεται από τον τροποποιητή `/s`. Αυτή είναι η διπλή σημασία για την οποία πρέπει να προσέξετε: το `\N{NAME}` (με αγκύλη) είναι ονομαστική διαφυγή χαρακτήρα Unicode (δείτε το κεφάλαιο [unicode](unicode.md))· το γυμνό `\N` είναι η κλάση μη νέας γραμμής. ## Η τελεία Η `.` ταιριάζει με οποιονδήποτε μεμονωμένο χαρακτήρα εκτός από τη νέα γραμμή. Υπό τον τροποποιητή `/s` (καλύπτεται στο κεφάλαιο [modifiers](modifiers.md)), η `.` ταιριάζει επίσης με νέα γραμμή: ```perl "a\nb" =~ /a.b/; # does not match "a\nb" =~ /a.b/s; # matches ``` Όταν θέλετε «οποιονδήποτε χαρακτήρα συμπεριλαμβανομένης της νέας γραμμής» χωρίς `/s`, ο κλασικός ιδιωματισμός είναι το `[\s\S]` (ή `[\d\D]`): ```perl "a\nb" =~ /a[\s\S]b/; # matches without /s ``` Το τέχνασμα είναι ότι οποιοσδήποτε χαρακτήρας είναι είτε λευκός χαρακτήρας είτε μη λευκός χαρακτήρας· η κλάση καλύπτει και τα δύο. ## Σύνθεση κλάσεων Μπορείτε να αναμείξετε συντομογραφίες, εύρη, και μεμονωμένους χαρακτήρες μέσα σε μία κλάση: ```perl /[\d\s]/; # a digit or whitespace /[A-Z\d_]/; # uppercase letter, digit, or underscore /[a-zA-Z\d]/; # letter or digit (ASCII) ``` Ο νόμος του De Morgan έχει σημασία: το `[^\d\w]` *δεν* είναι το `[\D\W]`. Το πρώτο απαιτεί ο χαρακτήρας να είναι *και* μη ψηφίο *και* μη χαρακτήρας λέξης. Όμως κάθε ψηφίο είναι χαρακτήρας λέξης, οπότε το `[^\d\w]` απλοποιείται σε `[^\w]`, δηλαδή `\W`. Να είστε προσεκτικοί όταν συνδυάζετε αρνημένες συντομογραφίες. ## Κλάσεις POSIX Οι κλάσεις χαρακτήρων POSIX χρησιμοποιούν τη μορφή `[:name:]` και δουλεύουν μόνο μέσα σε `[…]`: | POSIX | Ισοδύναμο | |--------------|--------------------------------------------------| | `[:alpha:]` | αλφαβητικός | | `[:alnum:]` | αλφαριθμητικός | | `[:digit:]` | ψηφίο (όπως `\d`) | | `[:word:]` | χαρακτήρας λέξης (επέκταση Perl) | | `[:space:]` | λευκός χαρακτήρας (όπως `\s`) | | `[:upper:]` | κεφαλαία | | `[:lower:]` | πεζά | | `[:xdigit:]` | δεκαεξαδικό ψηφίο | | `[:ascii:]` | 0x00–0x7F | | `[:cntrl:]` | χαρακτήρας ελέγχου | | `[:graph:]` | εκτυπώσιμος, όχι διάστημα | | `[:print:]` | εκτυπώσιμος, συμπεριλαμβανομένου του διαστήματος | | `[:punct:]` | στίξη | | `[:blank:]` | διάστημα ή στηλοθέτη | Αρνηθείτε μια κλάση POSIX με `^` *μέσα* στις άνω-κάτω τελείες: ```perl /[[:^digit:]]/; # same as \D /[[:alpha:][:digit:]]/; # letter or digit — equivalent to \w minus '_' ``` Οι κλάσεις POSIX ακολουθούν τους ίδιους κανόνες Unicode έναντι ASCII με τις συντομογραφίες: χωρίς `/a`, η `[:alpha:]` είναι το αλφαβητικό σύνολο Unicode. Το POSIX ορίζει επίσης δύο σχετικές κατασκευές που σπάνια υλοποιούνται: - **Στοιχεία ταξινόμησης** `[.span-ll.]` — ταιριάζουν με ένα στοιχείο ταξινόμησης πολλών χαρακτήρων ως μία μονάδα (π.χ. το ισπανικό `ll` ιστορικά). - **Κλάσεις ισοδυναμίας** `[[=n=]]` — ταιριάζουν με οποιονδήποτε χαρακτήρα που είναι ισοδύναμος υπό τους κανόνες ταξινόμησης του locale (π.χ. τονισμένες παραλλαγές του `n`). Η Perl αναγνωρίζει τη σύνταξη αλλά αντιμετωπίζει και τις δύο μορφές ως τους κυριολεκτικούς χαρακτήρες. Στην πράξη κανένα φορητό σενάριο δεν βασίζεται σε αυτές· τεκμηριώνονται για πληρότητα. ## Ιδιότητες Unicode Το Unicode ορίζει χιλιάδες ιδιότητες. Η σημειογραφία είναι `\p{Name}` για «έχει αυτή την ιδιότητα» και `\P{Name}` για «δεν έχει αυτή την ιδιότητα»: ```perl /\p{Lu}/; # any uppercase letter, any script /\p{Greek}/; # any character in the Greek script /\p{Number}/; # any numeric character /\P{ASCII}/; # any non-ASCII character ``` Σύντομα μονόγραμμα ψευδώνυμα υπάρχουν για συνηθισμένες ιδιότητες και παραλείπουν τα άγκιστρα: το `\pL` είναι γράμμα, το `\pN` αριθμός, το `\pP` στίξη. Το `\p{L}` είναι το ίδιο με το `\pL`. Το κεφάλαιο [unicode](unicode.md) καλύπτει τις ιδιότητες λεπτομερώς, συμπεριλαμβανομένης της σύνθετης μορφής `\p{Name=Value}`, του συμπλέγματος γραφημάτων `\X`, και των τροποποιητών συνόλου χαρακτήρων `/a`, `/u`, `/l`, `/d`. ## Εκτεταμένες κλάσεις σε αγκύλες — `(?[ ])` Η τυπική σύνταξη `[…]` χειρίζεται καλά τις ενώσεις («οποιοσδήποτε από αυτούς τους χαρακτήρες») αλλά δεν έχει πράξεις συνόλων στις κλάσεις. Η εκτεταμένη μορφή `(?[ … ])` έχει: | Τελεστής | Σημασία | |------------|------------------------------------------------------------------------| | `+` ή `|` | ένωση (οι ίδιοι χαρακτήρες που έχει οποιοσδήποτε από τους τελεσταίους) | | `&` | τομή (και στους δύο) | | `-` | διαφορά (στον αριστερό, όχι στον δεξιό) | | `^` | συμμετρική διαφορά (στον έναν αλλά όχι και στους δύο) | | `!` | συμπλήρωμα (όλα εκτός από) | Οι λευκοί χαρακτήρες μέσα σε `(?[…])` αγνοούνται, οπότε οι τελεστές διαβάζονται ως αριθμητικοί. ```perl # Greek letters only: /(?[ \p{Greek} & \p{Letter} ])/; # Letters that are not Latin: /(?[ \p{Letter} - \p{Latin} ])/; # Hex digit, but not 'a' through 'f': /(?[ [0-9A-Fa-f] - [a-f] ])/; ``` Η κατασκευή είναι πιο χρήσιμη όταν συνδυάζονται ιδιότητες Unicode που επικαλύπτονται. Χωρίς αυτήν, οι ίδιες εκφράσεις θα απαιτούσαν εκτεταμένες διεκδικήσεις περιβάλλοντος ή λογική εκτός μοτίβου. Το `(?[…])` είναι το ίδιο μια κλάση χαρακτήρων — καταναλώνει έναν χαρακτήρα και μπορεί να ποσοδεικτηθεί: ```perl /(?[ \p{Letter} & \p{ASCII} ])+ /x; # ASCII letters ``` Επιφύλαξη: το `(?[…])` έχει τον δικό του μικρό αναλυτή μέσα στον αναλυτή regex. Μέσα του, αναγνωρίζονται μόνο συγκεκριμένοι τελεστές και τελεσταίοι. Τα λάθη παράγουν συγκεκριμένα σφάλματα κατά τη μεταγλώττιση, κάτι που με τη σειρά του σημαίνει ότι η *αυστηρή λειτουργία* (`use re 'strict'`) πιάνει περισσότερες κακές εκφράσεις κλάσεων όταν χρησιμοποιείτε την εκτεταμένη μορφή. ## Η αρνημένη κλάση κερδίζει το `.*?` Ένα σύνηθες μοτίβο για νεοφερμένους: χρησιμοποιήστε `.*?` (μη άπληστη `.`) για να ταιριάξετε τα πάντα μέχρι ένα διαχωριστικό, όπως `<.*?>`. Το μοτίβο δουλεύει στις εισόδους που το δοκιμάσατε· σε αντιπαραθετική είσοδο όχι. ```perl " " =~ /<.*?>/; # matches '' — fine " foo" =~ /<.+?>foo/; # matches ' foo' — bad ``` Στη δεύτερη περίπτωση η μηχανή ταίριαξε πρώτα το ``, μετά χρειαζόταν `foo` αλλά βρήκε ένα διάστημα. Υπό αυτή την πίεση οπισθοχώρησης το μη άπληστο `.+?` αναγκάστηκε να επεκταθεί, καταναλώνοντας ευχαρίστως το `>` του `` και το διάστημα μέχρι να ευθυγραμμιστεί το `foo`. Η αρνημένη κλάση χαρακτήρων δεν μπορεί να υποχωρήσει με αυτόν τον τρόπο: ```perl " foo" =~ /<[^>]+>foo/; # matches 'foo' — [^>]+ refuses to cross '>' ``` Δύο λόγοι να προτιμάτε το `[^>]+` έναντι του `.+?` οποτεδήποτε το διαχωριστικό είναι μεμονωμένος χαρακτήρας: 1. **Ορθότητα**: η αρνημένη κλάση είναι σκληρό φράγμα· η μη άπληστη μορφή είναι προτίμηση. 2. **Απόδοση**: μια αρνημένη κλάση συμμετέχει στη βελτιστοποίηση απλής επανάληψης· το `.+?` όχι (η μηχανή πρέπει να βγαίνει από τον εσωτερικό βρόχο σε κάθε επανάληψη για να ελέγξει τι ακολουθεί). Σε μακριές εισόδους αυτό έχει σημασία. ## Επεξεργασμένο παράδειγμα: μια regex διεύθυνσης IP Η κανονική άσκηση «ειδικότητα έναντι πολυπλοκότητας». Πέντε επαναλήψεις, κάθε μία διορθώνει μια κατηγορία ασάφειας: **1. Αφελής.** «Τέσσερις ομάδες ψηφίων χωρισμένες με τελεία.» ```perl /[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/; ``` Ταιριάζει ευχαρίστως με `and then.....?` — κάθε ομάδα είναι προαιρετική, το μοτίβο ικανοποιείται από τέσσερις τελείες και τίποτα άλλο. **2. Απαιτήστε ψηφία.** Αγκυρώστε το μοτίβο. ```perl /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/; ``` Ταιριάζει με `1234.5678.9101112.131415`. Κάθε ομάδα έχει ψηφία αλλά χωρίς άνω όριο πλήθους. **3. Περιορίστε το πλήθος ψηφίων, κακώς.** ```perl /^\d{3}\.\d{3}\.\d{3}\.\d{3}$/; ``` Ταιριάζει με `192.168.001.001` αλλά απορρίπτει το `1.2.3.4` — τα αρχικά μηδενικά δεν γράφονται πάντα. **4. Επιτρέψτε 1 έως 3 ψηφία.** ```perl /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/; ``` Τώρα ταιριάζει με `1.2.3.4` και απορρίπτει το `1234.5.6.7`. Αλλά ταιριάζει επίσης με `999.999.999.999` — πέρα από το εύρος 0–255. **5. Σωστό ως προς το εύρος.** ```perl /^(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\. (?:25[0-5]|2[0-4]\d|[01]?\d\d?)\. (?:25[0-5]|2[0-4]\d|[01]?\d\d?)\. (?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/x; ``` Κάθε ομάδα είναι μία από: `25[0-5]` (250–255), `2[0-4]\d` (200–249), ή `[01]?\d\d?` (0–199 σε διάφορες μορφές). Το μοτίβο τώρα ταιριάζει με *ακριβώς* τις συμβολοσειρές που ονομάζουν μια συντακτικά έγκυρη διεύθυνση IPv4. Το μάθημα δεν είναι «αποστηθίστε αυτή τη regex». Είναι η *εξέλιξη*: κάθε επανάληψη σφίγγει ένα συγκεκριμένο είδος ασάφειας. Η σωστή regex για ένα πρόβλημα είναι αυτή που δέχεται ακριβώς τις σωστές εισόδους και απορρίπτει όλες τις υπόλοιπες, και φτάνετε εκεί μόνο ρωτώντας τι πραγματικά επέτρεπε η *προηγούμενη* regex. ## Μεταξύ μηχανών: συντομογραφικές κλάσεις Οι συντομογραφίες `\d`, `\w`, `\s` δεν είναι φορητές. Το κεφάλαιο [cross-engine](cross-engine.md) έχει τον πλήρη πίνακα· οι σχετικές γραμμές αποσπασμένες: | Συντομογραφία | Perl 5.42 (προεπιλογή) | PCRE2 | Emacs | POSIX BRE / ERE | RE2 / Go (προεπιλογή) | |-----------------|----------------------------|---------|----------------------------------------------|-------------------|---------------------------| | `\d` | ASCII (ή Unicode υπό `/u`) | ASCII | ΟΧΙ (χρησιμοποιήστε `[0-9]` ή `[[:digit:]]`) | ΟΧΙ | ASCII· Unicode υπό `(?u)` | | `\w` | ASCII ή Unicode | ASCII | ναι (καθοδηγείται από τον πίνακα σύνταξης) | ΟΧΙ | ASCII· Unicode υπό `(?u)` | | `\s` | ASCII ή Unicode | ASCII | ναι | ΟΧΙ | ASCII· Unicode υπό `(?u)` | | όριο λέξης `\b` | ναι | ναι | ναι (`\<`/`\>` παραδοσιακά) | ΟΧΙ | ναι | | `\h`, `\v` | ναι | ναι | ΟΧΙ | ΟΧΙ | ΟΧΙ | Δύο πράγματα να αφομοιώσετε: 1. Το POSIX BRE και το ERE στερούνται εντελώς των `\d`, `\w`, `\s`. Τα φορητά σενάρια κελύφους χρησιμοποιούν `[0-9]`, `[[:alnum:]_]`, `[[:space:]]`. 2. Ο Emacs έχει `\w` και `\s` αλλά όχι `\d`. Η σύνταξη `\s` του Emacs *ακολουθείται από* έναν χαρακτήρα κλάσης σύνταξης (`\s-` για λευκό χαρακτήρα, `\sw` για λέξη) — μοναδικό στον Emacs. Οι κλάσεις σε αγκύλες POSIX (`[[:digit:]]`, `[[:alpha:]]`, …) είναι η καθολικά φορητή γραφή: κάθε μηχανή στη σύγκριση τις αναγνωρίζει. ## Μια χρήσιμη συνήθεια Οι ονομαστικές και οι συντομογραφικές κλάσεις είναι σχεδόν πάντα σαφέστερες από τα ρητά εύρη. Το `\d{4}-\d{2}-\d{2}` διαβάζεται· το `[0-9]{4}-[0-9]{2}-[0-9]{2}` χρειάζεται μια στιγμή. Χρησιμοποιείτε τα εύρη μόνο όταν έχετε συγκεκριμένο λόγο — συνήθως απόδοση σε καυτό βρόχο, ή σκόπιμο περιορισμό σε ASCII. ## Δείτε επίσης - Το κεφάλαιο [unicode](unicode.md) — `\p{…}`, `\P{…}`, `\X`, οι τροποποιητές συνόλου χαρακτήρων `/a`, `/u`, `/l`, `/d`. - Το κεφάλαιο [anchors and assertions](anchors-and-assertions.md) — `\b` εκτός κλάσης. - Το κεφάλαιο [cross-engine](cross-engine.md) — πλήρης πίνακας υποστήριξης συντομογραφιών μεταξύ μηχανών. - [`m`](../../p5/core/perlfunc/m.md) — ο τελεστής αντιστοίχισης. - [`qr`](../../p5/core/perlfunc/qr.md) — μεταγλώττιση μοτίβου για επαναχρησιμοποίηση.