# מחלקות תווים
מחלקת תווים מתאימה בדיוק לתו אחד, הנבחר מתוך קבוצה שמגדירים. בעוד `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) — הידור תבנית לשימוש חוזר.