# מחלקות תווים מחלקת תווים מתאימה בדיוק לתו אחד, הנבחר מתוך קבוצה שמגדירים. בעוד `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 ``` ## שלילה סימן ה־caret `^` כתו הראשון בתוך `[…]` הופך את המחלקה לשלילה: ```perl /[^a]/; # any character except 'a' /[^0-9]/; # any non-digit ``` caret במקום אחר הוא מילולי: ```perl /[a^]/; # matches 'a' or '^' ``` מחלקה שלילית עדיין מתאימה ל *תו* אחד — `[^a]` אינו מתאים למחרוזת הריקה; הוא דורש תו אחד שאינו `a`. ## תווים מיוחדים בתוך מחלקה בתוך `[…]` קבוצת התווים המיוחדים מצטמצמת ל־`- ] \ ^ $` (ולמתחם התבנית). האחרים — `.`, `*`, `+`, `?`, `(`, `)`, `{`, `}`, `|` — הם מילוליים במחלקה: ```perl /[.+*]/; # matches a literal '.', '+', or '*' /[()]/; # matches '(' or ')' ``` כדי להתאים `]` בתוך המחלקה, יש לבצע לו escape או להציבו ראשון (לאחר `^` מוביל אם קיים): ```perl /[\]]/; # matches ']' /[]ab]/; # matches ']', 'a', or 'b' ``` `$` ו־`\` מעט מסורבלים מכיוון שהם מקיימים אינטראקציה עם השיבוץ וה־escape: ```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}` (עם סוגריים מסולסלים) הוא escape לתו 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) ``` חוק דה־מורגן חשוב: `[^\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=]]` — מתאים לכל תו שהוא שקול תחת כללי הסידור של ההגדרה האזורית (למשל וריאנטים מנוקדים של `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 החופפות. בלעדיו, אותם ביטויים היו דורשים lookaround מילולי או לוגיקה מחוץ לתבנית. `(?[…])` הוא בעצמו מחלקת תווים — הוא צורך תו אחד וניתן לכמת אותו: ```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) — הידור תבנית לשימוש חוזר.