نلفت انتباهكم إلى ترجمة دليل قصير للتعبيرات العادية في لغة جافا، كتبه جيف فريسين لموقع
JavaWorld . ولتسهيل القراءة قمنا بتقسيم المقال إلى عدة أجزاء.
استخدام واجهة برمجة تطبيقات التعبير العادي في برامج Java للتعرف على الأنماط ووصفها
توفر أحرف Java وأنواع بيانات السلسلة المختلفة دعمًا منخفض المستوى لمطابقة الأنماط، ولكن استخدامها لهذا الغرض عادةً ما يضيف تعقيدًا كبيرًا في التعليمات البرمجية. يتم الحصول على تعليمات برمجية أبسط وأكثر أداءً باستخدام Regex API ("Regular Expression API"). سيساعدك هذا البرنامج التعليمي على البدء باستخدام التعبيرات العادية وواجهة برمجة تطبيقات Regex. سنناقش أولاً الفئات الثلاثة الأكثر إثارة للاهتمام في الحزمة بشكل عام
java.util.regex
، ثم نلقي نظرة داخل الفصل
Pattern
ونستكشف بنياته المتطورة لمطابقة الأنماط.
انتباه: يمكنك تنزيل الكود المصدري (الذي أنشأه Jeff Friesen لموقع JavaWorld) للتطبيق التجريبي من هذه المقالة
من هنا .
ما هي التعبيرات العادية؟
التعبير العادي (التعبير العادي/regex/regexp) عبارة عن سلسلة تمثل نمطًا يصف مجموعة معينة من السلاسل. يحدد النمط الصفوف التي تنتمي إلى المجموعة. يتكون النمط من أحرف حرفية وأحرف أولية، وهي أحرف ذات معنى خاص بدلاً من المعنى الحرفي. مطابقة الأنماط عبارة عن بحث في النص للعثور على التطابقات، أي السلاسل التي تطابق نمط التعبير العادي. تدعم Java مطابقة الأنماط من خلال Regex API الخاص بها. تتكون واجهة برمجة التطبيقات هذه من ثلاث فئات:
Pattern
و
Matcher
و
PatternSyntaxException
، الموجودة في الحزمة
java.util.regex
:
- كائنات الفئة
Pattern
، والتي تسمى أيضًا القوالب، عبارة عن تعبيرات عادية مجمعة.
- كائنات الفئة
Matcher
، أو المطابقات، هي آليات لتفسير الأنماط للعثور على التطابقات في تسلسلات الأحرف (الكائنات التي تنفذ فئاتها واجهة java.lang.CharSequence
وتعمل كمصادر نصية).
- تُستخدم كائنات الفئة
PatternSyntaxException
لوصف أنماط التعبير العادي غير الصالحة.
توفر Java أيضًا دعمًا لمطابقة الأنماط من خلال طرق مختلفة لملف
java.lang.String
.
boolean matches (String regex)
على سبيل المثال، ترجع الدالة
true
فقط إذا كانت سلسلة الاستدعاء تطابق التعبير العادي تمامًا
regex
.
طرق مريحة |
matches() ويتم تنفيذ أساليب الراحة الأخرى الموجهة نحو التعبير العادي String ضمن الغطاء بطريقة مشابهة لـ Regex API. |
RegexDemo
لقد قمت بإنشاء تطبيق لتوضيح تعبيرات
RegexDemo
Java العادية والأساليب المختلفة لـ
Pattern
. يوجد أدناه الكود المصدري لهذا التطبيق التجريبي. القائمة 1. مظاهرة التعبير العادي
Matcher
PatternSyntaxException
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class RegexDemo
{
public static void main(String[] args)
{
if (args.length != 2)
{
System.err.println("usage: java RegexDemo regex input");
return;
}
args[1] = args[1].replaceAll("\\\\n", "\n");
try
{
System.out.println("regex = " + args[0]);
System.out.println("input = " + args[1]);
Pattern p = Pattern.compile(args[0]);
Matcher m = p.matcher(args[1]);
while (m.find())
System.out.println("Found [" + m.group() + "] starting at "
+ m.start() + " and ending at " + (m.end() - 1));
}
catch (PatternSyntaxException pse)
{
System.err.println("Неправильное регулярное выражение: " + pse.getMessage());
System.err.println("Описание: " + pse.getDescription());
System.err.println("Позиция: " + pse.getIndex());
System.err.println("Неправильный шаблон: " + pse.getPattern());
}
}
}
أول شيء تفعله طريقة
main
الفصل
RegexDemo
هو التحقق من سطر الأوامر الخاص بها. ويتطلب وسيطين: الأول عبارة عن تعبير عادي، والثاني هو نص الإدخال الذي سيتم البحث فيه عن التعبير العادي. قد تحتاج إلى استخدام حرف السطر الجديد داخل نص الإدخال
(\n)
. ولا يمكن القيام بذلك إلا عن طريق تحديد الحرف
\
متبوعًا بالحرف
n
. تقوم الدالة
main()
بتحويل تسلسل الأحرف هذا إلى قيمة Unicode 10. ويتم تضمين
الجزء الأكبر من الكود في ملف . تقوم الكتلة أولاً بإخراج التعبير العادي المحدد والنص المُدخل، ثم تقوم بإنشاء كائن يخزن التعبير العادي المترجم (يتم تجميع التعبيرات العادية لتحسين أداء مطابقة الأنماط). يتم استخراج المطابق من الكائن واستخدامه للبحث عن التطابقات بشكل متكرر حتى يتم العثور عليها جميعًا. تستدعي الكتلة عدة طرق فئة لاسترداد معلومات مفيدة حول الاستثناء. يتم إخراج هذه المعلومات بشكل تسلسلي إلى دفق الإخراج. ليست هناك حاجة لمعرفة تفاصيل كيفية عمل الكود بعد: ستتضح عندما ندرس واجهة برمجة التطبيقات (API) في الجزء الثاني من المقالة. ومع ذلك، يجب عليك ترجمة القائمة 1. خذ الكود من القائمة 1، ثم اكتب الأمر التالي في موجه الأوامر للتجميع :
RegexDemo
try-catch
try
Pattern
Pattern
catch
PatternSyntaxException
RegexDemo
javac RegexDemo.java
فئة النمط وبنياتها
الفئة
Pattern
، الأولى من بين الفئات الثلاث التي تشكل Regex API، هي تمثيل مجمع للتعبير العادي. تصف وثائق فئة SDK
Pattern
مجموعة متنوعة من بنيات التعبير العادي، ولكن إذا كنت لا تستخدم التعبيرات العادية بشكل نشط، فقد تكون أجزاء من هذه الوثائق مربكة. ما هي أدوات القياس الكمية وما هو الفرق بين أجهزة قياس الكميات الجشعة والمترددة والتملكية؟ ما هي فئات الأحرف ومطابقات الحدود والمراجع الخلفية وتعبيرات العلم المضمنة؟ سأجيب على هذه الأسئلة وغيرها في الأقسام التالية.
سلاسل حرفية
أبسط بناء للتعبير العادي هو سلسلة حرفية. لكي تنجح مطابقة النمط، يجب أن يتطابق جزء من نص الإدخال مع نمط هذا البناء. خذ بعين الاعتبار المثال التالي:
java RegexDemo apple applet
في هذا المثال، نحاول العثور على تطابق لنمط
apple
في النص المُدخل
applet
. تظهر النتيجة التالية المطابقة التي تم العثور عليها:
regex = apple
input = applet
Found [apple] starting at 0 and ending at 4
نرى في الإخراج التعبير العادي والنص المدخل، ومن ثم إشارة إلى الكشف الناجح
apple
في التطبيق الصغير. بالإضافة إلى ذلك، تم تحديد موضعي البداية والنهاية لهذه المباراة:
0
و
4
، على التوالي. يشير موضع البداية إلى المكان الأول في النص الذي تم العثور على تطابق فيه، ويشير موضع النهاية إلى النقطة الأخيرة في المطابقة. لنفترض الآن أننا قدمنا سطر الأوامر التالي:
java RegexDemo apple crabapple
هذه المرة حصلنا على النتيجة التالية، بمواضع بداية ونهاية مختلفة:
regex = apple
input = crabapple
Found [apple] starting at 4 and ending at 8
بخلاف ذلك، مع
applet
التعبير العادي
apple
- نص الإدخال، لن يتم العثور على أي تطابقات. يجب أن يتطابق التعبير العادي بأكمله، ولكن في هذه الحالة، لا يحتوي النص المُدخل
t
على بعد
apple
.
الأحرف الأولية
تجمع بنيات التعبير العادي الأكثر إثارة للاهتمام بين الأحرف الحرفية والأحرف الأولية. على سبيل المثال، في التعبير العادي ، يعني
a.b
الحرف الأولي النقطي أي حرف بين وb. خذ بعين الاعتبار المثال التالي: يستخدم هذا المثال كتعبير عادي وكنص إدخال. يبحث في النص عن مطابقات تبدأ بأي حرف وتنتهي بـ وتكون نتائج تنفيذه كما يلي:
(.)
a
java RegexDemo .ox "The quick brown fox jumps over the lazy ox."
.ox
The quick brown fox jumps over the lazy ox.
RegexDemo
ox.
regex = .ox
input = The quick brown fox jumps over the lazy ox.
Found [fox] starting at 16 and ending at 18
Found [ ox] starting at 39 and ending at 41
في الإخراج نرى مطابقتين:
fox
و
ox
(مع وجود مسافة أمامه). يتطابق الحرف الأولي
.
مع حرف
f
في الحالة الأولى ومسافة في الحالة الثانية. ماذا يحدث إذا قمت باستبداله
.ox
بحرف أولي
.
؟ وهذا هو ما نحصل عليه كنتيجة لسطر الأوامر التالي:
java RegexDemo . "The quick brown fox jumps over the lazy ox."
بما أن الحرف النقطي يتطابق مع أي حرف،
RegexDemo
فسيتم إخراج التطابقات الموجودة لجميع الأحرف (بما في ذلك حرف النقطة اللاحقة) للنص المُدخل:
regex = .
input = The quick brown fox jumps over the lazy ox.
Found [T] starting at 0 and ending at 0
Found [h] starting at 1 and ending at 1
Found [e] starting at 2 and ending at 2
Found [ ] starting at 3 and ending at 3
Found [q] starting at 4 and ending at 4
Found [u] starting at 5 and ending at 5
Found [i] starting at 6 and ending at 6
Found [c] starting at 7 and ending at 7
Found [k] starting at 8 and ending at 8
Found [ ] starting at 9 and ending at 9
Found [b] starting at 10 and ending at 10
Found [r] starting at 11 and ending at 11
Found [o] starting at 12 and ending at 12
Found [w] starting at 13 and ending at 13
Found [n] starting at 14 and ending at 14
Found [ ] starting at 15 and ending at 15
Found [f] starting at 16 and ending at 16
Found [o] starting at 17 and ending at 17
Found [x] starting at 18 and ending at 18
Found [ ] starting at 19 and ending at 19
Found [j] starting at 20 and ending at 20
Found [u] starting at 21 and ending at 21
Found [m] starting at 22 and ending at 22
Found [p] starting at 23 and ending at 23
Found [s] starting at 24 and ending at 24
Found [ ] starting at 25 and ending at 25
Found [o] starting at 26 and ending at 26
Found [v] starting at 27 and ending at 27
Found [e] starting at 28 and ending at 28
Found [r] starting at 29 and ending at 29
Found [ ] starting at 30 and ending at 30
Found [t] starting at 31 and ending at 31
Found [h] starting at 32 and ending at 32
Found [e] starting at 33 and ending at 33
Found [ ] starting at 34 and ending at 34
Found [l] starting at 35 and ending at 35
Found [a] starting at 36 and ending at 36
Found [z] starting at 37 and ending at 37
Found [y] starting at 38 and ending at 38
Found [ ] starting at 39 and ending at 39
Found [o] starting at 40 and ending at 40
Found [x] starting at 41 and ending at 41
Found [.] starting at 42 and ending at 42
اقتباس الأحرف الأولية |
لتحديد . أو أي حرف أولي آخر كحرف حرفي في بنية تعبير عادي، يجب عليك الهروب منه بإحدى الطرق التالية:
- يسبقه حرف مائل عكسي؛
- ضع هذا الحرف الأولي بين
\Q و \E (على سبيل المثال، \Q.\E ).
تذكر تكرار أي أحرف تظهر في السلسلة الحرفية، مثل String regex = "\\."; الخطوط المائلة العكسية (على سبيل المثال، \\. أو \\Q.\\E ). لا تقم بتكرار تلك الخطوط المائلة العكسية التي تعد جزءًا من وسيطة سطر الأوامر. |
فئات الشخصيات
في بعض الأحيان يتعين عليك قصر التطابقات التي تبحث عنها على مجموعة محددة من الأحرف. على سبيل المثال، ابحث في النص عن حروف العلة
a
و
e
و
i
و
o
و
u
، مع اعتبار كل ظهور لحرف متحرك متطابقًا. في حل مثل هذه المشكلات، ستساعدنا فئات الأحرف التي تحدد مجموعات من الأحرف بين الأحرف الأولية بين الأقواس المربعة (
[ ]
). يدعم الفصل
Pattern
فئات الأحرف البسيطة وفئات النطاق والعكس والاتحاد والتقاطع والطرح. سننظر في كل منهم الآن.
فئات الأحرف البسيطة
تتكون فئة الأحرف البسيطة من أحرف موضوعة جنبًا إلى جنب وتتطابق مع تلك الأحرف فقط. على سبيل المثال، يتطابق الفصل مع
[abc]
الأحرف و . خذ بعين الاعتبار المثال التالي: كما ترون من النتائج، في هذا المثال فقط الحرف الذي يوجد تطابق له :
a
b
c
java RegexDemo [csw] cave
c
cave
regex = [csw]
input = cave
Found [c] starting at 0 and ending at 0
فئات الأحرف المقلوبة
تبدأ فئة الأحرف المقلوبة بحرف أولي
^
وتتطابق فقط مع الأحرف غير الموجودة فيه. على سبيل المثال، يتطابق الفصل
[^abc]
مع كافة الأحرف
a
باستثناء
b
و
c
. خذ بعين الاعتبار المثال التالي:
java RegexDemo "[^csw]" cave
لاحظ أنه في نظام التشغيل (Windows) الخاص بي، تكون علامات الاقتباس المزدوجة مطلوبة لأن الصدفة تتعامل معها
^
كحرف هروب. كما ترون، في هذا المثال فقط الأحرف و
a
تم العثور عليها والتي توجد مطابقات لها في :
v
e
cave
regex = [^csw]
input = cave
Found [a] starting at 1 and ending at 1
Found [v] starting at 2 and ending at 2
Found [e] starting at 3 and ending at 3
فئات أحرف النطاق
تتكون فئة أحرف النطاق من حرفين مفصولين بواصلة (
-
). تعتبر كافة الأحرف، بدءًا من الحرف الموجود على يسار الواصلة وتنتهي بالحرف الموجود على اليمين، جزءًا من النطاق. على سبيل المثال، يتطابق النطاق
[a-z]
مع كافة الأحرف اللاتينية الصغيرة. وهذا يعادل تعريف فئة بسيطة
[abcdefghijklmnopqrstuvwxyz]
. خذ بعين الاعتبار المثال التالي:
java RegexDemo [a-c] clown
سيطابق هذا المثال فقط الحرف
c
الذي له تطابق في
clown
:
regex = [a-c]
input = clown
Found [c] starting at 0 and ending at 0
التعبيرات العادية في جافا، الجزء 2 التعبيرات العادية في جافا، الجزء 3 التعبيرات العادية في جافا، الجزء 4 التعبيرات العادية في جافا، الجزء 5
GO TO FULL VERSION