Εργασία με συμβολοσειρές

Η Nette\Utils\Strings είναι μια στατική κλάση με χρήσιμες συναρτήσεις για την εργασία με συμβολοσειρές κυρίως στην κωδικοποίηση UTF-8.

Εγκατάσταση:

composer require nette/utils

Όλα τα παραδείγματα προϋποθέτουν ότι έχει δημιουργηθεί ένα ψευδώνυμο:

use Nette\Utils\Strings;

Αλλαγή πεζών-κεφαλαίων

Αυτές οι συναρτήσεις απαιτούν την επέκταση PHP mbstring.

lower (string $s): string

Μετατρέπει μια συμβολοσειρά UTF-8 σε πεζά γράμματα.

Strings::lower('Dobrý den'); // 'dobrý den'

upper (string $s): string

Μετατρέπει μια συμβολοσειρά UTF-8 σε κεφαλαία γράμματα.

Strings::upper('Dobrý den'); // 'DOBRÝ DEN'

firstUpper (string $s): string

Μετατρέπει το πρώτο γράμμα μιας συμβολοσειράς UTF-8 σε κεφαλαίο, τα υπόλοιπα παραμένουν αμετάβλητα.

Strings::firstUpper('dobrý den'); // 'Dobrý den'

firstLower (string $s): string

Μετατρέπει το πρώτο γράμμα μιας συμβολοσειράς UTF-8 σε πεζό, τα υπόλοιπα παραμένουν αμετάβλητα.

Strings::firstLower('Dobrý den'); // 'dobrý den'

capitalize (string $s): string

Μετατρέπει το πρώτο γράμμα κάθε λέξης σε μια συμβολοσειρά UTF-8 σε κεφαλαίο, τα υπόλοιπα σε πεζά.

Strings::capitalize('Dobrý den'); // 'Dobrý Den'

Τροποποίηση συμβολοσειράς

normalize (string $s): string

Αφαιρεί τους χαρακτήρες ελέγχου, κανονικοποιεί τις αλλαγές γραμμής σε \n, περικόπτει τις αρχικές και τελικές κενές γραμμές, περικόπτει τα δεξιά κενά στις γραμμές, κανονικοποιεί το UTF-8 στην κανονική μορφή NFC.

unixNewLines (string $s): string

Μετατρέπει τις αλλαγές γραμμής σε \n που χρησιμοποιούνται σε συστήματα unix. Οι αλλαγές γραμμής είναι: \n, \r, \r\n, U+2028 διαχωριστής γραμμής, U+2029 διαχωριστής παραγράφου.

$unixLikeLines = Strings::unixNewLines($string);

platformNewLines (string $s)string

Μετατρέπει τις αλλαγές γραμμής στους χαρακτήρες που είναι συγκεκριμένοι για την τρέχουσα πλατφόρμα, δηλαδή \r\n στα Windows και \n αλλού. Οι αλλαγές γραμμής είναι: \n, \r, \r\n, U+2028 διαχωριστής γραμμής, U+2029 διαχωριστής παραγράφου.

$platformLines = Strings::platformNewLines($string);

webalize (string $s, ?string $charlist=null, bool $lower=true)string

Τροποποιεί μια συμβολοσειρά UTF-8 στη μορφή που χρησιμοποιείται στα URL, δηλαδή αφαιρεί τα διακριτικά και αντικαθιστά όλους τους χαρακτήρες, εκτός από τα γράμματα του αγγλικού αλφαβήτου και τους αριθμούς, με παύλες.

Strings::webalize('náš produkt'); // 'nas-produkt'

Εάν πρέπει να διατηρηθούν και άλλοι χαρακτήρες, μπορούν να καθοριστούν στη δεύτερη παράμετρο της συνάρτησης.

Strings::webalize('10. obrázek_id', '._'); // '10.-obrazek_id'

Με την τρίτη παράμετρο, μπορεί να καταργηθεί η μετατροπή σε πεζά γράμματα.

Strings::webalize('Dobrý den', null, false); // 'Dobry-den'

Απαιτεί την επέκταση PHP intl.

trim (string $s, ?string $charlist=null)string

Περικόπτει τα κενά (ή άλλους χαρακτήρες που καθορίζονται από τη δεύτερη παράμετρο) από την αρχή και το τέλος μιας συμβολοσειράς UTF-8.

Strings::trim('  Hello  '); // 'Hello'

truncate (string $s, int $maxLen, string $append=`'…'`)string

Περικόπτει μια συμβολοσειρά UTF-8 στο καθορισμένο μέγιστο μήκος, προσπαθώντας να διατηρήσει ολόκληρες λέξεις. Εάν η συμβολοσειρά συντομευτεί, προσθέτει αποσιωπητικά στο τέλος (μπορεί να αλλάξει με την τρίτη παράμετρο).

$text = 'Řekněte, jak se máte?';
Strings::truncate($text, 5);       // 'Řekn…'
Strings::truncate($text, 20);      // 'Řekněte, jak se…'
Strings::truncate($text, 30);      // 'Řekněte, jak se máte?'
Strings::truncate($text, 20, '~'); // 'Řekněte, jak se~'

indent (string $s, int $level=1, string $indentationChar=`"\t"`)string

Δημιουργεί εσοχή σε ένα κείμενο πολλαπλών γραμμών από τα αριστερά. Ο αριθμός των εσοχών καθορίζεται από τη δεύτερη παράμετρο, ο χαρακτήρας εσοχής από την τρίτη παράμετρο (η προεπιλεγμένη τιμή είναι tab).

Strings::indent('Nette');         // "\tNette"
Strings::indent('Nette', 2, '+'); // '++Nette'

padLeft (string $s, int $length, string $pad=`' '`)string

Συμπληρώνει μια συμβολοσειρά UTF-8 στο καθορισμένο μήκος επαναλαμβάνοντας τη συμβολοσειρά $pad από τα αριστερά.

Strings::padLeft('Nette', 6);        // ' Nette'
Strings::padLeft('Nette', 8, '+*');  // '+*+Nette'

padRight (string $s, int $length, string $pad=`' '`)string

Συμπληρώνει μια συμβολοσειρά UTF-8 στο καθορισμένο μήκος επαναλαμβάνοντας τη συμβολοσειρά $pad από τα δεξιά.

Strings::padRight('Nette', 6);       // 'Nette '
Strings::padRight('Nette', 8, '+*'); // 'Nette+*+'

substring (string $s, int $start, ?int $length=null)string

Επιστρέφει ένα τμήμα της συμβολοσειράς UTF-8 $s που καθορίζεται από τη θέση έναρξης $start και το μήκος $length. Εάν το $start είναι αρνητικό, η επιστρεφόμενη συμβολοσειρά θα ξεκινά από τον χαρακτήρα -$start από το τέλος.

Strings::substring('Nette Framework', 0, 5); // 'Nette'
Strings::substring('Nette Framework', 6);    // 'Framework'
Strings::substring('Nette Framework', -4);   // 'work'

reverse (string $s): string

Αντιστρέφει μια συμβολοσειρά UTF-8.

Strings::reverse('Nette'); // 'etteN'

length (string $s): int

Επιστρέφει τον αριθμό των χαρακτήρων (όχι των bytes) σε μια συμβολοσειρά UTF-8.

Αυτός είναι ο αριθμός των κωδικών σημείων Unicode, ο οποίος μπορεί να διαφέρει από τον αριθμό των γραφημάτων.

Strings::length('Nette');   // 5
Strings::length('červená'); // 7

startsWith (string $haystack, string $needle)bool

Ελέγχει εάν η συμβολοσειρά $haystack ξεκινά με τη συμβολοσειρά $needle.

$haystack = 'Začíná';
$needle = 'Za';
Strings::startsWith($haystack, $needle); // true

Χρησιμοποιήστε την εγγενή str_starts_with().

endsWith (string $haystack, string $needle)bool

Ελέγχει εάν η συμβολοσειρά $haystack τελειώνει με τη συμβολοσειρά $needle.

$haystack = 'Končí';
$needle = 'čí';
Strings::endsWith($haystack, $needle); // true

Χρησιμοποιήστε την εγγενή str_ends_with().

contains (string $haystack, string $needle)bool

Ελέγχει εάν η συμβολοσειρά $haystack περιέχει τη $needle.

$haystack = 'Posluchárna';
$needle = 'sluch';
Strings::contains($haystack, $needle); // true

Χρησιμοποιήστε την εγγενή str_contains().

compare (string $left, string $right, ?int $length=null)bool

Σύγκριση δύο συμβολοσειρών UTF-8 ή τμημάτων τους χωρίς διάκριση πεζών-κεφαλαίων. Εάν το $length περιέχει null, συγκρίνονται ολόκληρες οι συμβολοσειρές, εάν είναι αρνητικό, συγκρίνεται ο αντίστοιχος αριθμός χαρακτήρων από το τέλος των συμβολοσειρών, διαφορετικά συγκρίνεται ο αντίστοιχος αριθμός χαρακτήρων από την αρχή.

Strings::compare('Nette', 'nette');     // true
Strings::compare('Nette', 'next', 2);   // true - αντιστοιχία των πρώτων 2 χαρακτήρων
Strings::compare('Nette', 'Latte', -2); // true - αντιστοιχία των τελευταίων 2 χαρακτήρων

findPrefix (…$strings): string

Βρίσκει την κοινή αρχή των συμβολοσειρών. Ή επιστρέφει μια κενή συμβολοσειρά εάν δεν βρέθηκε κοινό πρόθεμα.

Strings::findPrefix('prefix-a', 'prefix-bb', 'prefix-c');   // 'prefix-'
Strings::findPrefix(['prefix-a', 'prefix-bb', 'prefix-c']); // 'prefix-'
Strings::findPrefix('Nette', 'is', 'great');                // ''

before (string $haystack, string $needle, int $nth=1): ?string

Επιστρέφει το τμήμα της συμβολοσειράς $haystack πριν από την n-οστή $nth εμφάνιση της συμβολοσειράς $needle. Ή null, εάν η $needle δεν βρέθηκε. Με αρνητική τιμή $nth, η αναζήτηση γίνεται από το τέλος της συμβολοσειράς.

Strings::before('Nette_is_great', '_', 1);  // 'Nette'
Strings::before('Nette_is_great', '_', -2); // 'Nette'
Strings::before('Nette_is_great', ' ');     // null
Strings::before('Nette_is_great', '_', 3);  // null

after (string $haystack, string $needle, int $nth=1): ?string

Επιστρέφει το τμήμα της συμβολοσειράς $haystack μετά την n-οστή $nth εμφάνιση της συμβολοσειράς $needle. Ή null, εάν η $needle δεν βρέθηκε. Με αρνητική τιμή $nth, η αναζήτηση γίνεται από το τέλος της συμβολοσειράς.

Strings::after('Nette_is_great', '_', 2);  // 'great'
Strings::after('Nette_is_great', '_', -1); // 'great'
Strings::after('Nette_is_great', ' ');     // null
Strings::after('Nette_is_great', '_', 3);  // null

indexOf (string $haystack, string $needle, int $nth=1)?int

Επιστρέφει τη θέση σε χαρακτήρες της n-οστής $nth εμφάνισης της συμβολοσειράς $needle στη συμβολοσειρά $haystack. Ή null, εάν η $needle δεν βρέθηκε. Με αρνητική τιμή $nth, η αναζήτηση γίνεται από το τέλος της συμβολοσειράς.

Strings::indexOf('abc abc abc', 'abc', 2);  // 4
Strings::indexOf('abc abc abc', 'abc', -1); // 8
Strings::indexOf('abc abc abc', 'd');       // null

Κωδικοποίηση

fixEncoding (string $s): string

Αφαιρεί τους μη έγκυρους χαρακτήρες UTF-8 από τη συμβολοσειρά.

$correctStrings = Strings::fixEncoding($string);

checkEncoding (string $s)bool

Ελέγχει εάν πρόκειται για έγκυρη συμβολοσειρά UTF-8.

$isUtf8 = Strings::checkEncoding($string);

Χρησιμοποιήστε το Nette\Utils\Validator::isUnicode().

toAscii (string $s): string

Μετατρέπει μια συμβολοσειρά UTF-8 σε ASCII, δηλαδή αφαιρεί τα διακριτικά κ.λπ.

Strings::toAscii('žluťoučký kůň'); // 'zlutoucky kun'

Απαιτεί την επέκταση PHP intl.

chr (int $code): string

Επιστρέφει έναν συγκεκριμένο χαρακτήρα σε UTF-8 από το κωδικό σημείο (αριθμός στην περιοχή 0×0000..D7FF και 0xE000..10FFFF).

Strings::chr(0xA9); // '©' στην κωδικοποίηση UTF-8

ord (string $char): int

Επιστρέφει το κωδικό σημείο ενός συγκεκριμένου χαρακτήρα σε UTF-8 (αριθμός στην περιοχή 0×0000..D7FF ή 0xE000..10FFFF).

Strings::ord('©'); // 0xA9

Κανονικές εκφράσεις

Η κλάση Strings προσφέρει συναρτήσεις για την εργασία με κανονικές εκφράσεις. Σε αντίθεση με τις εγγενείς συναρτήσεις της PHP, διαθέτουν πιο κατανοητό API, καλύτερη υποστήριξη Unicode και κυρίως ανίχνευση σφαλμάτων. Οποιοδήποτε σφάλμα κατά τη μεταγλώττιση ή την επεξεργασία της έκφρασης δημιουργεί μια εξαίρεση Nette\RegexpException.

split (string $subject, string $pattern, bool $captureOffset=false, bool $skipEmpty=false, int $limit=-1, bool $utf8=false)array

Διαιρεί μια συμβολοσειρά σε έναν πίνακα σύμφωνα με μια κανονική έκφραση. Οι εκφράσεις σε παρενθέσεις θα συλληφθούν και θα επιστραφούν επίσης.

Strings::split('hello, world', '~,\s*~');
// ['hello', 'world']

Strings::split('hello, world', '~(,)\s*~');
// ['hello', ',', 'world']``

Εάν το $skipEmpty είναι true, θα επιστραφούν μόνο τα μη κενά στοιχεία:

Strings::split('hello, world, ', '~,\s*~');
// ['hello', 'world', '']

Strings::split('hello, world, ', '~,\s*~', skipEmpty: true);
// ['hello', 'world']

Εάν καθοριστεί το $limit, θα επιστραφούν μόνο οι υποσυμβολοσειρές μέχρι το όριο και η υπόλοιπη συμβολοσειρά θα τοποθετηθεί στο τελευταίο στοιχείο. Ένα όριο –1 ή 0 σημαίνει κανένας περιορισμός.

Strings::split('hello, world, third', '~,\s*~', limit: 2);
// ['hello', 'world, third']

Εάν το $utf8 είναι true, η αξιολόγηση μεταβαίνει σε λειτουργία Unicode. Παρόμοια με όταν καθορίζετε τον τροποποιητή u.

Εάν το $captureOffset είναι true, για κάθε εμφάνιση αντιστοιχίας θα επιστραφεί επίσης η θέση της στη συμβολοσειρά (σε bytes, εάν έχει οριστεί το $utf8 τότε σε χαρακτήρες). Αυτό αλλάζει την τιμή επιστροφής σε έναν πίνακα όπου κάθε στοιχείο είναι ένα ζεύγος που αποτελείται από την αντιστοιχισμένη συμβολοσειρά και τη θέση της.

Strings::split('žlutý, kůň', '~,\s*~', captureOffset: true);
// [['žlutý', 0], ['kůň', 9]]

Strings::split('žlutý, kůň', '~,\s*~', captureOffset: true, utf8: true);
// [['žlutý', 0], ['kůň', 7]]

match (string $subject, string $pattern, bool $captureOffset=false, int $offset=0, bool $unmatchedAsNull=false, bool $utf8=false)?array

Αναζητά στη συμβολοσειρά ένα τμήμα που αντιστοιχεί στην κανονική έκφραση και επιστρέφει έναν πίνακα με την αντιστοιχισμένη έκφραση και τις επιμέρους υποεκφράσεις, ή null.

Strings::match('hello!', '~\w+(!+)~');
// ['hello!', '!']

Strings::match('hello!', '~X~');
// null

Εάν το $unmatchedAsNull είναι true, οι μη συλληφθείσες υπο-αντιστοιχίες επιστρέφονται ως null, διαφορετικά επιστρέφονται ως κενή συμβολοσειρά ή δεν επιστρέφονται:

Strings::match('hello', '~\w+(!+)?~');
// ['hello']

Strings::match('hello', '~\w+(!+)?~', unmatchedAsNull: true);
// ['hello', null]

Εάν το $utf8 είναι true, η αξιολόγηση μεταβαίνει σε λειτουργία Unicode. Παρόμοια με όταν καθορίζετε τον τροποποιητή u:

Strings::match('žlutý kůň', '~\w+~');
// ['lut']

Strings::match('žlutý kůň', '~\w+~', utf8: true);
// ['žlutý']

Η παράμετρος $offset μπορεί να χρησιμοποιηθεί για τον καθορισμό της θέσης από την οποία θα ξεκινήσει η αναζήτηση (σε bytes, εάν έχει οριστεί το $utf8 τότε σε χαρακτήρες).

Εάν το $captureOffset είναι true, για κάθε εμφάνιση αντιστοιχίας θα επιστραφεί επίσης η θέση της στη συμβολοσειρά (σε bytes, εάν έχει οριστεί το $utf8 τότε σε χαρακτήρες). Αυτό αλλάζει την τιμή επιστροφής σε έναν πίνακα όπου κάθε στοιχείο είναι ένα ζεύγος που αποτελείται από την αντιστοιχισμένη συμβολοσειρά και τη μετατόπισή της:

Strings::match('žlutý!', '~\w+(!+)?~', captureOffset: true);
// [['lut', 2]]

Strings::match('žlutý!', '~\w+(!+)?~', captureOffset: true, utf8: true);
// [['žlutý!', 0], ['!', 5]]

matchAll (string $subject, string $pattern, bool $captureOffset=false, int $offset=0, bool $unmatchedAsNull=false, bool $patternOrder=false, bool $utf8=false, bool $lazy=false): array|Generator

Αναζητά στη συμβολοσειρά όλες τις εμφανίσεις που αντιστοιχούν στην κανονική έκφραση και επιστρέφει έναν πίνακα πινάκων με την αντιστοιχισμένη έκφραση και τις επιμέρους υποεκφράσεις.

Strings::matchAll('hello, world!!', '~\w+(!+)?~');
/* [
	0 => ['hello'],
	1 => ['world!!', '!!'],
] */

Εάν το $patternOrder είναι true, η δομή των αποτελεσμάτων αλλάζει έτσι ώστε το πρώτο στοιχείο να είναι ένας πίνακας πλήρων αντιστοιχίσεων του μοτίβου, το δεύτερο να είναι ένας πίνακας συμβολοσειρών που αντιστοιχούν στην πρώτη υπο-αντιστοιχία σε παρένθεση, και ούτω καθεξής:

Strings::matchAll('hello, world!!', '~\w+(!+)?~', patternOrder: true);
/* [
	0 => ['hello', 'world!!'],
	1 => ['', '!!'],
] */

Εάν το $unmatchedAsNull είναι true, οι μη συλληφθείσες υπο-αντιστοιχίες επιστρέφονται ως null, διαφορετικά επιστρέφονται ως κενή συμβολοσειρά ή δεν επιστρέφονται:

Strings::matchAll('hello, world!!', '~\w+(!+)?~', unmatchedAsNull: true);
/* [
	0 => ['hello', null],
	1 => ['world!!', '!!'],
] */

Εάν το $utf8 είναι true, η αξιολόγηση μεταβαίνει σε λειτουργία Unicode. Παρόμοια με όταν καθορίζετε τον τροποποιητή u:

Strings::matchAll('žlutý kůň', '~\w+~');
/* [
	0 => ['lut'],
	1 => ['k'],
] */

Strings::matchAll('žlutý kůň', '~\w+~', utf8: true);
/* [
	0 => ['žlutý'],
	1 => ['kůň'],
] */

Η παράμετρος $offset μπορεί να χρησιμοποιηθεί για τον καθορισμό της θέσης από την οποία θα ξεκινήσει η αναζήτηση (σε bytes, εάν έχει οριστεί το $utf8 τότε σε χαρακτήρες).

Εάν το $captureOffset είναι true, για κάθε εμφάνιση αντιστοιχίας θα επιστραφεί επίσης η θέση της στη συμβολοσειρά (σε bytes, εάν έχει οριστεί το $utf8 τότε σε χαρακτήρες). Αυτό αλλάζει την τιμή επιστροφής σε έναν πίνακα όπου κάθε στοιχείο είναι ένα ζεύγος που αποτελείται από την αντιστοιχισμένη συμβολοσειρά και τη θέση της:

Strings::matchAll('žlutý kůň', '~\w+~', captureOffset: true);
/* [
	0 => [['lut', 2]],
	1 => [['k', 8]],
] */

Strings::matchAll('žlutý kůň', '~\w+~', captureOffset: true, utf8: true);
/* [
	0 => [['žlutý', 0]],
	1 => [['kůň', 6]],
] */

Εάν το $lazy είναι true, η συνάρτηση επιστρέφει έναν Generator αντί για έναν πίνακα, πράγμα που προσφέρει σημαντικά πλεονεκτήματα απόδοσης κατά την εργασία με μεγάλες συμβολοσειρές. Ο γεννήτορας επιτρέπει την αναζήτηση αντιστοιχίσεων σταδιακά, αντί για ολόκληρη τη συμβολοσειρά ταυτόχρονα. Αυτό επιτρέπει την αποδοτική εργασία ακόμη και με εξαιρετικά μεγάλα κείμενα εισόδου. Επιπλέον, μπορείτε να διακόψετε την επεξεργασία ανά πάσα στιγμή εάν βρείτε την αντιστοιχία που αναζητάτε, εξοικονομώντας έτσι υπολογιστικό χρόνο.

$matches = Strings::matchAll($largeText, '~\w+~', lazy: true);
foreach ($matches as $match) {
    echo "Βρέθηκε: $match[0]\n";
    // Η επεξεργασία μπορεί να διακοπεί ανά πάσα στιγμή
}

replace (string $subject, string|array $pattern, string|callable $replacement='', int $limit=-1, bool $captureOffset=false, bool $unmatchedAsNull=false, bool $utf8=false)string

Αντικαθιστά όλες τις εμφανίσεις που αντιστοιχούν στην κανονική έκφραση. Το $replacement είναι είτε μια μάσκα συμβολοσειράς αντικατάστασης είτε ένα callback.

Strings::replace('hello, world!', '~\w+~', '--');
// '--, --!'

Strings::replace('hello, world!', '~\w+~', fn($m) => strrev($m[0]));
// 'olleh, dlrow!'

Η συνάρτηση επιτρέπει επίσης την εκτέλεση πολλαπλών αντικαταστάσεων περνώντας έναν πίνακα στη δεύτερη παράμετρο με τη μορφή pattern => replacement:

Strings::replace('hello, world!', [
	'~\w+~' => '--',
	'~,\s+~' => ' ',
]);
// '-- --!'

Η παράμετρος $limit περιορίζει τον αριθμό των αντικαταστάσεων που εκτελούνται. Ένα όριο –1 σημαίνει κανένας περιορισμός.

Εάν το $utf8 είναι true, η αξιολόγηση μεταβαίνει σε λειτουργία Unicode. Παρόμοια με όταν καθορίζετε τον τροποποιητή u.

Strings::replace('žlutý kůň', '~\w+~', '--');
// 'ž--ý --ůň'

Strings::replace('žlutý kůň', '~\w+~', '--', utf8: true);
// '-- --'

Εάν το $captureOffset είναι true, για κάθε εμφάνιση αντιστοιχίας θα περάσει στο callback επίσης η θέση της στη συμβολοσειρά (σε bytes, εάν έχει οριστεί το $utf8 τότε σε χαρακτήρες). Αυτό αλλάζει τη μορφή του περασμένου πίνακα, όπου κάθε στοιχείο είναι ένα ζεύγος που αποτελείται από την αντιστοιχισμένη συμβολοσειρά και τη θέση της.

Strings::replace(
	'žlutý kůň',
	'~\w+~',
	function (array $m) { dump($m); return ''; },
	captureOffset: true,
);
// dumps [['lut', 2]] και [['k', 8]]

Strings::replace(
	'žlutý kůň',
	'~\w+~',
	function (array $m) { dump($m); return ''; },
	captureOffset: true,
	utf8: true,
);
// dumps [['žlutý', 0]] και [['kůň', 6]]

Εάν το $unmatchedAsNull είναι true, οι μη συλληφθείσες υπο-αντιστοιχίες περνούν στο callback ως null, διαφορετικά περνούν ως κενή συμβολοσειρά ή δεν περνούν:

Strings::replace(
	'ac',
	'~(a)(b)*(c)~',
	function (array $m) { dump($m); return ''; },
);
// dumps ['ac', 'a', '', 'c']

Strings::replace(
	'ac',
	'~(a)(b)*(c)~',
	function (array $m) { dump($m); return ''; },
	unmatchedAsNull: true,
);
// dumps ['ac', 'a', null, 'c']
έκδοση: 4.0