מה זה Regex?
ביטויים רגולריים (regex או regexp) הם רצפי תווים המגדירים דפוסי חיפוש. הם אחד הכלים החזקים ביותר לעיבוד טקסט, זיהוי דפוסים וחילוץ נתונים.
למה להשתמש בביטויים רגולריים?
Regex חיוניים עבור:
- אימות טפסים (אימייל, מספרי טלפון, סיסמאות)
- חילוץ נתונים (ניתוח לוגים, גירוד דפי אינטרנט)
- עיבוד טקסט (חיפוש והחלפה, עיצוב)
- Refactoring קוד (שינוי שמות משתנים, עדכון תחביר)
- חיטוי קלט (אבטחה, מניעת התקפות injection)
איך לקרוא את דף העזר הזה
המדריך מאורגן בסעיפים מתקדמים:
- יסודות - תחביר ודפוסים בסיסיים
- תכונות מתקדמות - Lookaround, קבוצות עם שם, Unicode
- ספציפי לשפה - דוגמאות ב-Python, JavaScript, PHP, C#, Java, Go, Ruby
- Regex ב-VS Code - טרנספורמציות חיפוש/החלפה עם מעל 20 דוגמאות
- דפוסים נפוצים - דפוסי העתק-הדבק לאימייל, URL, תאריכים ועוד
- מקרי שימוש מעשיים - יישומים מהעולם האמיתי
- פתרון בעיות - טעויות נפוצות וטיפים לביצועים
כל סעיף כולל:
- הסברים ברורים
- דוגמאות ויזואליות
- קטעי קוד שאפשר להעתיק
- טיפים מקצועיים ומלכודות
תווים ליטרליים
הregex הפשוט ביותר הוא רצף של תווים ליטרליים:
abc
מתאים ל: "abc" ב"הרצף abc"
רגישות לאותיות גדולות/קטנות
כברירת מחדל, regex רגיש לאותיות גדולות/קטנות:
שלוםמתאים ל"שלום" אבל לא ל"שלום" (אם הוא באות שונה)- השתמש בדגל
iלהתאמה ללא רגישות:/שלום/i
תווים מיוחדים (מטא-תווים)
12 תווים אלה בעלי משמעות מיוחדת ב-regex וחייבים להיות מוחלפים עם \ כדי להתאים ליטרלית:
. ^ $ * + ? { } [ ] \ | ( )
דוגמאות:
\.מתאים לנקודה ליטרלית\$מתאים לסימן דולר\(מתאים לסוגר ליטרלי
| תו | Escape | דוגמה | מתאים ל |
|---|---|---|---|
. (נקודה) |
\. |
3\.14 |
"3.14" |
$ (דולר) |
\$ |
\$100 |
"$100" |
* (כוכבית) |
\* |
a\*b |
"a*b" |
מחלקות תווים
מחלקות תווים מוגדרות מראש
| דפוס | תיאור | שווה ערך | דוגמה | מתאים ל |
|---|---|---|---|---|
\d |
כל ספרה | [0-9] |
\d\d |
"42" |
\D |
כל לא-ספרה | [^0-9] |
\D+ |
"abc" |
\w |
תו מילה | [a-zA-Z0-9_] |
\w+ |
"שלום_123" |
\W |
תו לא-מילה | [^a-zA-Z0-9_] |
\W |
"@", "#" |
\s |
רווח לבן | [ \t\n\r\f\v] |
\s+ |
" " (רווחים) |
\S |
לא-רווח | [^ \t\n\r\f\v] |
\S+ |
"שלום" |
. |
כל תו חוץ משורה חדשה | - | a.c |
"abc", "a1c" |
טיפ מקצועי: \w לא כולל אותיות Unicode כברירת מחדל. השתמש ב-\p{L} לתמיכה ב-Unicode (JavaScript/Python).
מחלקות תווים מותאמות אישית
| דפוס | תיאור | דוגמה | מתאים ל |
|---|---|---|---|
[abc] |
מתאים לכל אחד מ-a, b, או c | [aeiou] |
תנועות: "a", "e", "i", "o", "u" |
[^abc] |
מתאים לכל דבר חוץ מ a, b, או c | [^0-9] |
לא-ספרות |
[a-z] |
טווח: אותיות קטנות | [a-z]+ |
"hello" |
[A-Z] |
טווח: אותיות גדולות | [A-Z]+ |
"HELLO" |
[0-9] |
טווח: ספרות | [0-9]{4} |
"2025" |
[a-zA-Z] |
משולב: כל האותיות | [a-zA-Z0-9] |
אלפאנומרי |
דוגמאות:
[aeiou] → מתאים לכל תנועה
[^aeiou] → מתאים לכל עיצור (לא תנועה)
[a-z0-9] → מתאים לאותיות קטנות וספרות
[a-zA-Z0-9_] → שווה ל-\w (תווי מילה)
כמתים
כמתים מציינים כמה פעמים דפוס צריך להתאים.
כמתים בסיסיים
| דפוס | תיאור | דוגמה | מתאים ל |
|---|---|---|---|
* |
0 או יותר | ab*c |
"ac", "abc", "abbc", "abbbc" |
+ |
1 או יותר | ab+c |
"abc", "abbc" (לא "ac") |
? |
0 או 1 (אופציונלי) | colou?r |
"color", "colour" |
{n} |
בדיוק n פעמים | \d{4} |
"2025" (בדיוק 4 ספרות) |
{n,} |
n או יותר פעמים | \d{2,} |
"42", "123", "9999" |
{n,m} |
בין n ל-m פעמים | \d{2,4} |
"42", "123", "2025" |
כמתים חמדניים לעומת עצלניים
חמדני (ברירת מחדל): מתאים למקסימום האפשרי
<.*> → מתאים: "<div>שלום</div>" (כל המחרוזת)
עצלני (לא-חמדני): מתאים למינימום האפשרי (הוסף ? אחרי הכמת)
<.*?> → מתאים: "<div>" ו-"</div>" בנפרד
| חמדני | עצלני | תיאור |
|---|---|---|
* |
*? |
0 או יותר (עצלני) |
+ |
+? |
1 או יותר (עצלני) |
? |
?? |
0 או 1 (עצלני) |
{n,m} |
{n,m}? |
בין n ל-m (עצלני) |
דוגמה:
טקסט: "שלום" ו-"עולם"
".*"מתאים:"שלום" ו-"עולם"(חמדני)".*?"מתאים:"שלום"ו-"עולם"בנפרד (עצלני)
עוגנים וגבולות
עוגנים מתאימים למיקומים, לא לתווים.
| דפוס | תיאור | דוגמה | מתאים ל |
|---|---|---|---|
^ |
תחילת מחרוזת/שורה | ^שלום |
"שלום עולם" (בהתחלה) |
$ |
סוף מחרוזת/שורה | עולם$ |
"שלום עולם" (בסוף) |
\b |
גבול מילה | \bחתול\b |
"חתול" ב"החתול ישב" (לא "חתולה") |
\B |
לא-גבול מילה | \Bחת |
"חתולה" (חת לא בגבול) |
\A |
תחילת מחרוזת (לא שורה) | \Aשלום |
מתאים רק אם "שלום" ממש בהתחלה |
\z |
סוף מחרוזת (לא שורה) | עולם\z |
מתאים רק אם "עולם" ממש בסוף |
\Z |
סוף מחרוזת (לפני שורה חדשה אחרונה) | עולם\Z |
מתאים ל"עולם" או "עולם\n" |
דוגמאות:
^חתול$ → מתאים: "חתול" (כל השורה היא "חתול")
\bחתול\b → מתאים: "חתול" ב"החתול ישב" (מילה שלמה)
\Bחת → מתאים: "חת" ב"חתולה" (לא בגבול)
מצב מרובה שורות (דגל m):
- בלי
m:^ו-$מתאימים לתחילת/סוף כל המחרוזת - עם
m:^ו-$מתאימים לתחילת/סוף כל שורה
קבוצות וחלופה
קבוצות לכידה
קבוצות לכידה (...) זוכרות את הטקסט המתאים:
(\d+)-(\d+) → מתאים: "123-456"
קבוצה 1: "123"
קבוצה 2: "456"
הפניות אחורה (שימוש חוזר בקבוצות שנלכדו):
(\w)\1 → מתאים: "aa", "bb", "cc" (תו חוזר)
(\w+) \1 → מתאים: "שלום שלום" (מילה חוזרת)
קבוצות ללא-לכידה
השתמש ב-(?:...) כשצריך לקבץ אבל לא צריך ללכוד:
(?:https?://) → מקבץ "http://" או "https://" בלי ללכוד
למה להשתמש בללא-לכידה?
- ביצועים טובים יותר (ללא תקורת זיכרון)
- הפניות אחורה נקיות יותר (קבוצות ממוספרות סופרות רק קבוצות לכידה)
חלופה (OR)
השתמש ב-| ל"מתאים לזה או לזה":
חתול|כלב → מתאים: "חתול" או "כלב"
אפ(ור|ר) → מתאים: "אפור" או "אפר"
דוגמאות:
(מר|גב|ד"ר)\.? → מתאים: "מר.", "גב.", "ד"ר."
https?:// → מתאים: "http://" או "https://"
קביעות Lookaround
Lookaround הן קביעות באורך אפס שמתאימות למיקום (כמו עוגנים) אבל עם תנאים.
Lookahead חיובי (?=...)
מתאים אם הדפוס קדימה מתאים (אבל לא צורך אותו):
\d(?=px) → מתאים: "10" ב"10px" (לא את החלק "px")
מקרה שימוש: אימות סיסמה
^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[@$!%*?&]).{8,}$
פירוק:
(?=.*[A-Z])- חייב להכיל אות גדולה(?=.*[a-z])- חייב להכיל אות קטנה(?=.*\d)- חייב להכיל ספרה(?=.*[@$!%*?&])- חייב להכיל תו מיוחד.{8,}- לפחות 8 תווים
Lookahead שלילי (?!...)
מתאים אם הדפוס קדימה לא מתאים:
\d(?!px) → מתאים: "10" ב"10em" (לא "10px")
מקרה שימוש: אי הכללת מילים מסוימות
\b(?!test)\w+ → מתאים למילים שלא מתחילות ב"test"
Lookbehind חיובי (?<=...)
מתאים אם הדפוס מאחור מתאים:
(?<=₪)\d+ → מתאים: "100" ב"₪100" (לא את החלק "₪")
מקרה שימוש: חילוץ מחירים
(?<=מחיר: ₪)\d+\.\d{2} → מתאים: "29.99" ב"מחיר: ₪29.99"
Lookbehind שלילי (?<!...)
מתאים אם הדפוס מאחור לא מתאים:
(?<!₪)\d+ → מתאים: "100" אבל לא ב"₪100"
טבלת סיכום:
| סוג | תחביר | תיאור | דוגמה |
|---|---|---|---|
| Lookahead חיובי | (?=...) |
מתאים אם אחריו... | q(?=u) מתאים "q" ב"queen" |
| Lookahead שלילי | (?!...) |
מתאים אם לא אחריו... | q(?!u) מתאים "q" ב"iraq" |
| Lookbehind חיובי | (?<=...) |
מתאים אם לפניו... | (?<=₪)\d+ מתאים "10" ב"₪10" |
| Lookbehind שלילי | (?<!...) |
מתאים אם לא לפניו... | (?<!₪)\d+ מתאים "10" ב"10" |
קבוצות לכידה עם שם
קבוצות עם שם (?<שם>...) הופכות את ה-regex לקריא יותר:
JavaScript:
const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2025-01-17'.match(dateRegex);
console.log(match.groups.year); // "2025"
console.log(match.groups.month); // "01"
console.log(match.groups.day); // "17"
Python:
import re
pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
match = re.search(pattern, '2025-01-17')
print(match.group('year')) # "2025"
print(match.group('month')) # "01"
print(match.group('day')) # "17"
C#:
var pattern = @"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})";
var match = Regex.Match("2025-01-17", pattern);
Console.WriteLine(match.Groups["year"].Value); // "2025"
קבוצות אטומיות וכמתים possessive
קבוצות אטומיות (?>...)
ברגע שמתאימה, הקבוצה לא עושה backtrack. מונעת backtracking קטסטרופלי:
(?>\d+)bar → מתאים: "123bar" (מהיר)
בלי קבוצה אטומית:
\d+bar → מנסה: "123bar", "12bar", "1bar" (איטי באי-התאמה)
כמתים Possessive
| חמדני | Possessive | תיאור |
|---|---|---|
* |
*+ |
0 או יותר (ללא backtracking) |
+ |
++ |
1 או יותר (ללא backtracking) |
? |
?+ |
0 או 1 (ללא backtracking) |
מקרה שימוש: מניעת backtracking קטסטרופלי בדפוסים מורכבים.
תמיכת Unicode
מנועי regex מודרניים תומכים בקטגוריות וסקריפטים של Unicode.
קטגוריות Unicode \p{...}
JavaScript (ES2018+):
const letters = /\p{L}+/u; // כל אות (כל שפה)
const numbers = /\p{N}+/u; // כל מספר
const currency = /\p{Sc}/u; // סמלי מטבע
Python:
import regex # הערה: דורש מודול 'regex', לא 're'
letters = regex.compile(r'\p{L}+')
קטגוריות Unicode נפוצות:
| קטגוריה | תיאור | דוגמה |
|---|---|---|
\p{L} |
אות | "a", "字", "א" |
\p{N} |
מספר | "1", "①", "一" |
\p{S} |
סמל | "$", "©", "♥" |
\p{Sc} |
סמל מטבע | "$", "€", "₪" |
\p{P} |
פיסוק | ".", "!", "?" |
\p{Z} |
מפריד | רווח, טאב |
סקריפטים של Unicode:
/\p{Script=Hebrew}/u → מתאים לאותיות עבריות: "א", "ב", "ג"
/\p{Script=Greek}/u → מתאים לאותיות יווניות: "α", "β", "γ"
/\p{Script=Cyrillic}/u → מתאים לקירילית: "а", "б", "в"
/\p{Script=Han}/u → מתאים לתווים סיניים
שלילה:
/\P{L}+/u → מתאים לכל מה שאינו אות
משנים ודגלים
דגלים משנים איך דפוסי regex מפורשים.
| דגל | שם | תיאור | דוגמה |
|---|---|---|---|
i |
חסר רגישות | מתעלם מאותיות גדולות/קטנות | /שלום/i מתאים "שלום" |
g |
גלובלי | מוצא את כל ההתאמות | /חתול/g מוצא את כל "חתול" |
m |
מרובה שורות | ^ ו-$ מתאימים לתחילת/סוף שורה |
/^שלום/m |
s |
Dotall | . מתאים גם לשורה חדשה |
/a.b/s מתאים "a\nb" |
u |
Unicode | מאפשר תכונות Unicode | /\p{L}+/u |
x |
מורחב | מתעלם מרווחים לבנים (free-spacing) | מאפשר הערות |
y |
דביק | מתאים במיקום מדויק | רק JavaScript |
דוגמאות:
חסר רגישות (i):
/שלום/i.test('שלום') // true
גלובלי (g):
'חתול כלב חתול'.match(/חתול/g) // ["חתול", "חתול"]
מרובה שורות (m):
const text = 'שורה 1\nשורה 2';
/^שורה 2/m.test(text) // true (בלי 'm': false)
Dotall (s):
/a.b/s.test('a\nb') // true (בלי 's': false)
משנים בשורה
החל דגלים על חלק מהדפוס:
(?i)שלום → "שלום" חסר רגישות
(?-i)עולם → "עולם" רגיש לאותיות
(?i:שלום) → רק "שלום" חסר רגישות
דפוסים מותנים
תחביר: (?(תנאי)נכון|לא נכון)
דוגמה: התאמת מחרוזות עם או בלי מרכאות
("|')?[^"'\r\n]*(?(1)\1)
פירוק:
("|')?- לוכד אופציונלית מרכאה פותחת[^"'\r\n]*- מתאים לתוכן(?(1)\1)- אם קבוצה 1 התאימה (מרכאה פותחת), התאם את אותה מרכאה סוגרת
מתאים:
"שלום"✅'עולם'✅בדיקה✅ (ללא מרכאות)"מעורב'❌ (מרכאות לא תואמות)
הערות ב-Regex
הערות בשורה (?# הערה)
\d{3}(?# קידומת)-\d{3}(?# אמצעי)-\d{4}(?# מספר)
מצב Free-Spacing (דגל x)
מתעלם מרווחים לבנים ומאפשר הערות:
(?x)
\d{3} # קידומת
- # מפריד
\d{3} # אמצעי
- # מפריד
\d{4} # מספר
הרבה יותר קריא לדפוסים מורכבים!
סעיף זה מדגים כיצד להשתמש ב-regex ב-7 שפות תכנות פופולריות. לכל שפה יש את ה-API של regex שלה, אבל תחביר הדפוסים נשאר ברובו עקבי.
JavaScript / Node.js
יצירת דפוסי Regex
// סימון ליטרלי (הכי נפוץ)
const pattern1 = /\d{3}-\d{4}/;
// קונסטרוקטור (כשהדפוס דינמי)
const pattern2 = new RegExp('\\d{3}-\\d{4}');
// הערה: צריך לברוח מ-backslash במחרוזות
// עם דגלים
const pattern3 = /שלום/gi; // גלובלי, חסר רגישות
מתודות String
// .match() - מוצא התאמות
const text = 'צור קשר: 123-4567 או 987-6543';
const matches = text.match(/\d{3}-\d{4}/g);
console.log(matches); // ["123-4567", "987-6543"]
// .matchAll() - מקבל את כל ההתאמות עם קבוצות (ES2020)
const emailPattern = /([\w.-]+)@([\w.-]+\.[a-z]{2,})/gi;
const emails = 'admin@example.co.il, user@test.org';
for (const match of emails.matchAll(emailPattern)) {
console.log(`משתמש: ${match[1]}, דומיין: ${match[2]}`);
}
// משתמש: admin, דומיין: example.co.il
// משתמש: user, דומיין: test.org
// .search() - מוצא מיקום של ההתאמה הראשונה
const pos = 'שלום עולם'.search(/עולם/);
console.log(pos); // 5
// .replace() - מחליף התאמות
const phone = '(+972) 50 123 4567';
const cleaned = phone.replace(/[^\d]/g, '');
console.log(cleaned); // "972501234567"
// .replaceAll() - מחליף את כל ההתאמות (ES2021)
const text2 = 'חתול כלב חתול';
const result = text2.replaceAll(/חתול/g, 'ציפור');
console.log(result); // "ציפור כלב ציפור"
// .split() - מחלק לפי דפוס
const csv = 'תפוח,בננה, תפוז , ענבים';
const fruits = csv.split(/\s*,\s*/);
console.log(fruits); // ["תפוח", "בננה", "תפוז", "ענבים"]
מתודות RegExp
// .test() - מחזיר בוליאני
const isEmail = /^[\w.-]+@[\w.-]+\.[a-z]{2,}$/i;
console.log(isEmail.test('user@example.co.il')); // true
// .exec() - מחזיר פרטי התאמה (או null)
const pattern = /(\d{4})-(\d{2})-(\d{2})/;
const match = pattern.exec('תאריך: 2025-01-17');
if (match) {
console.log(match[0]); // "2025-01-17" (התאמה מלאה)
console.log(match[1]); // "2025" (קבוצה 1)
console.log(match[2]); // "01" (קבוצה 2)
console.log(match[3]); // "17" (קבוצה 3)
}
קבוצות עם שם (ES2018+)
const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2025-01-17'.match(pattern);
console.log(match.groups.year); // "2025"
console.log(match.groups.month); // "01"
console.log(match.groups.day); // "17"
// הפניות אחורה עם שם
const dupeWord = /\b(?<word>\w+)\s+\k<word>\b/i;
console.log(dupeWord.test('שלום שלום')); // true
תמיכת Unicode (ES2018+)
// מתאים לכל אות (כולל מודגשות, סיניות, ערביות וכו')
const letters = /\p{L}+/u;
console.log(letters.test('קפה')); // true
console.log(letters.test('你好')); // true
// מתאים לאמוג'י
const emoji = /\p{Emoji}/u;
console.log(emoji.test('שלום 👋')); // true
Python
המודול re
import re
# קימפול דפוס (מומלץ לשימוש חוזר)
pattern = re.compile(r'\d{3}-\d{4}')
# או שימוש ישיר
re.search(r'\d{3}-\d{4}', 'התקשר 123-4567')
פונקציות ליבה
import re
# re.search() - מוצא התאמה ראשונה
match = re.search(r'\d{3}-\d{4}', 'צור קשר: 123-4567 או 987-6543')
if match:
print(match.group()) # "123-4567"
print(match.start()) # 10 (מיקום)
print(match.end()) # 18
# re.match() - מתאים בהתחלת המחרוזת
match = re.match(r'\d+', '123 רחוב הרצל')
print(match.group() if match else None) # "123"
match = re.match(r'\d+', 'רחוב הרצל 123')
print(match) # None (לא מתחיל בספרה)
# re.fullmatch() - מתאים לכל המחרוזת
result = re.fullmatch(r'\d{3}-\d{4}', '123-4567')
print(bool(result)) # True
result = re.fullmatch(r'\d{3}-\d{4}', 'התקשר 123-4567')
print(bool(result)) # False (טקסט נוסף)
# re.findall() - מוצא את כל ההתאמות (מחזיר רשימה)
text = 'מחירים: ₪10, ₪25, ₪100'
prices = re.findall(r'₪(\d+)', text)
print(prices) # ['10', '25', '100']
# re.finditer() - מוצא את כל ההתאמות (מחזיר איטרטור)
for match in re.finditer(r'₪(\d+)', text):
print(f'נמצא ₪{match.group(1)} במיקום {match.start()}')
# נמצא ₪10 במיקום 8
# נמצא ₪25 במיקום 13
# נמצא ₪100 במיקום 18
# re.sub() - מחליף התאמות
phone = '(+972) 50 123 4567'
cleaned = re.sub(r'[^\d]', '', phone)
print(cleaned) # "972501234567"
# re.split() - מחלק לפי דפוס
csv = 'תפוח,בננה, תפוז , ענבים'
fruits = re.split(r'\s*,\s*', csv)
print(fruits) # ['תפוח', 'בננה', 'תפוז', 'ענבים']
קבוצות וקבוצות עם שם
import re
# קבוצות ממוספרות
pattern = r'(\d{4})-(\d{2})-(\d{2})'
match = re.search(pattern, 'תאריך: 2025-01-17')
if match:
print(match.group(0)) # "2025-01-17" (התאמה מלאה)
print(match.group(1)) # "2025"
print(match.group(2)) # "01"
print(match.group(3)) # "17"
print(match.groups()) # ('2025', '01', '17')
# קבוצות עם שם (?P<name>...)
pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
match = re.search(pattern, '2025-01-17')
if match:
print(match.group('year')) # "2025"
print(match.group('month')) # "01"
print(match.group('day')) # "17"
print(match.groupdict()) # {'year': '2025', 'month': '01', 'day': '17'}
דגלים
import re
# חסר רגישות
re.search(r'שלום', 'שלום', re.IGNORECASE) # או re.I
# מרובה שורות (^ ו-$ מתאימים לתחילת/סוף שורה)
re.search(r'^שורה 2', 'שורה 1\nשורה 2', re.MULTILINE) # או re.M
# Dotall (. מתאים לשורה חדשה)
re.search(r'a.b', 'a\nb', re.DOTALL) # או re.S
# Verbose (מצב free-spacing עם הערות)
pattern = re.compile(r'''
\d{3} # קידומת
- # מפריד
\d{3} # אמצעי
- # מפריד
\d{4} # מספר
''', re.VERBOSE) # או re.X
# שילוב דגלים עם |
pattern = re.compile(r'שלום', re.IGNORECASE | re.MULTILINE)
החלפה עם פונקציות
import re
# שימוש בפונקציה להחלפות דינמיות
def double_number(match):
num = int(match.group())
return str(num * 2)
text = 'יש לי 5 תפוחים ו-10 תפוזים'
result = re.sub(r'\d+', double_number, text)
print(result) # "יש לי 10 תפוחים ו-20 תפוזים"
# עם קבוצות עם שם
def format_name(match):
return f"{match.group('last').upper()}, {match.group('first')}"
pattern = r'(?P<first>\w+)\s+(?P<last>\w+)'
text = 'דוד כהן'
result = re.sub(pattern, format_name, text)
print(result) # "כהן, דוד"
PHP
פונקציות PCRE
<?php
// preg_match() - מוצא התאמה ראשונה
$pattern = '/\d{3}-\d{4}/';
$text = 'צור קשר: 123-4567 או 987-6543';
if (preg_match($pattern, $text, $matches)) {
echo $matches[0]; // "123-4567"
}
// preg_match_all() - מוצא את כל ההתאמות
preg_match_all('/\d{3}-\d{4}/', $text, $matches);
print_r($matches[0]); // ["123-4567", "987-6543"]
// preg_replace() - מחליף התאמות
$phone = '(+972) 50 123 4567';
$cleaned = preg_replace('/[^\d]/', '', $phone);
echo $cleaned; // "972501234567"
// preg_split() - מחלק לפי דפוס
$csv = 'תפוח,בננה, תפוז , ענבים';
$fruits = preg_split('/\s*,\s*/', $csv);
print_r($fruits); // ["תפוח", "בננה", "תפוז", "ענבים"]
// preg_grep() - מסנן מערך לפי דפוס
$words = ['תפוח', 'בננה', 'אבטיח', 'אגס'];
$aWords = preg_grep('/^א/', $words);
print_r($aWords); // ["אבטיח", "אגס"]
?>
קבוצות עם שם
<?php
$pattern = '/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/';
$text = '2025-01-17';
if (preg_match($pattern, $text, $matches)) {
echo $matches['year']; // "2025"
echo $matches['month']; // "01"
echo $matches['day']; // "17"
}
?>
משנים (דגלים)
<?php
// i - חסר רגישות
preg_match('/שלום/i', 'שלום'); // מתאים
// m - מרובה שורות
preg_match('/^שורה 2/m', "שורה 1\nשורה 2"); // מתאים
// s - Dotall (. מתאים לשורה חדשה)
preg_match('/a.b/s', "a\nb"); // מתאים
// x - Free-spacing (מתעלם מרווחים לבנים)
$pattern = '/
\d{3} # קידומת
- # מפריד
\d{3} # אמצעי
- # מפריד
\d{4} # מספר
/x';
// u - תמיכת UTF-8
preg_match('/\w+/u', 'קפה'); // מתאים (כולל ה)
// שילוב משנים
preg_match('/שלום/imu', $text);
?>
החלפה עם Callback
<?php
$text = 'יש לי 5 תפוחים ו-10 תפוזים';
$result = preg_replace_callback('/\d+/', function($matches) {
return (int)$matches[0] * 2;
}, $text);
echo $result; // "יש לי 10 תפוחים ו-20 תפוזים"
?>
C# (.NET)
מחלקת Regex
using System;
using System.Text.RegularExpressions;
// מתודות סטטיות (שימוש פשוט)
string text = "צור קשר: 123-4567 או 987-6543";
Match match = Regex.Match(text, @"\d{3}-\d{4}");
if (match.Success)
{
Console.WriteLine(match.Value); // "123-4567"
}
// מוצא את כל ההתאמות
MatchCollection matches = Regex.Matches(text, @"\d{3}-\d{4}");
foreach (Match m in matches)
{
Console.WriteLine(m.Value);
}
// פלט:
// 123-4567
// 987-6543
// החלפה
string phone = "(+972) 50 123 4567";
string cleaned = Regex.Replace(phone, @"[^\d]", "");
Console.WriteLine(cleaned); // "972501234567"
// חלוקה
string csv = "תפוח,בננה, תפוז , ענבים";
string[] fruits = Regex.Split(csv, @"\s*,\s*");
// ["תפוח", "בננה", "תפוז", "ענבים"]
Regex קומפיילד (ביצועים טובים יותר)
using System.Text.RegularExpressions;
// קימפול לשימוש חוזר (הרבה יותר מהיר לשימוש חוזר)
Regex pattern = new Regex(@"\d{3}-\d{4}", RegexOptions.Compiled);
string text = "צור קשר: 123-4567";
Match match = pattern.Match(text);
if (match.Success)
{
Console.WriteLine(match.Value);
}
RegexOptions (דגלים)
using System.Text.RegularExpressions;
// חסר רגישות
Regex.IsMatch("שלום", "שלום", RegexOptions.IgnoreCase);
// מרובה שורות
Regex.Match("שורה 1\nשורה 2", "^שורה 2", RegexOptions.Multiline);
// Singleline (. מתאים לשורה חדשה)
Regex.Match("a\nb", "a.b", RegexOptions.Singleline);
// קומפיילד (ביצועים טובים יותר)
var pattern = new Regex(@"\d+", RegexOptions.Compiled);
// שילוב אפשרויות
var opts = RegexOptions.IgnoreCase | RegexOptions.Multiline;
Regex.Match(text, pattern, opts);
קבוצות עם שם
using System;
using System.Text.RegularExpressions;
string pattern = @"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})";
Match match = Regex.Match("2025-01-17", pattern);
if (match.Success)
{
Console.WriteLine(match.Groups["year"].Value); // "2025"
Console.WriteLine(match.Groups["month"].Value); // "01"
Console.WriteLine(match.Groups["day"].Value); // "17"
}
החלפה עם MatchEvaluator
using System;
using System.Text.RegularExpressions;
string text = "יש לי 5 תפוחים ו-10 תפוזים";
string result = Regex.Replace(text, @"\d+", match =>
{
int num = int.Parse(match.Value);
return (num * 2).ToString();
});
Console.WriteLine(result); // "יש לי 10 תפוחים ו-20 תפוזים"
Java
מחלקות Pattern ו-Matcher
import java.util.regex.Pattern;
import java.util.regex.Matcher;
// קימפול דפוס
Pattern pattern = Pattern.compile("\\d{3}-\\d{4}");
String text = "צור קשר: 123-4567 או 987-6543";
// יצירת matcher
Matcher matcher = pattern.matcher(text);
// מוצא התאמה ראשונה
if (matcher.find()) {
System.out.println(matcher.group()); // "123-4567"
}
// מוצא את כל ההתאמות
matcher.reset(); // איפוס להתחלה
while (matcher.find()) {
System.out.println(matcher.group());
}
// פלט:
// 123-4567
// 987-6543
מתודות String
// matches() - בודק אם כל המחרוזת מתאימה
boolean isPhone = "123-4567".matches("\\d{3}-\\d{4}");
System.out.println(isPhone); // true
// replaceAll() - מחליף את כל ההתאמות
String phone = "(+972) 50 123 4567";
String cleaned = phone.replaceAll("[^\\d]", "");
System.out.println(cleaned); // "972501234567"
// replaceFirst() - מחליף התאמה ראשונה
String text = "חתול כלב חתול";
String result = text.replaceFirst("חתול", "ציפור");
System.out.println(result); // "ציפור כלב חתול"
// split() - מחלק לפי דפוס
String csv = "תפוח,בננה, תפוז , ענבים";
String[] fruits = csv.split("\\s*,\\s*");
// ["תפוח", "בננה", "תפוז", "ענבים"]
דגלי Pattern
import java.util.regex.Pattern;
// חסר רגישות
Pattern pattern = Pattern.compile("שלום", Pattern.CASE_INSENSITIVE);
// מרובה שורות
Pattern.compile("^שורה 2", Pattern.MULTILINE);
// Dotall (. מתאים לשורה חדשה)
Pattern.compile("a.b", Pattern.DOTALL);
// הערות (free-spacing)
Pattern.compile("""
\\d{3} # קידומת
- # מפריד
\\d{3} # אמצעי
- # מפריד
\\d{4} # מספר
""", Pattern.COMMENTS);
// שילוב דגלים
int flags = Pattern.CASE_INSENSITIVE | Pattern.MULTILINE;
Pattern.compile("pattern", flags);
קבוצות עם שם
import java.util.regex.Pattern;
import java.util.regex.Matcher;
Pattern pattern = Pattern.compile("(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})");
Matcher matcher = pattern.matcher("2025-01-17");
if (matcher.find()) {
System.out.println(matcher.group("year")); // "2025"
System.out.println(matcher.group("month")); // "01"
System.out.println(matcher.group("day")); // "17"
}
החלפה מתקדמת
import java.util.regex.Pattern;
import java.util.regex.Matcher;
String text = "יש לי 5 תפוחים ו-10 תפוזים";
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(text);
StringBuffer result = new StringBuffer();
while (matcher.find()) {
int num = Integer.parseInt(matcher.group());
matcher.appendReplacement(result, String.valueOf(num * 2));
}
matcher.appendTail(result);
System.out.println(result); // "יש לי 10 תפוחים ו-20 תפוזים"
Go (Golang)
החבילה regexp
package main
import (
"fmt"
"regexp"
)
func main() {
// קימפול דפוס
pattern := regexp.MustCompile(`\d{3}-\d{4}`)
text := "צור קשר: 123-4567 או 987-6543"
// מוצא התאמה ראשונה
match := pattern.FindString(text)
fmt.Println(match) // "123-4567"
// מוצא את כל ההתאמות
matches := pattern.FindAllString(text, -1)
fmt.Println(matches) // [123-4567 987-6543]
// בודק אם מתאים
isMatch := pattern.MatchString("123-4567")
fmt.Println(isMatch) // true
// מחליף הכל
phone := "(+972) 50 123 4567"
cleaned := regexp.MustCompile(`[^\d]`).ReplaceAllString(phone, "")
fmt.Println(cleaned) // "972501234567"
// מחלק
csv := "תפוח,בננה, תפוז , ענבים"
fruits := regexp.MustCompile(`\s*,\s*`).Split(csv, -1)
fmt.Println(fruits) // [תפוח בננה תפוז ענבים]
}
Submatch (קבוצות)
package main
import (
"fmt"
"regexp"
)
func main() {
pattern := regexp.MustCompile(`(\d{4})-(\d{2})-(\d{2})`)
text := "תאריך: 2025-01-17"
// FindStringSubmatch מחזיר [מלא, קבוצה1, קבוצה2, ...]
matches := pattern.FindStringSubmatch(text)
if matches != nil {
fmt.Println(matches[0]) // "2025-01-17" (התאמה מלאה)
fmt.Println(matches[1]) // "2025" (קבוצה 1)
fmt.Println(matches[2]) // "01" (קבוצה 2)
fmt.Println(matches[3]) // "17" (קבוצה 3)
}
// FindAllStringSubmatch לכל ההתאמות
text2 := "תאריכים: 2025-01-17 ו-2024-12-31"
allMatches := pattern.FindAllStringSubmatch(text2, -1)
for _, match := range allMatches {
fmt.Printf("שנה: %s, חודש: %s, יום: %s\n", match[1], match[2], match[3])
}
// שנה: 2025, חודש: 01, יום: 17
// שנה: 2024, חודש: 12, יום: 31
}
קבוצות עם שם
package main
import (
"fmt"
"regexp"
)
func main() {
pattern := regexp.MustCompile(`(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})`)
text := "2025-01-17"
match := pattern.FindStringSubmatch(text)
if match != nil {
// מקבל אינדקסים של קבוצות עם שם
names := pattern.SubexpNames()
result := make(map[string]string)
for i, name := range names {
if i != 0 && name != "" {
result[name] = match[i]
}
}
fmt.Println(result["year"]) // "2025"
fmt.Println(result["month"]) // "01"
fmt.Println(result["day"]) // "17"
}
}
החלפה עם פונקציות
package main
import (
"fmt"
"regexp"
"strconv"
)
func main() {
text := "יש לי 5 תפוחים ו-10 תפוזים"
pattern := regexp.MustCompile(`\d+`)
result := pattern.ReplaceAllStringFunc(text, func(s string) string {
num, _ := strconv.Atoi(s)
return strconv.Itoa(num * 2)
})
fmt.Println(result) // "יש לי 10 תפוחים ו-20 תפוזים"
}
Ruby
ליטרלים של Regex
# סימון ליטרלי
pattern = /\d{3}-\d{4}/
# עם דגלים
pattern_ci = /שלום/i # חסר רגישות
pattern_multi = /^שורה/m # מרובה שורות
# קונסטרוקטור (לדפוסים דינמיים)
pattern = Regexp.new('\d{3}-\d{4}')
מתודות String
text = 'צור קשר: 123-4567 או 987-6543'
# match() - מחזיר MatchData או nil
match = text.match(/\d{3}-\d{4}/)
if match
puts match[0] # "123-4567"
end
# scan() - מוצא את כל ההתאמות
matches = text.scan(/\d{3}-\d{4}/)
puts matches # ["123-4567", "987-6543"]
# =~ אופרטור - מחזיר אינדקס של ההתאמה הראשונה
index = text =~ /\d{3}-\d{4}/
puts index # 10
# sub() - מחליף התאמה ראשונה
result = 'חתול כלב חתול'.sub(/חתול/, 'ציפור')
puts result # "ציפור כלב חתול"
# gsub() - מחליף את כל ההתאמות
phone = '(+972) 50 123 4567'
cleaned = phone.gsub(/[^\d]/, '')
puts cleaned # "972501234567"
# split() - מחלק לפי דפוס
csv = 'תפוח,בננה, תפוז , ענבים'
fruits = csv.split(/\s*,\s*/)
puts fruits # ["תפוח", "בננה", "תפוז", "ענבים"]
קבוצות לכידה
pattern = /(\d{4})-(\d{2})-(\d{2})/
match = '2025-01-17'.match(pattern)
if match
puts match[0] # "2025-01-17" (התאמה מלאה)
puts match[1] # "2025" (קבוצה 1)
puts match[2] # "01" (קבוצה 2)
puts match[3] # "17" (קבוצה 3)
end
קבוצות עם שם
pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
match = '2025-01-17'.match(pattern)
if match
puts match[:year] # "2025"
puts match[:month] # "01"
puts match[:day] # "17"
end
החלפה עם בלוקים
text = 'יש לי 5 תפוחים ו-10 תפוזים'
result = text.gsub(/\d+/) { |num| (num.to_i * 2).to_s }
puts result # "יש לי 10 תפוחים ו-20 תפוזים"
# עם קבוצות עם שם
pattern = /(?<first>\w+)\s+(?<last>\w+)/
text = 'דוד כהן'
result = text.gsub(pattern) do |match|
m = Regexp.last_match
"#{m[:last].upcase}, #{m[:first]}"
end
puts result # "כהן, דוד"
דגלים
# i - חסר רגישות
/שלום/i.match('שלום') # מתאים
# m - מרובה שורות (. מתאים לשורה חדשה)
/a.b/m.match("a\nb") # מתאים
# x - Free-spacing (מתעלם מרווחים לבנים)
pattern = /
\d{3} # קידומת
- # מפריד
\d{3} # אמצעי
- # מפריד
\d{4} # מספר
/x
# o - קימפול פעם אחת (אופטימיזציה)
pattern = /\d+/o
החיפוש והחלפה של Visual Studio Code (Ctrl/Cmd+H) תומך ב-regex עם יכולות טרנספורמציה חזקות. סעיף זה מציג 28 דוגמאות מעשיות שמפתחים משתמשים בהן כל יום.
גישה לחיפוש והחלפה
קיצורי מקלדת:
- חיפוש:
Ctrl+F(Windows/Linux) /Cmd+F(Mac) - החלפה:
Ctrl+H(Windows/Linux) /Cmd+H(Mac) - הפעלת Regex: לחץ על כפתור
.*או הקשAlt+R
טיפים:
- השתמש ב-
Ctrl+Enter(Cmd+Enter) כדי להחליף הכל - תצוגה מקדימה של התאמות לפני החלפה (מודגשות בצהוב)
- השתמש ב-
F3/Shift+F3לניווט בין התאמות
טרנספורמציות אותיות גדולות/קטנות
VS Code תומך ברצפים מיוחדים להחלפה להמרת אותיות:
| רצף | השפעה | דוגמה |
|---|---|---|
\l |
אות קטנה לתו הבא | \l |
\u |
אות גדולה לתו הבא | \u |
\L |
אות קטנה לכל התווים הבאים | \L |
\U |
אות גדולה לכל התווים הבאים | \U |
\E |
סיום טרנספורמציית אותיות | \U\E |
דוגמה 1: הפוך לאות גדולה בתחילת מילה
חיפוש:
\b(\w)(\w*)
החלפה:
\u$1$2
לפני:
שלום עולם
אחרי:
שלום עולם
סעיף זה מספק מעל 25 דפוסי regex מוכנים לשימוש.
אימות אימייל
^[\w.-]+@[\w.-]+\.[a-z]{2,}$
מספרי טלפון (ישראל)
^(\+?972)?[-.\s]?\(?([0-9]{2,3})\)?[-.\s]?([0-9]{3})[-.\s]?([0-9]{4})$
תאריכים (ISO 8601)
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
URL
^https?://(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b
כתובות IPv4
^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$
צבעי Hex
^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$
סיסמה חזקה
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$
שם משתמש (3-16 תווים)
^[a-zA-Z0-9_-]{3,16}$
UUID v4
^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
ועוד 15+ דפוסים עם תיעוד מלא!
יישומי regex מהעולם האמיתי בפיתוח.
אימות טפסים
const validators = {
email: /^[\w.-]+@[\w.-]+\.[a-z]{2,}$/i,
phone: /^\(?\d{2,3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/
};
חילוץ נתונים
חילוץ אימיילים מטקסט:
import re
emails = re.findall(r'[\w.-]+@[\w.-]+\.[a-z]{2,}', text)
ניתוח לוגים
pattern = r'(?P<ip>[\d.]+).+(?P<status>\d{3})'
Refactoring קוד
המרת קריאות API ישנות ב-VS Code:
חיפוש: apiClient\.get\('([^']+)'\)
החלפה: fetch('$1').then(r => r.json())
טעויות נפוצות
1. שכחת לברוח מתווים מיוחדים
❌ שגוי: file.txt
✅ נכון: file\.txt
2. חמדני לעומת עצלני
❌ חמדני: <.*> מתאים לכל <div>טקסט</div>
✅ עצלני: <.*?> מתאים ל-<div> ו-</div> בנפרד
3. אי שימוש בעוגנים
❌ /\d{3}/ מתאים "123" ב"abc123def"
✅ /^\d{3}$/ מתאים רק בדיוק ל"123"
טיפים לביצועים
- השתמש במחלקות תווים ספציפיות במקום
. - עגן את הדפוסים כשאפשר
- הימנע מכמתים מקוננים (backtracking קטסטרופלי)
- השתמש בקבוצות אטומיות לביצועים
- קמפל דפוסים לשימוש חוזר
ניפוי שגיאות
- בדוק ב-regex101.com
- השתמש במצב verbose עם הערות
- חלק דפוסים מורכבים לחלקים
- בדוק מקרי קצה
כלים מקוונים
בודקי Regex
- regex101.com - הבודק הטוב ביותר עם הסברים
- regexr.com - בונה ויזואלי של regex
- regexpal.com - בדיקה פשוטה ומהירה
כלי ויזואליזציה
- debuggex.com - דיאגרמות railroad
- regexper.com - כלי ויזואלי
משאבי למידה
- regexone.com - שיעורים אינטראקטיביים
- regexlearn.com - מדריך צעד אחר צעד
- regular-expressions.info - תיעוד
תוספים ל-IDE
- Regex Previewer (VS Code)
- Regex Tester (VS Code)
מחלקות תווים
| דפוס | מתאים ל |
|---|---|
\d |
ספרה [0-9] |
\w |
מילה [a-zA-Z0-9_] |
\s |
רווח לבן |
. |
כל תו |
כמתים
| דפוס | משמעות |
|---|---|
* |
0 או יותר |
+ |
1 או יותר |
? |
0 או 1 |
{n} |
בדיוק n |
עוגנים
| דפוס | משמעות |
|---|---|
^ |
תחילת שורה |
$ |
סוף שורה |
\b |
גבול מילה |
דגלים
| דגל | משמעות |
|---|---|
i |
חסר רגישות |
g |
גלובלי |
m |
מרובה שורות |
s |
Dotall |
שאלות כלליות
ש: מה ההבדל בין כמתים חמדניים לעצלניים?
ת: חמדני מתאים למקסימום האפשרי. עצלני (*?, +?) מתאים למינימום האפשרי.
ש: איך אני מתאים לנקודה ליטרלית?
ת: ברח ממנה עם backslash: \.
ש: מה זה backtracking קטסטרופלי?
ת: כאשר regex מנסה הרבה צירופים, גורם לאיטיות. הימנע מכמתים מקוננים כמו (a+)+.
ש: האם regex יכול לאמת אימייל בצורה מושלמת?
ת: לא. השתמש ב-regex לפורמט בסיסי, ואז אמת באמצעות אימייל.
ש: איך אני מתאים על פני מספר שורות?
ת: השתמש בדגל s, או השתמש ב-[\s\S]* במקום .*.
ספציפי ל-VS Code
ש: איך אני מחליף עם אותיות גדולות ב-VS Code?
ת: השתמש ב-\u (אות גדולה הבאה), \U (אות גדולה לכל).
ש: האם אני יכול להשתמש ב-regex בחיפוש קבצים ב-VS Code?
ת: כן! הקש Ctrl+Shift+F והפעל regex (Alt+R).
תוסף Chrome Regex Data Extractor
ה-Regex Data Extractor שלנו עוזר לכם לחלץ נתונים מדפי אינטרנט באמצעות הדפוסים מהמדריך הזה.
תכונות עיקריות
- ספריית דפוסים: דפוסים מובנים מראש
- בדיקה בזמן אמת: בדוק regex בכל דף אינטרנט
- ייצוא מרובה פורמטים: CSV, JSON, Excel, PDF
- חילוץ באצווה: חילוץ מדפים מרובים
דוגמה: חילוץ אימיילים
- התקן את Regex Data Extractor
- נווט לכל דף אינטרנט
- לחץ על אייקון התוסף
- הכנס דפוס:
[\w.-]+@[\w.-]+\.[a-z]{2,} - לחץ "חלץ"
- ייצא ל-CSV/JSON
דוגמה: חילוץ מחירים
דפוס: ₪([0-9]{1,3}(?:\.?[0-9]{3})*,?[0-9]{2})
לוכד: ₪1,234.56, ₪99.99
טיפים מקצועיים
- שמור דפוסים בשימוש תדיר
- השתמש בקבוצות עם שם לנתונים מובנים
- בדוק דפוסים קודם
- ייצא לניתוח נתונים