# Ομάδες και συλλήψεις Η ομαδοποίηση κάνει δύο πράγματα, τα οποία εύκολα συγχέονται: μετατρέπει μια ακολουθία στοιχείων μοτίβου σε μία μονάδα για ποσοδεικτοποίηση και εναλλαγή, και αποθηκεύει ό,τι ταίριαξε αυτή η μονάδα για μεταγενέστερη χρήση. ```perl /house(cat|keeper)/; # 'house' followed by 'cat' or 'keeper' /(ab){3}/; # 'ababab' /(\d{3})-(\d{4})/; # capture two groups separated by '-' ``` Πέρα από την απλή συλλαμβάνουσα μορφή `(…)`, η Perl παρέχει έναν μικρό ζωολογικό κήπο κατασκευών σε παρενθέσεις: μη συλλαμβάνουσες ομάδες για καθαρή ομαδοποίηση, ονομαστικές συλλήψεις για αυτο-τεκμηριωμένα μοτίβα, ατομικές ομάδες για έλεγχο της οπισθοχώρησης, αναδρομικά υπομοτίβα για εμφωλευμένες δομές, υπό συνθήκη μοτίβα για διακλάδωση με βάση προηγούμενες συλλήψεις, και την κατασκευή επαναφοράς διακλάδωσης για παράλληλες εναλλακτικές. Αυτό το κεφάλαιο τις καλύπτει όλες. ## Συλλαμβάνουσες ομάδες: `$1`, `$2`, … Κάθε ζεύγος μη διαφεμένων παρενθέσεων σε ένα μοτίβο ανοίγει μια συλλαμβάνουσα ομάδα. Μετά από μια επιτυχημένη αντιστοίχιση, το ταιριασμένο κείμενο της n-οστής ομάδας βρίσκεται στο `$n`: ```perl if ($time =~ /(\d\d):(\d\d):(\d\d)/) { my ($hours, $minutes, $seconds) = ($1, $2, $3); } ``` Σε περιβάλλον λίστας, μια αντιστοίχιση επιστρέφει απευθείας τη λίστα των συλληφθεισών συμβολοσειρών: ```perl my ($h, $m, $s) = $time =~ /(\d\d):(\d\d):(\d\d)/; ``` Αν το μοτίβο αποτύχει, η λίστα είναι κενή — ένας χρήσιμος ιδιωματισμός για «ανάλυσε ή παραιτήσου»: ```perl my ($h, $m, $s) = $time =~ /(\d\d):(\d\d):(\d\d)/ or die "not a time: $time"; ``` Δεν υπάρχει άνω όριο στο πλήθος των ομάδων σύλληψης. Οι ομάδες αριθμούνται με την πιο αριστερή ανοιχτή παρένθεση ως ομάδα 1, την επόμενη ως ομάδα 2, κ.ο.κ.: ```default /(ab(cd|ef)((gi)|j))/ 1 2 34 ``` Το `$1` συλλαμβάνει την εξωτερική ομάδα, το `$2` την πρώτη εσωτερική, το `$3` την επόμενη, το `$4` την πιο εσωτερική. ### Συνέλαβε την κενή συμβολοσειρά έναντι δεν ταίριαξε καθόλου Μια ομάδα σύλληψης που δεν συμμετείχε στην αντιστοίχιση έχει το `$n` *απροσδιόριστο*. Μια ομάδα που συμμετείχε και ταίριαξε με κενή συμβολοσειρά έχει το `$n` ορισμένο και ίσο με `""`. Η διάκριση έχει σημασία: ```perl "aba" =~ / a (x)* b \g1 a /x; # does NOT match "aba" =~ / a (x)? b \g1 a /x; # does NOT match "aba" =~ / a (x*) b \g1 a /x; # matches; $1 = "" "aba" =~ / a (x?) b \g1 a /x; # matches; $1 = "" ``` Στις δύο πρώτες περιπτώσεις, ο ποσοδείκτης είναι *εκτός* της ομάδας, οπότε η ίδια η ομάδα ποτέ δεν έκλεισε (η μηχανή ταίριαξε μηδέν επαναλήψεις — η ομάδα δεν εισήλθε καθόλου). Η οπισθαναφορά `\g1` επομένως δεν έχει τιμή για σύγκριση και αποτυγχάνει. Στις δύο δεύτερες περιπτώσεις, ο ποσοδείκτης είναι *μέσα* στην ομάδα, οπότε η ομάδα έτρεξε ακριβώς μία φορά και συνέλαβε μια κενή συμβολοσειρά· το `\g1` ταιριάζει με την ίδια κενή συμβολοσειρά σε εκείνη τη θέση. Το μάθημα: όταν μια ομάδα είναι προαιρετική, βάλτε τον ποσοδείκτη μέσα αν θέλετε τη σημασιολογία «η κενή αντιστοιχία μετράει ως αντιστοιχία». Ελέγχετε πάντα τις συλλήψεις με `defined`, όχι για αλήθεια — μια κενή σύλληψη είναι αληθής-αλλά-κενή υπό τη σημασιολογία συμβολοσειρών: ```perl if ("x" =~ /(a)?(x)/) { print "1 is $1\n" if defined $1; # $1 is undef here print "2 is $2\n" if defined $2; } ``` ### Οι αποτυχημένες αντιστοιχίσεις δεν επαναφέρουν τις μεταβλητές σύλληψης Αν μια αντιστοίχιση αποτύχει, τα `$1`, `$2`, … διατηρούν τις προηγούμενες τιμές τους από την τελευταία *επιτυχημένη* αντιστοίχιση στην ίδια εμβέλεια. Αυτό είναι χαρακτηριστικό: σας επιτρέπει να γράψετε μια σειρά από πιο εξειδικευμένα μοτίβα και να αναφερθείτε στις συλλήψεις της καλύτερης αντιστοιχίας μετά. ```perl "foo" =~ /(\w+)/ and "" =~ /(\d+)/; # second fails print $1; # "foo" — first match's capture survives ``` Είναι επίσης μια συχνή πηγή σύγχυσης. Ελέγχετε πάντα την τιμή επιστροφής της αντιστοίχισης πριν διαβάσετε τις μεταβλητές σύλληψης. ## Μη συλλαμβάνουσες ομάδες: `(?:…)` Αν χρειάζεστε την ομαδοποίηση μόνο για ποσοδεικτοποίηση ή εναλλαγή, και δεν θέλετε τη σύλληψη, χρησιμοποιήστε `(?:…)`: ```perl /(?:ab){3}/; # 'ababab', no capture /(?:\d+\.)*\d+/; # a dotted decimal, no captures at all ``` Οι μη συλλαμβάνουσες ομάδες είναι μικρή νίκη σε ταχύτητα και μεγαλύτερη νίκη σε σαφήνεια. Σηματοδοτούν «αυτή η ομαδοποίηση είναι για σύνταξη, όχι για δεδομένα». Επίσης αποτρέπουν την επαναρίθμηση των συλλαμβανουσών ομάδων που σας ενδιαφέρουν: ```perl # match a number — $1 = whole, $2 = optional exponent value /([+-]?\ *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE]([+-]?\d+))?)/; ``` Χωρίς τα περιτυλίγματα `(?:…)`, τα `$2`, `$3`, `$4` θα ορίζονταν όλα και το επιθυμητό `$2` (ο εκθέτης) θα μετατοπιζόταν στο `$5`. Η μορφή με εμβέλεια `(?flags:…)` (π.χ. `(?i:cat)`, `(?xms:…)`) προσαρτά τροποποιητές μόνο στο εσωτερικό μοτίβο και είναι επίσης μη συλλαμβάνουσα — δείτε το κεφάλαιο [modifiers](modifiers.md). Το `split` επωφελείται επίσης από το `(?:…)`. Το `split /(?:\s+)/` διαχωρίζει σε ακολουθίες λευκών χαρακτήρων χωρίς να εισάγει τους διαχωριστές στην έξοδο· το `split /(\s+)/` τους αφήνει σε εναλλασσόμενες θέσεις. ## Ονομαστικές συλλήψεις Το `(?…)` ή το `(?'name'…)` ονοματίζει μια ομάδα. Η αντιστοιχία της είναι προσβάσιμη μέσω του κατακερματισμού `%+`: ```perl if ("2026-04-23" =~ /(?\d{4})-(?\d{2})-(?\d{2})/) { print "year = $+{year}\n"; # 2026 print "month = $+{month}\n"; # 04 print "day = $+{day}\n"; # 23 } ``` Οι ονομαστικές ομάδες επίσης γεμίζουν τα `$1`, `$2`, … με τη συνηθισμένη σειρά από αριστερά προς τα δεξιά, οπότε κώδικας που χρησιμοποιεί και τις δύο συμβάσεις λειτουργεί. Μέσα στο μοτίβο, αναφερθείτε σε μια ονομαστική ομάδα με `\k` (ή με οποιαδήποτε από τις μορφές αγκίστρων/εισαγωγικών παρακάτω): ```perl /(?["'])(.*?)\k/; # same quote at start and end ``` Τα ονόματα ακολουθούν τους κανόνες αναγνωριστικών της Perl (`[_A-Za-z][_A-Za-z0-9]*`)· δεν μπορούν να ξεκινούν με ψηφίο και δεν μπορούν να περιέχουν παύλες. Αν δύο διακριτές ομάδες μοιράζονται ένα όνομα, το `$+{name}` αναφέρεται στην *πιο αριστερή ορισμένη* ομάδα στην αντιστοίχιση. Αυτό σπάνια το θέλετε *εκτός* μιας επαναφοράς διακλάδωσης (`(?|…)`), όπου τα κοινά ονόματα είναι ιδιωματικά. ### `(?P…)` — συμβατότητα με Python/PCRE Για προγραμματιστές που μεταφέρουν από το άρθρωμα `re` της Python ή το PCRE, η Perl δέχεται τις γραφές τύπου Python: | Μορφή Python | Ισοδύναμο Perl | |-----------------|------------------| | `(?P...)` | `(?...)` | | `(?P=NAME)` | `\k` | | `(?P>NAME)` | `(?&NAME)` | Οι μορφές Python δουλεύουν αλλά δεν είναι ιδιωματική Perl· προτιμήστε τις φυσικές μορφές σε νέο κώδικα. ## Οπισθαναφορές Μια οπισθαναφορά σε ένα μοτίβο απαιτεί μια μεταγενέστερη θέση να ταιριάξει με το *ίδιο κείμενο* που συνέλαβε μια προηγούμενη ομάδα — όχι με το ίδιο μοτίβο, αλλά με τους ίδιους πραγματικούς χαρακτήρες. | Μορφή | Αναφέρεται σε | |--------------|-----------------------------------------------------------------------| | `\1` … `\9` | πρώτη έως ένατη συλλαμβάνουσα ομάδα (παλαιά μορφή) | | `\g1`, `\g2` | αριθμημένη σύλληψη· ισοδύναμο με `\1`, `\2` | | `\g{1}` | μορφή με άγκιστρα· υποχρεωτική όταν διαφορετικά θα ακολουθούσαν ψηφία | | `\g-1` | πιο πρόσφατα ανοιχθείσα συλλαμβάνουσα ομάδα (σχετική) | | `\g{-2}` | δεύτερη πιο πρόσφατα ανοιχθείσα ομάδα | | `\k` | ονομαστική σύλληψη | | `\k'name'` | ίδιο, μορφή με απλά εισαγωγικά | | `\k{name}` | ίδιο, μορφή με άγκιστρα (επιτρέπει περιβάλλοντα διαστήματα) | | `\g{name}` | ονομαστική, εναλλακτική γραφή | Παραδείγματα: ```perl # Match a three-letter word followed by a space and the same word. "the the other day" =~ /\b(\w{3})\s\1\b/; # $1 eq 'the' # Match a four-letter, three-letter, two-letter, or one-letter # run followed by itself. /^(\w{1,4})\1$/; # 'beriberi', 'booboo', 'coco', 'mama', 'papa' ``` ### `\g{…}` έναντι `\1` για αποσαφήνιση Χρησιμοποιείτε `\g{…}` (ή `\k<…>`) όταν ψηφία ή χαρακτήρες που μοιάζουν με οκταδικούς ακολουθούν την αναφορά, για να αποφύγετε την ασάφεια: ```perl /(\d)abc\g{1}23/; # the '1' refers to group 1, '23' is literal /(\d)abc\123/; # '\123' is octal 0x53 ('S'), not group 1 ``` Ο κανόνας της Perl για τη γυμνή μορφή `\N`: τα `\1` έως `\9` σημαίνουν πάντα οπισθαναφορές. Τα `\10`, `\11`, … σημαίνουν οπισθαναφορά *μόνο αν* έχουν ανοίξει τόσες ομάδες σύλληψης νωρίτερα στο μοτίβο· αλλιώς είναι κυριολεκτικοί οκταδικοί χαρακτήρες. Γι” αυτό το `\g{...}` είναι η ασφαλέστερη μορφή όταν το μοτίβο χτίζεται με συνένωση. Αν χρησιμοποιείτε τη μορφή με άγκιστρα, επιτρέπονται προαιρετικά περιβάλλοντα διαστήματα — τα `\g{ -1 }` και `\k{ name }` είναι έγκυρα. ### Σχετικές οπισθαναφορές Τα `\g-1`, `\g{-1}` αναφέρονται στην *αμέσως προηγούμενη* συλλαμβάνουσα ομάδα· το `\g{-2}` αναφέρεται στην προηγούμενη αυτής· κ.ο.κ. Η απόσταση μετράται με *ανοιγμένες* παρενθέσεις, συμπεριλαμβανομένων των μη κλειστών. Αυτό έχει σημασία όταν ένα τμήμα μοτίβου παρεμβάλλεται μέσα σε ένα άλλο: ```perl my $pair = '([a-z])(\d)\g{-1}\g{-2}'; # a11a, g22g, x33x, ... # Embed it: outer group shifts numbering by 1, but relative # backreferences still work: "code=e99e" =~ /^(\w+)=$pair$/; # matches ``` Χωρίς σχετικές οπισθαναφορές, αυτό θα απαιτούσε να ξέρετε πόσες ομάδες προηγούνται του `$pair` σε κάθε σημείο παρεμβολής. Οι ονομαστικές και οι σχετικές αναφορές κάνουν τα μακριά μοτίβα ανθεκτικά στην αντιγραφή-επικόλληση. ## Ατομικές ομάδες: `(?>…)` Το `(?>…)` είναι μια μη συλλαμβάνουσα ομάδα της οποίας τα περιεχόμενα, αφού ταιριάξουν, *δεσμεύονται*. Η μηχανή δεν μπορεί να οπισθοχωρήσει μέσα στην ομάδα σε αποτυχία — μόνο να την προσπεράσει ως σύνολο. ```perl "aaab" =~ /a*ab/; # matches: a* gives back one 'a' "aaab" =~ /(?>a*)ab/; # does not match: a* takes all, refuses to give ``` Η πλήρης ανάλυση βρίσκεται στο κεφάλαιο [performance](performance.md). Η κατασκευή τεκμηριώνεται εδώ επειδή η σύνταξή της είναι μια ομάδα σε παρενθέσεις· δομικά ανήκει στο κεφάλαιο των συλλήψεων δίπλα στο `(?:…)`. Οι κτητικοί ποσοδείκτες (`*+`, `++`, `?+`, `{n,m}+`) είναι ακριβής συντακτική ζάχαρη για `(?>…)` γύρω από το ποσοδεικτημένο άτομο. Τα ακόλουθα είναι ισοδύναμα: | Κτητικός | Μορφή ατομικής ομάδας | |-------------|-------------------------| | `PAT*+` | `(?>PAT*)` | | `PAT++` | `(?>PAT+)` | | `PAT?+` | `(?>PAT?)` | | `PAT{n,m}+` | `(?>PAT{n,m})` | Η γραφή μακράς μορφής `(*atomic:…)` γίνεται επίσης δεκτή. ## Αναδρομικά υπομοτίβα Οι regex της Perl μπορούν να αναφέρονται πίσω σε μια ομάδα σύλληψης σαν να ήταν κλήση υπορουτίνας. Η κατασκευή ξανατρέχει το συλληφθέν μοτίβο στην τρέχουσα θέση. Αυτό κάνει αληθινά αναδρομικές δομές αντιστοιχίσιμες — ισοζυγισμένες παρενθέσεις, S-εκφράσεις, εμφωλευμένες αγκύλες — χωρίς να βγαίνετε από τη DSL της regex. | Μορφή | Καλεί αναδρομικά | |-------------|-----------------------------------------------------| | `(?R)` | ολόκληρο το μοτίβο | | `(?0)` | ίδιο με `(?R)` | | `(?1)` | ομάδα 1 | | `(?2)` | ομάδα 2 (κ.ο.κ.) | | `(?-1)` | πιο πρόσφατα ανοιχθείσα ομάδα (σχετική) | | `(?+1)` | επόμενη ομάδα προς άνοιγμα (σχετική προς τα εμπρός) | | `(?&NAME)` | ονομαστική ομάδα | | `(?P>NAME)` | ίδιο με `(?&NAME)` (συμβατό με Python) | Σημείωση: η σχετική αναδρομή μετράει μη κλειστές ομάδες, σε αντίθεση με τις σχετικές οπισθαναφορές. Το `(?-1)` σημαίνει πάντα την πιο πρόσφατα ανοιχθείσα ομάδα είτε έχει κλείσει είτε όχι. Ένας αντιστοιχιστής ισοζυγισμένων παρενθέσεων: ```perl my $bal = qr/ (?(DEFINE) (? \( # opening paren (?: [^()]++ # non-paren run, possessive | (?&paren) # or a balanced sub-group, recursively )*+ \) # closing paren ) ) (?&paren) /x; "((a)(b(c)))" =~ /^$bal$/; # matches ``` Το μπλοκ `(?(DEFINE)...)` δηλώνει ένα ονομαστικό υπομοτίβο χωρίς το ίδιο να ταιριάζει με τίποτα· το `(?&paren)` μετά από αυτό καλεί εκείνο το υπομοτίβο, και το αναδρομικό `(?&paren)` μέσα στο σώμα είναι αυτό που δίνει το απεριόριστο βάθος. Το `(?R)` δεν θα δούλευε εδώ — καλεί αναδρομικά *ολόκληρο* το περικλείον μοτίβο, συμπεριλαμβανομένων των αγκύρων `^` και `$` που προστίθενται στο σημείο κλήσης, κάτι που αναγκάζει κάθε επίπεδο αναδρομής να απαιτήσει αρχή και τέλος συμβολοσειράς. Ένα πιο λεπτομερές αναδρομικό μοτίβο: ταίριαξε μια συνάρτηση `foo(...)` όπου το όρισμα μπορεί το ίδιο να περιέχει ισοζυγισμένες παρενθέσεις. ```perl my $re = qr/( # group 1: full function call foo ( # group 2: parens with content \( ( # group 3: contents of parens (?: (?> [^()]+ ) # non-paren without backtracking | (?2) # recurse to group 2 )* ) \) ) )/x; 'foo(bar(baz)+baz(bop))' =~ /$re/ and print "1: $1\n2: $2\n3: $3\n"; # 1: foo(bar(baz)+baz(bop)) # 2: (bar(baz)+baz(bop)) # 3: bar(baz)+baz(bop) ``` ### Κατάσταση συλλήψεων μέσα σε αναδρομή Όταν μια ομάδα καλεί αναδρομικά τον εαυτό της, οι συλλήψεις που ορίζονται μέσα στην αναδρομή *δεν* είναι ορατές στον καλούντα αφού επιστρέψει η αναδρομή. Η αναδρομική κλήση έχει τη δική της κατάσταση συλλήψεων, η οποία απορρίπτεται κατά την επιστροφή. Γι” αυτό τα περισσότερα αναδρομικά μοτίβα τυλίγουν μια δευτερεύουσα ομάδα σύλληψης γύρω από την αναδρομική κλήση όταν χρειάζεται το ταιριασμένο κείμενο: ```perl /(?(?&NAME_PAT))(?(?&ADDRESS_PAT)) (?(DEFINE) (?....) (?....) )/x ``` Εδώ το `$+{NAME}` είναι η εξωτερική σύλληψη· το `$+{NAME_PAT}` είναι απροσδιόριστο επειδή ζούσε μόνο μέσα στην αναδρομή. Το ανώτατο όριο βάθους αναδρομής είναι μεταγλωττισμένο στη μηχανή. Μοτίβα που καλούν αναδρομικά χωρίς να καταναλώνουν είσοδο αποτυγχάνουν άμεσα αντί να τρέχουν επ” άπειρον — η μηχανή ανιχνεύει τον κύκλο. ### Μπλοκ `(DEFINE)` Το μπλοκ `(?(DEFINE)…)` περιέχει ονομαστικά υπομοτίβα που ποτέ δεν τρέχουν από μόνα τους — καλούνται μόνο μέσω `(?&NAME)`. Έτσι γράφεται μια regex που μοιάζει με μια μικρή γραμματική: ```perl my $email = qr/ \A (?&LOCAL) @ (?&DOMAIN) \z (?(DEFINE) (? [\w.+-]+ ) (? (?&LABEL) (?: \. (?&LABEL) )+ ) (?