ما هو التعبير العادي RegEx؟
في الواقع، التعبير العادي (RegEx في Java) هو نمط للبحث عن سلسلة في النص. في Java، يكون التمثيل الأولي لهذا النمط دائمًا عبارة عن سلسلة، أي كائن من فئة السلسلة. ومع ذلك، لا يمكن تجميع أي سلسلة في تعبير عادي، فقط تلك التي تتبع قواعد كتابة التعبير العادي - بناء الجملة المحدد في مواصفات اللغة. لكتابة تعبير عادي، يتم استخدام الأحرف الأبجدية والرقمية، بالإضافة إلى الأحرف الأولية - وهي الأحرف التي لها معنى خاص في بناء جملة التعبيرات العادية. على سبيل المثال:String regex = "java"; // string template "java";
String regex = "\\d{3}"; // string template of three numeric characters;
إنشاء التعبيرات العادية في جافا
لإنشاء RegEx في Java، عليك اتباع خطوتين بسيطتين:- كتابتها كسلسلة باستخدام بناء جملة التعبير العادي؛
- تجميع هذه السلسلة في تعبير عادي؛
Pattern
. للقيام بذلك، تحتاج إلى استدعاء إحدى الطريقتين الثابتتين المتوفرتين في الفصل compile
. تأخذ الطريقة الأولى وسيطة واحدة - سلسلة حرفية للتعبير العادي، والثانية - بالإضافة إلى معلمة أخرى تقوم بتشغيل وضع مقارنة القالب بالنص:
public static Pattern compile (String literal)
public static Pattern compile (String literal, int flags)
يتم تعريف قائمة قيم المعلمات المحتملة flags
في الفصل Pattern
وهي متاحة لنا كمتغيرات فئة ثابتة. على سبيل المثال:
Pattern pattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE);//searching for matches with the pattern will be done case-insensitively.
في الأساس، الفصل Pattern
هو منشئ التعبير العادي. تحت الغطاء، compile
تستدعي الطريقة المُنشئ الخاص للفئة Pattern
لإنشاء طريقة عرض مجمعة. يتم تنفيذ هذه الطريقة لإنشاء مثيل القالب بهدف إنشائه ككائن غير قابل للتغيير. عند الإنشاء، يتم إجراء فحص بناء الجملة للتعبير العادي. إذا كانت هناك أخطاء في السطر، فسيتم إنشاء استثناء PatternSyntaxException
.
بناء جملة التعبير العادي
يعتمد بناء جملة التعبير العادي على استخدام الرموز<([{\^-=$!|]})?*+.>
، والتي يمكن دمجها مع الأحرف الأبجدية. اعتمادًا على دورهم، يمكن تقسيمهم إلى عدة مجموعات:
حرف أولي | غاية |
---|---|
^ | بداية السطر |
$ | نهاية الخط |
\ب | حدود الكلمة |
\ب | ليس حدا للكلمة |
\أ | بداية الإدخال |
\ز | نهاية المباراة السابقة |
\ز | نهاية الإدخال |
\ض | نهاية الإدخال |
حرف أولي | غاية |
---|---|
\د | رمز رقمي |
\د | حرف غير رقمي |
\س | حرف الفضاء |
\س | حرف غير مسافة بيضاء |
\ث | حرف أبجدي رقمي أو الشرطة السفلية |
\د | أي حرف بخلاف الحروف الأبجدية أو الرقمية أو الشرطة السفلية |
. | أي شخصية |
حرف أولي | غاية |
---|---|
\ ر | حرف علامة التبويب |
\ن | حرف السطر الجديد |
\ ص | حرف العودة |
\F | انتقل إلى الصفحة الجديدة |
\u0085 | حرف السطر التالي |
\ش 2028 | حرف فاصل الخط |
\ش 2029 | رمز فاصل الفقرة |
حرف أولي | غاية |
---|---|
[أ ب ج] | أي مما سبق (أ، ب، ج) |
[^اي بي سي] | أي شيء آخر غير تلك المذكورة (ليس أ، ب، ج) |
[أ-ي-ي] | دمج النطاق (الأحرف اللاتينية من a إلى z غير حساسة لحالة الأحرف) |
[إعلان[MP]] | تسلسل الأحرف (من a إلى d ومن m إلى p) |
[أ&&[تعريف]] | تقاطع الرموز (الرموز d,e,f) |
[من الألف إلى الياء &&[^قبل الميلاد]] | طرح الأحرف (الأحرف a، dz) |
حرف أولي | غاية |
---|---|
؟ | واحد أو مفقود |
* | صفر مرة أو أكثر |
+ | مرة واحدة أو أكثر |
{ن} | ن مرات |
{ن،} | ن مرات أو أكثر |
{ن،م} | ما لا يقل عن n مرة ولا يزيد عن m مرة |
وضع الكمي الجشع
الميزة الخاصة لمحددات الكمية هي القدرة على استخدامها في أوضاع مختلفة: الجشع، والجشع الشديد، والكسالى. يتم تشغيل الوضع الجشع الإضافي بإضافة الرمز "+
" بعد محدد الكمية، والوضع البطيء بإضافة الرمز " ?
". على سبيل المثال:
"A.+a" // greedy mode
"A.++a" // over-greedy mode
"A.+?a" // lazy mode
باستخدام هذا القالب كمثال، دعونا نحاول فهم كيفية عمل محددات الكمية في أوضاع مختلفة. بشكل افتراضي، يعمل محدد الكمية في الوضع الجشع. هذا يعني أنه يبحث عن أطول تطابق ممكن في السلسلة. نتيجة لتشغيل هذا الكود:
public static void main(String[] args) {
String text = "Egor Alla Alexander";
Pattern pattern = Pattern.compile("A.+a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(text.substring(matcher.start(), matcher.end()));
}
}
سنحصل على المخرجات التالية: Alla Alexa . يتم تنفيذ خوارزمية البحث لنمط معين " А.+а
" بالتسلسل التالي:
-
في النمط المحدد، الحرف الأول هو الحرف الروسي
А
.Matcher
يطابقها مع كل حرف في النص، بدءًا من الموضع صفر. يوجد رمز في الموضع صفر في نصناЕ
، بحيثMatcher
يمر عبر الأحرف الموجودة في النص بشكل تسلسلي حتى يتطابق مع النمط. في مثالنا، هذا هو الرمز الموجود في الموضع رقم 5. -
بعد العثور على تطابق مع الحرف الأول للنمط،
Matcher
فإنه يتحقق من التطابق مع الحرف الثاني من النمط. في حالتنا، هذا هو الرمز ".
"، الذي يرمز إلى أي حرف.وفي الموضع السادس يوجد رمز الحرف
л
. وبطبيعة الحال، فإنه يطابق نمط "أي شخصية". -
Matcher
ينتقل إلى التحقق من الحرف التالي من النمط. في القالب الخاص بنا، يتم تحديده باستخدام.+
محدد الكمية "". وبما أن عدد تكرارات "أي حرف" في النمط هو مرة واحدة أو أكثر،Matcher
فإنه يأخذ الحرف التالي من السلسلة بدوره ويتحقق من مطابقته للنمط، طالما تم استيفاء شرط "أي حرف"، في مثالنا - حتى نهاية السطر ( من الموضع رقم 7 - رقم 18 من النص).في الواقع،
Matcher
فهو يلتقط السطر بأكمله حتى النهاية - وهنا يتجلى "جشعه". -
بعد
Matcher
الوصول إلى نهاية النص والانتهاء من التحقق منА.+
الجزء " " من النمط، يبدأ Matcher في التحقق من بقية النمط - حرف الحرفа
. بما أن النص في الاتجاه الأمامي قد انتهى، يتم التحقق في الاتجاه العكسي، بدءًا من الحرف الأخير: -
Matcher
"يتذكر" عدد التكرارات في النمط ".+
" الذي وصل عنده إلى نهاية النص، فيقوم بتقليل عدد التكرارات بمقدار واحد ويتحقق من نمط النص حتى يتم العثور على تطابق:
وضع الكمي الجشع للغاية
في وضع الجشع الفائق، يعمل المطابق بشكل مشابه لآلية وضع الجشع. والفرق هو أنه عندما تقوم بسحب النص إلى نهاية السطر، لا يوجد بحث عكسي. أي أن المراحل الثلاث الأولى في وضع الجشع الفائق ستكون مشابهة لوضع الجشع. بعد التقاط السلسلة بأكملها، يضيف المطابق بقية النمط ويقارنه بالسلسلة الملتقطة. في مثالنا، عند تنفيذ الطريقة الرئيسية بالنمط "А.++а
"، لن يتم العثور على أي تطابقات.
وضع الكمي كسول
-
في هذا الوضع، في المرحلة الأولية، كما هو الحال في الوضع الجشع، يتم البحث عن تطابق مع الحرف الأول من النمط:
-
بعد ذلك، يبحث عن تطابق مع الحرف التالي في النمط - أي حرف:
-
على عكس الوضع الجشع، يبحث الوضع البطيء عن أقصر تطابق في النص، لذلك بعد العثور على تطابق مع الحرف الثاني من النمط، والذي تم تحديده بنقطة ويطابق الحرف في الموضع رقم 6 من النص، فإنه
Matcher
سيتحقق مما إذا كان النص يطابق بقية النمط - الحرف "а
" . -
بما أنه لم يتم العثور على تطابق مع النمط الموجود في النص (في الموضع رقم 7 في النص يوجد الرمز ""
л
)،Matcher
فإنه يضيف "أي حرف" آخر في النمط، حيث يتم تحديده مرة واحدة أو أكثر، ومرة أخرى يقارن النمط مع النص في المواضع من رقم 5 إلى رقم 8: -
في حالتنا، تم العثور على تطابق، ولكن لم يتم الوصول إلى نهاية النص بعد. لذلك، من الموضع رقم 9، يبدأ الفحص بالبحث عن الحرف الأول للنمط باستخدام خوارزمية مشابهة ثم يكرر حتى نهاية النص.
main
عند استخدام القالب " А.+?а
"، سنحصل على النتيجة التالية: Alla Alexa كما يتبين من مثالنا، عند استخدام أوضاع قياس كمية مختلفة لنفس القالب، حصلنا على نتائج مختلفة. ولذلك فمن الضروري أخذ هذه الخاصية بعين الاعتبار واختيار الوضع المطلوب حسب النتيجة المطلوبة أثناء البحث.
الهروب من الأحرف في التعبيرات العادية
نظرًا لأن التعبير العادي في Java، أو بشكل أكثر دقة تمثيله الأولي، يتم تحديده باستخدام سلسلة حرفية، فمن الضروري مراعاة قواعد مواصفات Java التي تتعلق بالسلسلة الحرفية. على وجه الخصوص، يتم تفسير حرف الخط المائل العكسي "\
" في سلسلة حرفية في التعليمات البرمجية المصدر لـ Java على أنه حرف هروب ينبه المترجم إلى أن الحرف الذي يتبعه هو حرف خاص ويجب تفسيره بطريقة خاصة. على سبيل المثال:
String s = "The root directory is \nWindows";//wrap Windows to a new line
String s = "The root directory is \u00A7Windows";//insert paragraph character before Windows
لذلك، في سلسلة حرفية تصف تعبيرًا عاديًا وتستخدم الحرف " \
" (على سبيل المثال، للأحرف الأولية)، يجب مضاعفته حتى لا يفسره مترجم Java bytecode بشكل مختلف. على سبيل المثال:
String regex = "\\s"; // template for searching for space characters
String regex = "\"Windows\""; // pattern to search for the string "Windows"
يجب أيضًا استخدام حرف الشرطة المائلة العكسية المزدوجة للهروب من الأحرف الخاصة إذا كنا نخطط لاستخدامها كأحرف "عادية". على سبيل المثال:
String regex = "How\\?"; // template for searching the string "How?"
طرق فئة النمط
لدى الفئةPattern
طرق أخرى للتعامل مع التعبيرات العادية: String pattern()
– إرجاع تمثيل السلسلة الأصلية للتعبير العادي الذي تم إنشاء الكائن منه Pattern
:
Pattern pattern = Pattern.compile("abc");
System.out.println(Pattern.pattern())//"abc"
static boolean matches(String regex, CharSequence input)
- يسمح لك بالتحقق من التعبير العادي الذي تم تمريره في معلمة regex مقابل النص الذي تم تمريره في المعلمة input
. العوائد: صحيح – إذا كان النص يطابق النمط؛ كاذبة – خلاف ذلك؛ مثال:
System.out.println(Pattern.matches("A.+a","Alla"));//true
System.out.println(Pattern.matches("A.+a","Egor Alla Alexander"));//false
int flags()
- يُرجع flags
قيم معلمات القالب التي تم تعيينها عند إنشائه، أو 0 إذا لم يتم تعيين هذه المعلمة. مثال:
Pattern pattern = Pattern.compile("abc");
System.out.println(pattern.flags());// 0
Pattern pattern = Pattern.compile("abc",Pattern.CASE_INSENSITIVE);
System.out.println(pattern.flags());// 2
String[] split(CharSequence text, int limit)
- يقسم النص الذي تم تمريره كمعلمة إلى مجموعة من العناصر String
. تحدد المعلمة limit
الحد الأقصى لعدد التطابقات التي يتم البحث عنها في النص:
- متى
limit>0
–limit-1
يتم إجراء البحث عن التطابقات؛ - في
limit<0
- يبحث عن جميع التطابقات في النص - عندما
limit=0
- يبحث عن جميع التطابقات في النص، بينما يتم تجاهل الأسطر الفارغة في نهاية المصفوفة؛
public static void main(String[] args) {
String text = "Egor Alla Anna";
Pattern pattern = Pattern.compile("\\s");
String[] strings = pattern.split(text,2);
for (String s : strings) {
System.out.println(s);
}
System.out.println("---------");
String[] strings1 = pattern.split(text);
for (String s : strings1) {
System.out.println(s);
}
}
إخراج وحدة التحكم: Egor Alla Anna -------- Egor Alla Anna سننظر في طريقة فئة أخرى لإنشاء كائن Matcher
أدناه.
أساليب الطبقة المتطابقة
Matcher
هي فئة يتم من خلالها إنشاء كائن للبحث عن الأنماط. Matcher
- هذا "محرك بحث"، "محرك" للتعبيرات العادية. للبحث، يحتاج إلى إعطائه شيئين: نمط بحث و"عنوان" للبحث فيه. لإنشاء كائن، Matcher
يتم توفير الطريقة التالية في الفصل Pattern
: рublic Matcher matcher(CharSequence input)
كوسيطة، تأخذ الطريقة سلسلة من الأحرف التي سيتم إجراء البحث فيها. هذه هي كائنات الفئات التي تنفذ الواجهة CharSequence
. يمكنك تمرير ليس فقط String
، ولكن أيضا StringBuffer
، وكوسيطة . قالب البحث هو كائن الفئة الذي يتم استدعاء الطريقة عليه . مثال على إنشاء المطابق: StringBuilder
Segment
CharBuffer
Pattern
matcher
Pattern p = Pattern.compile("a*b");// compiled the regular expression into a view
Matcher m = p.matcher("aaaaab");//created a search engine in the text “aaaaab” using the pattern "a*b"
الآن، بمساعدة "محرك البحث" الخاص بنا، يمكننا البحث عن التطابقات، ومعرفة موضع التطابق في النص، واستبدال النص باستخدام أساليب الفصل. تبحث الطريقة boolean find()
عن المطابقة التالية في النص مع النمط. باستخدام هذه الطريقة ومشغل الحلقة، يمكنك تحليل النص بأكمله وفقًا لنموذج الحدث (تنفيذ العمليات اللازمة عند وقوع حدث - العثور على تطابق في النص). على سبيل المثال، باستخدام طرق هذه الفئة، int start()
يمكنك int end()
تحديد مواضع التطابق في النص، وباستخدام الطرق String replaceFirst(String replacement)
، String replaceAll(String replacement)
يمكنك استبدال المطابقات في النص بنص بديل آخر. مثال:
public static void main(String[] args) {
String text = "Egor Alla Anna";
Pattern pattern = Pattern.compile("A.+?a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
int start=matcher.start();
int end=matcher.end();
System.out.println("Match found" + text.substring(start,end) + " с "+ start + " By " + (end-1) + "position");
}
System.out.println(matcher.replaceFirst("Ira"));
System.out.println(matcher.replaceAll("Olga"));
System.out.println(text);
}
مخرجات البرنامج: تم العثور على تطابق Alla من 5 إلى 8 مواضع تم العثور على تطابق Anna من 10 إلى 13 موضعًا Egor Ira Anna Egor Olga Olga Egor Alla Anna من المثال، من الواضح أن الأساليب replaceFirst
تنشئ replaceAll
كائنًا جديدًا String
- سلسلة، والتي هو النص المصدر الذي يتم فيه استبدال المطابقات مع القالب بالنص الذي تم تمريره إلى الطريقة كوسيطة. علاوة على ذلك، فإن الطريقة replaceFirst
تحل محل المطابقة الأولى فقط، وجميع replaceAll
التطابقات في الاختبار. يبقى النص الأصلي دون تغيير. يمكن العثور على استخدام أساليب الصنف الأخرى Matcher
، بالإضافة إلى أمثلة التعبيرات العادية، في هذه السلسلة من المقالات . العمليات الأكثر شيوعًا مع التعبيرات العادية عند العمل مع النص هي من الفئات Pattern
ومضمنة Matcher
في ملف String
. هذه طرق مثل split
, matches
, replaceFirst
. replaceAll
ولكن في الواقع، "تحت غطاء محرك السيارة" يستخدمون Pattern
و Matcher
. لذلك، إذا كنت بحاجة إلى استبدال نص أو مقارنة سلاسل في برنامج دون كتابة تعليمات برمجية غير ضرورية، فاستخدم أساليب String
. إذا كنت بحاجة إلى إمكانات متقدمة، ففكر في الفئات Pattern
و Matcher
.
خاتمة
يتم وصف التعبير العادي في برنامج Java باستخدام سلاسل تتطابق مع النمط المحدد بواسطة القواعد. عند تشغيل التعليمات البرمجية، تقوم Java بإعادة ترجمة هذه السلسلة إلى كائن فئةPattern
وتستخدم كائن الفئة Matcher
للعثور على التطابقات في النص. كما قلت في البداية، غالبًا ما يتم وضع التعبيرات النمطية جانبًا لوقت لاحق، حيث يعتبر هذا موضوعًا صعبًا. ومع ذلك، إذا فهمت أساسيات بناء الجملة، والأحرف الأولية، والهروب، ودراسة أمثلة التعبيرات العادية، فقد تبين أنها أبسط بكثير مما تبدو للوهلة الأولى.
GO TO FULL VERSION