# Βασικά Η μικρότερη χρήσιμη regex είναι μια απλή συμβολοσειρά. Το `"Hello World" =~ /World/` ρωτά: περιέχει η συμβολοσειρά στα αριστερά το μοτίβο στα δεξιά; Το περιέχει, άρα η έκφραση είναι αληθής. ```perl if ("Hello World" =~ /World/) { print "matched\n"; } ``` Τα `//` περικλείουν το μοτίβο. Ο τελεστής `=~` συνδέει το μοτίβο με τη συμβολοσειρά που θέλετε να ελέγξετε. Χωρίς τελεστή σύνδεσης, η Perl εφαρμόζει το μοτίβο στο `$_`. ## Ο τελεστής αντιστοίχισης Η εκτεταμένη μορφή είναι `m//`: ```perl "Hello World" =~ m/World/; "Hello World" =~ m!World!; # alternate delimiters "Hello World" =~ m{World}; # paired delimiters ``` Το `m` σάς επιτρέπει να επιλέξετε οποιοδήποτε διαχωριστικό. Αυτό έχει σημασία όταν το ίδιο το μοτίβο περιέχει το προεπιλεγμένο διαχωριστικό `/` — συγκρίνετε ```perl "/usr/bin/perl" =~ /\/usr\/bin\/perl/; # leaning toothpick syndrome "/usr/bin/perl" =~ m!/usr/bin/perl!; # clearer ``` Τα ζευγαρωτά διαχωριστικά (`{}`, `()`, `[]`, `<>`) εμφωλεύονται, κάτι που είναι χρήσιμο όταν το μοτίβο περιέχει τον χαρακτήρα του διαχωριστικού. Χωρίς `m`, η αρχική κάθετος είναι υποχρεωτική: μόνο `/pat/`. Με `m`, το αρχικό `m` είναι υποχρεωτικό: `m{pat}`, όχι `{pat}`. Μια μικρή αλλά χρήσιμη γωνία: τα `m''` (απλά εισαγωγικά ως διαχωριστικά) κάνουν το μοτίβο *τύπου απλών εισαγωγικών* — χωρίς παρεμβολή μεταβλητών, χωρίς διαφυγές διπλών εισαγωγικών. Χρήσιμο όταν το μοτίβο πρόκειται να περιέχει κυριολεκτικό `$` ή `@` και δεν θέλετε να τα διαφεύγετε. ```perl 'price: $10' =~ m'\$\d+'; # $-as-anchor would be /$\d+/ 'price: $10' =~ m'$10'; # literal '$10' — no interpolation ``` ## Άλλοι τελεστές regex Το `m//` είναι ένα από τα τέσσερα: | Τελεστής | Σκοπός | |-------------------------|--------------------------------------------------------------| | `m//` | αντιστοίχιση — ταιριάζει το μοτίβο με τη συμβολοσειρά; | | `s///` | αντικατάσταση — αντικαθιστά την αντιστοιχία με κάτι άλλο | | `qr//` | μεταγλωττίζει ένα αντικείμενο μοτίβου για επαναχρησιμοποίηση | | `tr///` (επίσης `y///`) | μετάφραση χαρακτήρα προς χαρακτήρα | Το `tr///` *δεν* είναι τελεστής regex παρότι βρίσκεται στην ίδια γειτονιά — εκτελεί μετάφραση κλάσεων χαρακτήρων, όχι αντιστοίχιση μοτίβων. Αναφέρεται για πληρότητα· δείτε [`tr`](../../p5/core/perlfunc/tr.md) για τη σημασιολογία του. Τα [`m`](../../p5/core/perlfunc/m.md), [`s`](../../p5/core/perlfunc/s.md) και [`qr`](../../p5/core/perlfunc/qr.md) μοιράζονται όλα τη σύνταξη regex που καλύπτεται σε αυτόν τον οδηγό. Οι διαφορές βρίσκονται σε αυτό που κάνουν *με* μια επιτυχημένη αντιστοιχία. ## Επαναχρησιμοποίηση μοτίβου με `qr//` Το `qr//` μεταγλωττίζει ένα μοτίβο μία φορά και παράγει ένα επαναχρησιμοποιήσιμο αντικείμενο. Χρησιμοποιήστε το όταν το ίδιο μοτίβο αντιστοιχίζεται επανειλημμένα, ιδίως μέσα σε βρόχους: ```perl my $word = qr/\b[a-z]+\b/; for my $line (@lines) { while ($line =~ /$word/g) { print "$&\n"; } } ``` Το μεταγλωττισμένο αντικείμενο `qr//` εισάγεται σε άλλα μοτίβα μέσω παρεμβολής. Επίσης σας επιτρέπει να χτίζετε μοτίβα από ονομασμένα τμήματα, κάτι που γίνεται απαραίτητο για κάθε regex πάνω από περίπου δέκα γραμμές: ```perl my $name = qr/[A-Z][a-z]+/; my $number = qr/\d+/; my $entry = qr/$name \s+ $number/x; "Alice 42" =~ /^$entry$/; # matches ``` Το ίδιο όφελος της μίας μεταγλώττισης, εκφρασμένο στο σωστό επίπεδο αφαίρεσης. ## Σύνδεση: `=~` και `!~` Το `=~` ρωτά «ταιριάζει;». Το `!~` ρωτά «αποτυγχάνει να ταιριάξει;». ```perl $s = "Hello World"; print "yes\n" if $s =~ /World/; # yes print "no\n" if $s !~ /planet/; # no ``` Το `!~` δεν είναι ξεχωριστή κατασκευή regex — είναι η αρνημένη σύνδεση. Ισοδυναμεί με `not ($s =~ /pat/)`. ## Αντιστοίχιση με το `$_` Αν παραλείψετε τη σύνδεση, η αντιστοίχιση γίνεται με το `$_`: ```perl for ("cat", "dog", "bird") { print "has an 'o'\n" if /o/; # implicit: $_ =~ /o/ } ``` Αυτό είναι ιδιωματικό σε βρόχους `while (<>)`, μέσα σε `grep` και `map`, και μέσα σε βρόχους `for` που ορίζουν το `$_`. ## Διάκριση πεζών-κεφαλαίων και η προεπιλεγμένη άγκυρα Οι αντιστοιχίες γίνονται με διάκριση πεζών-κεφαλαίων και χωρίς αγκύρωση: ```perl "Hello" =~ /hello/; # does not match — case differs "Hello" =~ /ell/; # matches — inside the string is fine ``` Για αντιστοίχιση χωρίς διάκριση πεζών-κεφαλαίων, προσθέστε `/i`. Για να περιορίσετε την αντιστοιχία στην αρχή ή το τέλος της συμβολοσειράς, χρησιμοποιήστε άγκυρες. Και τα δύο καλύπτονται στα δικά τους κεφάλαια. Όταν ένα μοτίβο μπορεί να ταιριάξει σε περισσότερες από μία θέσεις, η Perl δοκιμάζει από τα αριστερά και παίρνει την πρώτη που λειτουργεί: ```perl "That hat is red" =~ /hat/; # matches 'hat' in 'That', not in 'hat' ``` Ο κανόνας «η αντιστοιχία πιο αριστερά κερδίζει» είναι θεμελιώδης και υπερισχύει κάθε άλλης προτίμησης αντιστοίχισης: μια αντιστοιχία σε προγενέστερη θέση είναι πάντα καλύτερη από μια αντιστοιχία σε μεταγενέστερη θέση, ανεξάρτητα από τις εσωτερικές επιλογές κάθε αντιστοίχισης. Αυτό αποκαλείται μερικές φορές *ιδιότητα bump-along*: η μηχανή προσπαθεί να ταιριάξει στη θέση 0· αν αποτύχει, μετακινείται στη θέση 1· αν αποτύχει, στη θέση 2· κ.ο.κ., επιστρέφοντας την πρώτη επιτυχία. ## Μετα-χαρακτήρες Οι περισσότεροι χαρακτήρες σε ένα μοτίβο ταιριάζουν με τον εαυτό τους. Οι παρακάτω όχι: ```none { } [ ] ( ) ^ $ . | * + ? \ ``` Δύο ακόμα είναι ειδικοί μόνο σε συγκεκριμένα περιβάλλοντα: - Το `-` είναι μετα-χαρακτήρας μόνο μέσα σε κλάση χαρακτήρων, όπου σχηματίζει εύρος (`[a-z]`). Εκτός `[…]` είναι κυριολεκτικό. - Το `#` είναι μετα-χαρακτήρας μόνο υπό τη σημαία `/x`, όπου εισάγει σχόλιο μέχρι το τέλος της γραμμής. Χωρίς `/x` είναι κυριολεκτικό. Κάθε μετα-χαρακτήρας έχει μια ειδική σημασία που καλύπτεται αργότερα. Για να ταιριάξετε ένα κυριολεκτικό αντίγραφο, βάλτε μια ανάστροφη κάθετο μπροστά: ```perl "2+2=4" =~ /2+2/; # fails — '+' is a quantifier, needs escaping "2+2=4" =~ /2\+2/; # matches "end." =~ /end\./; # matches a literal dot "end." =~ /end./; # also matches — but . matches any character, # so this would also match "endx", "end ", etc. ``` Η ίδια η ανάστροφη κάθετος είναι μετα-χαρακτήρας, οπότε μια κυριολεκτική ανάστροφη κάθετος σε ένα μοτίβο χρειάζεται `\\`: ```perl 'C:\WIN32' =~ /C:\\WIN/; # matches ``` Ένας μετα-χαρακτήρας που δεν έχει τίποτα ειδικό να κάνει στο περιβάλλον του επιστρέφει στο να ταιριάζει με τον εαυτό του. Το `}` κλείνει μόνο έναν ποσοδείκτη `{…}`· εκτός αυτού του περιβάλλοντος είναι κυριολεκτικό `}`. Αυτό είναι βολικό αλλά εύκολο να παρερμηνευτεί· δείτε *Αυστηρή λειτουργία* παρακάτω. ## Αυστηρή λειτουργία: `use re 'strict'` Το `use re 'strict'` μετατρέπει την προηγουμένως ανεκτή χαλαρότητα στις regex σε σφάλματα κατά τη μεταγλώττιση. Χρησιμοποιήστε το όταν θέλετε ο μεταγλωττιστής regex να επισημαίνει μοτίβα που *πιθανώς* σημαίνουν κάτι διαφορετικό από αυτό που γράψατε: ```perl use re 'strict'; /abc{,1/; # error: unescaped '{' in non-quantifier context /(?-p)/; # error: useless negation of always-on flag /[a-]/; # error: dash at end of class ``` Η αυστηρή λειτουργία είναι ανά λεξική εμβέλεια, οπότε μπορεί να ενεργοποιηθεί για αρθρώματα με πολλές regex χωρίς να επηρεάζει άλλον κώδικα. Δεν είναι προεπιλεγμένη γιατί θα έσπαζε λειτουργικά παλαιότερα μοτίβα· ο νέος κώδικας θα έπρεπε να την εξετάζει. ## Ακολουθίες διαφυγής Οι μη εκτυπώσιμοι χαρακτήρες χρησιμοποιούν τις ίδιες ακολουθίες διαφυγής όπως στις συμβολοσειρές διπλών εισαγωγικών: | Ακολουθία | Ταιριάζει με | |-------------|-------------------------------------------| | `\t` | στηλοθέτη (tab) | | `\n` | νέα γραμμή | | `\r` | επαναφορά κεφαλής (carriage return) | | `\f` | αλλαγή σελίδας (form feed) | | `\a` | ειδοποίηση (κουδούνι) | | `\e` | escape (`\x1B`) | | `\0` | byte NUL | | `\xHH` | byte με δεκαεξαδική τιμή HH | | `\x{…}` | σημείο κώδικα Unicode με δεκαεξαδική τιμή | | `\o{…}` | οκταδικό σημείο κώδικα | | `\cX` | control-X | | `\N{…}` | χαρακτήρας Unicode με όνομα | ```perl "1000\t2000" =~ /0\t2/; # matches "a\x{263a}b" =~ /\x{263a}/; # matches U+263A, WHITE SMILING FACE ``` Η πλήρης ιστορία Unicode βρίσκεται στο κεφάλαιο [unicode](unicode.md). ## Μεταβλητές μέσα στα μοτίβα Ένα μοτίβο (από προεπιλογή) παρεμβάλλεται όπως μια συμβολοσειρά διπλών εισαγωγικών, οπότε οι μεταβλητές αντικαθίστανται πριν την αντιστοίχιση: ```perl my $word = "house"; "housecat" =~ /$word/; # matches "housecat" =~ /${word}cat/; # matches — braces disambiguate ``` Για να ταιριάξετε ένα κυριολεκτικό `$` ή `@`, διαφεύγετέ το: ```perl 'price: $10' =~ /\$10/; # matches a literal dollar sign ``` Αν μια συμβολοσειρά που παρέχεται από τον χρήστη πρόκειται να παρεμβληθεί σε ένα μοτίβο και θέλετε οι μετα-χαρακτήρες της να αντιμετωπιστούν κυριολεκτικά, χρησιμοποιήστε [`quotemeta`](../../p5/core/perlfunc/quotemeta.md) — ή το εντός μοτίβου ισοδύναμό του `\Q…\E`: ```perl my $input = "1+1"; "1+1=2" =~ /\Q$input\E/; # matches the literal string ``` Χωρίς `\Q…\E` το `+` θα διαβαζόταν ως ποσοδείκτης. ## Πώς διαβάζεται μια regex Η Perl διαβάζει ένα μοτίβο regex σε τέσσερις φάσεις. Η γνώση των φάσεων εξηγεί μερικά ερωτήματα του τύπου «γιατί δουλεύει αυτό;»: 1. **Φάση Α**: ο αναλυτής αναγνωρίζει το διαχωριστικό και εντοπίζει το τέλος του μοτίβου. Τα σχόλια `(?#…)` αφαιρούνται. 2. **Φάση Β**: το μοτίβο αναλύεται ως *συμβολοσειρά τύπου διπλών εισαγωγικών* — οι μεταβλητές παρεμβάλλονται, οι ακολουθίες διαφυγής επεξεργάζονται, το `\Q…\E` μεταφράζεται σε διαφυγή τύπου `quotemeta`. 3. **Φάση Γ**: υπό `/x` ή `/xx`, οι λευκοί χαρακτήρες χωρίς διαφυγή και τα σχόλια μετά το `#` αφαιρούνται. 4. **Φάση Δ**: ο μεταγλωττιστής regex διαβάζει το αποτέλεσμα και το μετατρέπει στην εσωτερική μορφή της μηχανής. Η σειρά έχει σημασία επειδή οι φάσεις Β και Δ λειτουργούν σε διαφορετικές αναπαραστάσεις. Το `\Q$dir\E` επεξεργάζεται στη Φάση Β, πριν το δει ο μεταγλωττιστής regex — μέχρι τη Φάση Δ, τα περιεχόμενα της μεταβλητής έχουν ήδη διαφύγει, και ο μεταγλωττιστής regex βλέπει ένα κυριολεκτικό μοτίβο. Αντιθέτως, το `\U…\E` ερμηνεύεται από τη Φάση Β ως οδηγία επεξεργασίας συμβολοσειράς (μετατροπή των περιεχομένων σε κεφαλαία), κάτι που σχεδόν σίγουρα *δεν* είναι αυτό που θέλετε μέσα σε μια regex. Η σύμβαση είναι: `\Q` και `\E` για σκοπούς regex· `\U`, `\L`, `\u`, `\l` μόνο όταν ξέρετε τι κάνετε. Το `(?#comment)` αφαιρείται προτού η Φάση Β δει καν το μοτίβο. Ένα κυριολεκτικό `#` μέσα στο `(?#…)` είναι μια χαρά. Ένα κυριολεκτικό `)` όχι — το σχόλιο τελειώνει στην πρώτη `)`. ## Η νωρίτερη αντιστοιχία κερδίζει — το bump-along Ο Friedl το διατυπώνει με ακρίβεια: > Η αντιστοιχία που ξεκινά νωρίτερα κερδίζει. Η θέση 0 δοκιμάζεται πρώτη, μετά η 1, μετά η 2, κ.ο.κ. Η μηχανή *ποτέ* δεν προτιμά μια μεταγενέστερη, μακρύτερη ή «πιο αισθητικά καλή» αντιστοιχία έναντι μιας προγενέστερης. Αυτό είναι τόσο θεμελιώδες ώστε διαμορφώνει κάθε άλλον κανόνα σε αυτόν τον οδηγό: - «Οι άπληστοι ποσοδείκτες αρπάζουν όσο το δυνατόν περισσότερα» — *στην τρέχουσα θέση εκκίνησης*. Η αρπαγή συμβαίνει αφού το bump-along έχει επιλέξει τη θέση. - «Η πιο αριστερή εναλλακτική κερδίζει» — *στην τρέχουσα θέση εκκίνησης*. Η εναλλακτική που επιλέγεται επηρεάζει τι συλλαμβάνεται αλλά όχι το πού ξεκινά η αντιστοιχία. - Άγκυρες όπως η `^` περιορίζουν *ποιες θέσεις είναι νόμιμες*, όχι τι προτιμάται ανάμεσα στις νόμιμες. ## Πείτε αυτό που εννοείτε Το επαναλαμβανόμενο σημείο του Friedl: η ασάφεια στη regex προκαλεί τόσο προβλήματα ορθότητας όσο και προβλήματα απόδοσης. Το παράδειγμα στο οποίο επιμένει: ```perl /-?[0-9]*\.?[0-9]*/ ``` Διαβασμένο ως αγγλικά: «προαιρετικό πρόσημο, προαιρετικά ψηφία, προαιρετική υποδιαστολή, προαιρετικά ψηφία». Διαβασμένο ως κώδικας: κάθε τμήμα είναι προαιρετικό, οπότε το μοτίβο *ταιριάζει με την κενή συμβολοσειρά* — στην αρχή οποιασδήποτε εισόδου, προτού καν κοιτάξει η μηχανή. Εφαρμόστε το στο «nothing here» και ταιριάζει στη θέση 0, συλλαμβάνοντας την κενή συμβολοσειρά, επιστρέφοντας επιτυχία. Η διόρθωση είναι να απαιτήσετε τουλάχιστον ένα ψηφίο σε τουλάχιστον μία πλευρά της υποδιαστολής: ```perl /-?[0-9]+(\.[0-9]*)?|-?\.[0-9]+/ ``` Δύο εναλλακτικές, κάθε μία απαιτεί τουλάχιστον ένα ψηφίο. Το μοτίβο τώρα ταιριάζει με αυτό που σκόπευε ο συγγραφέας του. Το μάθημα γενικεύεται. Ένα μοτίβο που *μπορεί* να ταιριάξει με την κενή συμβολοσειρά συνήθως *θα* ταιριάξει με την κενή συμβολοσειρά κάπου. Αν η αντιστοιχία σας πρέπει να σημαίνει κάτι, γράψτε απαιτήσεις που την αναγκάζουν να σημαίνει κάτι. ## Αντικατάσταση με μια ματιά Η αντικατάσταση κειμένου χρησιμοποιεί τον τελεστή `s///`, ο οποίος δέχεται ένα μοτίβο και μια συμβολοσειρά αντικατάστασης: ```perl my $x = "feed the cat"; $x =~ s/cat/dog/; # $x is now "feed the dog" ``` Η αντικατάσταση καλύπτεται σε βάθος στο δικό της κεφάλαιο· αναφέρεται εδώ ώστε να μπορείτε να τη συνδυάσετε με τα παραπάνω δεδομένα. Σχεδόν ό,τι ισχύει για τα μοτίβα `m//` ισχύει και μέσα στα μοτίβα `s///`. ## Πού να πάτε στη συνέχεια Οι κυριολεκτικές αντιστοιχίες σάς πάνε εκπληκτικά μακριά, αλλά κάθε πραγματική regex χρησιμοποιεί κλάσεις χαρακτήρων, άγκυρες, ή ποσοδείκτες. Οι κλάσεις χαρακτήρων ακολουθούν — επιτρέπουν σε μία θέση στο μοτίβο να δέχεται οποιονδήποτε από αρκετούς χαρακτήρες. Αν διαβάζετε τον οδηγό για μια συγκεκριμένη ερώτηση, τα κεφάλαια είναι ανεξάρτητα και ο [δείκτης](index.md) τα παραθέτει όλα. Μοτίβα που διαβάζονται μια χαρά αλλά τρέχουν για ώρες καλύπτονται στο [performance](performance.md) — όταν αμφιβάλλετε, η απάντηση συνήθως βρίσκεται εκεί. ## Δείτε επίσης - [`m`](../../p5/core/perlfunc/m.md) — πλήρης αναφορά για τον τελεστή αντιστοίχισης. - [`s`](../../p5/core/perlfunc/s.md) — πλήρης αναφορά για την αντικατάσταση. - [`qr`](../../p5/core/perlfunc/qr.md) — μεταγλώττιση αντικειμένου μοτίβου. - [`quotemeta`](../../p5/core/perlfunc/quotemeta.md) — διαφυγή συμβολοσειράς για ασφαλή παρεμβολή σε μοτίβο. - Το κεφάλαιο [character classes](character-classes.md) — τι ακολουθεί μετά την κυριολεκτική αντιστοίχιση. - Το κεφάλαιο [performance](performance.md) — τι μπορεί να πάει στραβά.