لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 09/30/23 في كل الموقع
-
السلام عليكم , ما سبب عدم ظهور الملف الصوتي نهائيا على صفحة الويب ؟ علما ان الملف الصوتي موجود بنفس مجلد الصفحة و ايضا لا يوجد هناك اي error , حتى ان الرسالة your browser... لا يتم طباعتها <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <audio> <source src="maman.mp3" type="audio/mpeg"> <source src="maman.ogg" type="audio/ogg"> <source src="maman.wav" type="audio/mpeg"> your browser does not support this type audio </audio> </body> </html>1 نقطة
-
السلام عليكم. أواجه في التنقل بين الصفحات حيث يتوجب علي تحديث الصفحة كلما أردت الحصول على الصفحة المطلوبة function App() { const user = JSON.parse(localStorage.getItem('user')) return ( <Router> <Routes> <Route path='/' element={user ? <Chat/> : <Navigate to='/login'/>} /> <Route path="/login" element={ !user ? <Login/> : <Navigate to='/' />}/> <Route path="/register" element={ !user ? <Register/> : <Navigate to='/login'/> }/> <Route path= "/*" element={ <NotFound/> }/> </Routes> </Router> ); } في هذا المثال مثلا لا يمكن لصفحة تسجيل الدخول بعد النقر على تسجيل الخروج إلا بعد تحديث الصفحة. كذلك بعد تسجيل الدخول لا يمككن التنقل لصفحة المحادثة إلا بعد تحديث الصفحة Login import React, { useState } from 'react' import { Card, Input, Button, Form } from 'reactstrap' import { Link, useNavigate } from 'react-router-dom'; import Error from '../components/Error'; import axios from 'axios' function Login() { const [error, setError] = useState('') const navigate = useNavigate(); const [formData, setFormData] = useState({ name: '', password: '' }) const { name, password } = formData const onChange = (e) => { setFormData({...formData, [e.target.name]: e.target.value}) } const onSubmit = async e => { e.preventDefault() axios.post('/api/auth/login', formData) .then(res => { localStorage.setItem("user", JSON.stringify(res.data)); navigate("/") }) .catch(error => setError(error.response.data.message)) } return ( <Card className="auth col-lg-3 col-sm-6"> <Form onSubmit={onSubmit}> <img src="" alt="" width="200" /> <h5 className="mb-4"> تسجيل الدخول</h5> <Error error={error} /> <Input value={name} name="name" onChange={onChange} placeholder="الاسم" required autoFocus /> <Input type="password" value={password} name="password" onChange={onChange} placeholder="كلمة المرور" required /> <Button color="primary" block className="mb-3"> {" "} تسجيل الدخول{" "} </Button> <small> <Link to="/register">إنشاء حساب جديد</Link> </small> <p className="m-3 text-muted">© {new Date().getFullYear()}</p> </Form> </Card> ); } export default Login Logout import React, {useEffect} from 'react' import { Row, DropdownItem, DropdownMenu, DropdownToggle, Nav, UncontrolledDropdown} from "reactstrap"; import Avatar from '../Avatar'; import { Navigate, useNavigate } from 'react-router-dom'; function ChatHeader({ receiver, users }) { const navigate = useNavigate() // Find Receiver Avatar const receiverAvatar = users.find(u=> u._id === receiver?._id) // logout const logout = () => { navigate('/login') localStorage.clear() } // useEffect(()=>{ // logout() // }, []) return ( <div> <Row className="heading m-0"> <div // onClick={props.toggle} > <Avatar src={receiverAvatar?.avatar} /> </div> <div className="text-right"> <div>{receiver ? receiver.name : ''}</div> {/* <small>{status()}</small> */} </div> <Nav className="mr-auto" navbar> <UncontrolledDropdown> <DropdownToggle tag="a" className="nav-link"> <i className="fa fa-ellipsis-v" /> </DropdownToggle> <DropdownMenu> <DropdownItem >تغيير كلمة المرور</DropdownItem> <DropdownItem divider /> <DropdownItem onClick={()=>logout()}>تسجيل الخروج</DropdownItem> </DropdownMenu> </UncontrolledDropdown> </Nav> </Row> </div> ) } export default ChatHeader شكرا على المساعدة1 نقطة
-
وانا بعمل الاوفر لاى وبعمله باك جرواند امدج عملت كل الخطوات بالظبط وعملته هايت لكن الباك جرواند مظهرش معرفس ليه #lightboxitem{ background-image: url(photo/img1.jpg); height: 500px; width: 700px; background-position: center; background-size: cover; } ده كود السى اس اس وده كود ال إتش تى ام ال <div id="lightboxcontainer"> <div id="lightboxitem"> </div> المفروض انى بعمل باك جرواند لليت بوكس ايتم واما بتتبع اللينك الخاص بالصورة بيظهرلى ان ف ايرور رغم ان الصورة مكانها واسمها مظبوط1 نقطة
-
المسار النسبي للصورة هو عندما تكون الصورة في ملف منفصل عن ملف الـ CSS يجب أن يكون المسار الذي تستخدمه في ملف الـ CSS معتمدًا على مكان ملف الصورة بالنسبة لملف الـ CSS نفسه على سبيل المثال إذا كان ملف الصورة في نفس المجلد مع ملف الـ CSS يمكنك استخدام اسم الملف فقط كما هو ولكن في حال وجود الصوهرفي مكان اخر غير مكان ملف ال CSS هيتوجب عليك وصف المسار للصوره من بداية من وقوفك عند ملف ال CSS. عندما قمت بنقل الصور من ملف "photo" إلى ملف CSS مباشرة، ربما قد تمكنت من عرض الخلفية بنجاح لأن المسار النسبي للصورة أصبح مباشرًا بالنسبة لملف الـ CSS. هذا هو المقصود بأن الصور يجب أن تكون منتسبة إلى ملف الـ CSS. عندما يكون لديك ملف CSS وملف الصور في نفس المجلد أو في مجلد فرعي من نفس المجلد الذي يحتوي على ملف CSS، يمكنك استخدام مسارات نسبية دون الحاجة إلى تضمين مسارات مطلقة للصور. هذا يسهل الأمور عند نقل المشروع من مكان إلى آخر أو عند مشاركته مع الآخرين. إذا كانت الصور محتفظة في ملف CSS بجوارها أو في مجلد فرعي، فإن المسار النسبي سيظل صحيحًا حتى إذا قمت بنقل المجلد الرئيسي للمشروع إلى مكان آخر. لهذا السبب، يُفضل عادةً استخدام مسارات نسبية للصور والملفات الأخرى لتسهيل إدارة المشروع وتوزيعه.1 نقطة
-
إذا كنت تقوم بإعداد الـ Overlay (التراكب) والـ Background (الخلفية) للـ Lightbox بالشكل الصحيح ولا ترى الصورة عند فتح الـ Lightbox، فإن هناك بعض الأسباب التي يمكن أن تكون وراء هذه المشكلة. إليك بعض الأمور التي يجب التحقق منها: التحقق من مسار الصورة: تأكد من أن مسار الصورة الموجود في ملف الـ CSS (img1.jpg) صحيح ويشير إلى الموقع الصحيح للصورة. يجب أن يكون المسار نسبيًا إلى ملف الـ CSS. إذا كان ملف الصورة في نفس المجلد مع ملف الـ CSS، فيمكنك استخدام اسم الملف فقط دون أي مسار. التحقق من تنسيق الصورة: تأكد من أن الصورة img1.jpg تحتوي على تنسيق صورة صالح مثل JPEG أو PNG. إذا كانت تصيغة الصورة غير صالحة، فإنها قد لا تعرض بشكل صحيح. التحقق من الأبعاد: قد يكون هناك تداخل في الأبعاد والأحجام المحيطة بالصورة والعناصر المحيطة بها في الـ Lightbox. تأكد من أن ارتفاع (height) وعرض (width) الـ Lightbox نفسهما معقولين وقد تم تعيينهما بشكل صحيح. يمكنك استخدام الـ inspect لمتابعة العناصر وفحص اذا كان المشكله فقط موجوده في الخلفيه ام ان من الاساس العنصر لا يظهر.1 نقطة
-
1 نقطة
-
السلام عليكم أكاديمية حسوب انا الان متدرب في الخطوط السعودية (قسم IT) وغدًا ان شاء الله المدرب سيأخذنا بجوله لمركز البيانات حيث توجد السيرفرات الان كيف استفيد من هاذي الجولة والتدريب و ما الأسئلة الذي يجب علي طرحها للمدرب وما الأمور الذي يجب انا اعرفها1 نقطة
-
وعليكم السلام بصراحة لديك فرصة رائعة فمثل هذه الزيارات مهمة جداً لذلك بالفعل يجب عليك استغلال هذه الفرصة لطرح الأسئلة والمعرفة أكثر حول مركز البيانات. كما أنه يمكنك أنت أن توضع أسئلتك الخاصة حول ما تعملته في مجالك . وهناك بعض الأمور التي يمكنك السؤال عنها مثل :- أمان المركز :- ما هي التدابير الازمة التي يتم اتخاذها لحماية المركز من الاختراق ؟ التبريد والطاقة :- مثلاً كيف يتم تبريد الخوادم في المركز ؟ ومن أين تأتي الطاقة الكهربائية المستخدمةفي المركز وأهم الاستراتيجيات لتحسين كفاءة استهلاك الطاقة ؟ إدارة السيرفرات:- ما هي التقنيات المستخدمة لإدارة السيرفرات ؟ كيف يتم الاحتفاظ بالبيانات والنسخ الاحتياطية ؟ التخزين :- ما هو نوع وسعة الأقراص التخزينية المستخدمة في المركز ؟ وهل يتوفر استراتيجيات تخزين سحابي داخل المركز ؟ هذه بعض أهم الأسئلة التي ممكن أن تسأل عنها في مركز البيانات .1 نقطة
-
السلام عليكم اريد أتعلم مجال تعليم الاله ماد تنصحوني ؟ وهل المجال صعب يعني فيه تفاصيل كثير وكده؟1 نقطة
-
وعليكم السلام، اختيارك لمجال تعلم الآلي اختيار موفق، لأنه من أهم المجالات الموجودة الآن وله مستقبل كبير. وبالنسبة إلى صعوبة المجال فهذه الإجابة تعتمد علي اهتماماتك وقدراتك أنت، إذا كنت جديد في مجال البرمجة وعلوم الحاسب، فقد تجد بعض المفاهيم صعبة في البداية. ومع ذلك، مع الممارسة، يمكنك إتقان المفاهيم الأساسية وتعلم خوارزميات تعلم الآلة المتقدمة. وهذه مجموعة مقالات سوف تساعدك علي التعرف علي المجال اكثر :-1 نقطة
-
استراتيجية جذب العملاء تتوقف علي طبيعة العمل أو الخدمة التي تقدمها، ولكن هناك قواعد عامة لجذب العملاء في جميع المجالات منها:- تقديم قيمة حقيقية وجوده عالية. تواصل مع العملاء المحتملين واعرض عليعهم خدماتك. استغل منصات التواصل للترويج لخدماتك أو منتجاتك. حاول تطوير خدماتك بشكل مستمر. قدم شيء مميز ومختلف عن الآخرين. وهذه مقالات سوف تساعدك في التعرف على استراتيجيات جذب العملاء:-1 نقطة
-
لماذا لايغلق الاسكريبت عند n ما هو الخطأ while True : repeat = input ("Do you want to peform another oparation (y/n): \n").lower() if repeat == "y" : break elif repeat == "n" : print("exit") quit else : print("invalid choice")1 نقطة
-
في العمل الحر وخصوصاً للمستقلين، هناك العديد من الاستراتيجيات التي يمكنك اتباعها لجذب العملاء الجدد. بعض من الاستراتيجيات الفعّالة:- إنشاء ملف شخصي قوي على منصات التوظيف الحر قم بإنشاء ملف شخصي مميز على منصات مثل Upwork أو Freelancer أو Fiverr تبرز فيه خبرتك ومهاراتك. ضع عينة من أعمالك السابقة وقدم تقييمات إيجابية من العملاء السابقين إذا كان ذلك ممكنًا. بناء حضور على الإنترنت قم بإنشاء موقع ويب شخصي يعرض خدماتك وأعمالك السابقة. كن نشطاً على وسائل التواصل الاجتماعي المهنية مثل LinkedIn وشارك محتوى ذو قيمة في مجالك. 3. توظيف استراتيجيات التسويق الشخصي: - استخدم شبكتك الشخصية للتعريف بخدماتك وطلب الإحالات من أصدقائك وزملائك. - قم بتطوير خطة تسويق شخصية تتضمن إرسال بريد إلكتروني للعملاء المحتملين والمتابعة معهم بانتظام. الاستثمار في التعليم وتطوير المهارات تواصل بتعلم مهارات جديدة وتحسين مهاراتك الحالية لتقديم خدمات عالية الجودة. توثيق مهاراتك بشهادات معترف بها. تقديم خدمات مجانية أو بأسعار مخفضة في البداية قدم خدمات مجانية أو بأسعار منخفضة للعملاء الأولين لجذبهم وكسب ثقتهم. بمرور الوقت ومع التقديم الممتاز، ستتمكن من زيادة أسعار خدماتك. الاستفادة من منصات التوظيف المحلية ابحث عن فرص عمل حر على المنصات المحلية أو في الأسواق المحلية. شارك في أحداث محلية أو معارض تجارية لبناء علاقات مع العملاء المحتملين. طور استراتيجية تسعير ملائمة حدد أسعار تنافسية وملائمة لمستوى خدماتك ولسوق العمل المحلي. قدم خيارات تسعير مختلفة لتلبية احتياجات مختلفة للعملاء. جمع التقييمات والشهادات اطلب من العملاء السعداء تقديم تقييمات إيجابية وشهادات عن خدماتك واعتمادها على موقعك أو ملفك الشخصي. النجاح في العمل الحر يحتاج إلى الصبر والتفاني، وغالباً ما يحتاج الأمر إلى بعض الوقت قبل أن تبدأ في جذب العملاء الجدد بشكل منتظم.1 نقطة
-
1 نقطة
-
تعرَّف التعابير النمطية بأنها مجموعات من المحارف التي تصف مجموعةً أخرى من المحارف أكبر منها، وهي تصف نمط المحارف الذي نستطيع البحث عنه في متن نص ما، وهي تشبه مفهوم المحارف البديلة wildcards المستخدمة في تسمية الملفات على أغلب نظم التشغيل، حيث يمكن استخدام محرف النجمة * لتمثيل أي تسلسل من المحارف في اسم ملف، ولهذا فإن *.py تعني أي ملف ينتهي بالامتداد .py، بل إن المحارف البديلة ما هي إلا مجموعة فرعية صغيرة من التعابير النمطية. وتدعم أغلب لغات البرمجة الحديثة التعابير النمطية ضمنيًا، أو لديها مكتبات أو وحدات متاحة للاستخدام في البحث عن النصوص واستبدالها وفقًا لتعابير نمطية، وذلك بسبب الإمكانيات الكبيرة لهذه التعابير، لكن شرحها المفصل هو خارج نطاق حديثنا، وستجد مصادر أخرى تتحدث عنها بتوسع شديد، وننصحك هنا بمراجعة كتب مثل كتاب أورايلي في التعابير النمطية وهو باللغة الإنجليزية، إضافةً إلى المقالات الموجودة في أكاديمية حسوب. ولعل إحدى الخصائص المميزة للتعابير النمطية هي أنها تُظهر أوجه التشابه مع البرامج في البنية، فهي أنماط مبنية من وحدات أصغر منها، وتلك الوحدات هي: محارف منفردة. محارف بديلة. نطاقات أو مجموعات من المحارف، أو مجموعات محاطة بأقواس. وبما أن المجموعة نفسها ما هي إلا وحدة، فيمكن أن تكون لدينا مجموعات من المجموعات إلى أن نصل إلى مستوى تعقيد كبير، ونستطيع جمع تلك الوحدات بطرق تشبه استخدام التسلسلات أو التكرارات أو العوامل الشرطية في لغات البرمجة، وسننظر في كل منها في حينه، فإضافةً إلى شرح مفهوم التعابير النمطية، سنعرف كيف نستخدمها في برامج بايثون، وننظر كيف تدعمها لغتا VBScript وجافاسكربت، ولنستطيع تجربة الأمثلة هنا يجب أن نستورد وحدة re ونستخدم التوابع الخاصة بها، وسنفترض أنك استوردتها تلقائيًا دون ذكر ذلك في كل مرة. التسلسلات تسلسلات المحارف لا شك أن أبسط بنية برمجية يمكن تصورها هي تسلسل من المحارف، كما أن أبسط تعبير نمطي ما هو إلا تسلسل من المحارف كذلك: red وهذا سيطابق أو يبحث في سلسلة نصية عن أي حدوث لهذه الأحرف الثلاثة التي تتكون منها كلمة red على الترتيب، وبناءً على ذلك سيجد كلمات مثل red وlettered وcredible، لأنها تحتوي على كلمة red ضمنها. ولنتحكم أكثر في خرج المطابقات، فإننا نوفر بعض المحارف الخاصة التي تُعرف باسم المحارف الوصفية metacharacters للحد من نطاق البحث: table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } التعبير المعنى مثال ^red في بداية السطر فقط red ribbons are good red$ في نهاية السطر فقط I love red \Wred في بداية الكلمة فقط it's redirected by post red\W في نهاية الكلمة فقط you covered it already يُطلق على هذه المحارف اسم المرابط anchors لأنها تثبت موضع التعبير النمطي في جملة أو كلمة ما، وهناك عدة مرابط أخرى معرَّفة في توثيق وحدة re يمكنك الاطلاع عليها. المحارف البديلة قد تحتوي التسلسلات على محارف بديلة Wildcard Characters تحل محل أي محرف، والمحرف البديل هو نقطة . جرِّب الشيفرة التالية مثلًا: >>> import re >>> re.match('be.t', 'best') <_sre.SRE_Match object at 0x01365AA0> >>> re.match('be.t', 'bess') تخبرنا الرسالة التي في الأقواس السهمية أن التعبير النمطي 'be.t' -الممرَّر وسيطًا أول- يطابق السلسلة 'best' الممرَّرة وسيطًا ثانيًا، كما يطابق 'beat' و'bent' و'belt' وغيرها، لكن المثال الثاني لا يطابق لأن 'bess' لا تنتهي بحرف t، لذا لا يُنشئ MatchObject. يمكنك تجريب عدة مطابقات أخرى لتفهم كيفية عملها، ولاحظ أن match() لا تطابق إلا في بداية السلسلة النصية، أما لمنتصفها فنستخدم search() كما سنرى لاحقًا. المجالات أو الفئات يتكون المجال range (أو الفئة set) من تجميعة من المحارف المغلَّفة في أقواس مربعة، ويبحث التعبير النمطي عن أي محرف يكون داخل هذه الأقواس: >>> re.match('s[pwl]am', 'spam') <_sre.SRE_Match object at 0x01365AD8> فهذا سيطابق swam أو slam، لكن لن يطابق sham لأن h غير موجودة في فئة التعبير النمطي. أما إذا وضعنا محرف الإقحام ^ أول عنصر في المجموعة، فكأننا نقول أننا نريد البحث عن أي محرف عدا المحارف الموجودة في المجموعة: >>> re.match('[^f]ool', 'cool') <_sre.SRE_Match object at 0x01365AA0> >>> re.match('[^f]ool','fool') وبناءً على ذلك نستطيع مطابقة cool وpool، لكننا لن نطابق fool لأننا نبحث عن أي محرف عدا f في بداية النمط. المجموعات نستطيع جمع تسلسلات من المحارف أو الوحدات الأخرى معًا من خلال تغليفها بأقواس، وهي لا تقوم بدور العزل هنا، بل تفيدنا عند دمجها مع خصائص التكرار والشرطيات التي سنشرحها لاحقًا. التكرار يمكن إنشاء تعابير نمطية تطابق تسلسلات مكررةً من المحارف باستخدام بعض المحارف الوصفية الخاصة، ونستطيع البحث بها عن تكرار محرف واحد أو مجموعة محارف: التعبير المعنى مثال '?' محرف واحد على الأكثر من المحارف السابقة -أي عدد صفر أو واحد من المحارف-، انتبه إلى الجزء الصفري هنا لأنه قد يربكك. pythonl?y يطابق: pythony وpythonly '*' يبحث عن صفر محرف سابق أو أكثر. pythonl*y يطابق ما ذكر في السطر السابق بالإضافة إلى: pythonlly وpythonllly ... إلخ '+' يبحث عن محرف واحد أو أكثر من المحارف السابقة. pythonl+y يطابق: pythonly وpythonlly وpythonllly ...إلخ {n,m} يبحث عن نطاق من التكرارات من n إلى m من المحارف السابقة. { fo{1,2 يطابق : fo أو foo يمكن تطبيق جميع محارف التكرار هذه على مجموعات أخرى من المحارف، وبناءً عليه: >>> re.match('(.an){1,2}s', 'cans') <_sre.SRE_Match object at 0x013667E0> يكون النمط هنا (.an){1,2}s الذي يقول إن لدينا مجموعةً تتكون من أي محرف متبوع بالحرفين an، ونريد أن نجد مجموعةً أو اثنتين متبوعتين بالحرف s، وسيطابق هذا النمط: cancans وpans وcanpans، لكن لن يطابق bananas لانعدام وجود حرف قبل مجموعة an الثانية فيها. جرب تعديل البحث ليطابق bananas. هناك مشكلة واحدة مع نمط التكرار {m,n}، وهو أنه لا يحد المطابقة لعدد n من الوحدات، وعلى ذلك سيطابق مثال {fo{1,2 الذي في الجدول السابق fooo لأنه يطابق foo في بداية fooo، وعليه فإذا أردنا الحد من عدد المحارف المطابَقة، فسنحتاج إلى أن نُتبع تعبير الضرب بمرساة أو نطاق نفي negated range. وفي حالتنا، فإن [fo{1,2}[^o سيمنع fooo من المطابقة بما أنه يقول طابق حرف o واحد أو حرفين متبوعين بأي شيء غير o، لكن يجب أن يكون متبوعًا بشيء ما، لذا فإن foo لم تَعُد مطابقةً الآن. يوضح هذا الطبيعة المتقلبة للتعابير النمطية، فقد يصعب ضبطها للحصول على الخرج الذي نريده، ويجب أن نضعها تحت اختبارات فاحصة لتجنب الأخطاء. أما النمط الفعلي المطلوب للسماح بمطابقة foo وfoobar مع استثناء fooo، فهو 'fo{1,2}[^o]*$'، وهذا يعني fo أو foo المتبوعين بعدد صفر أو أكثر من حروف o ونهاية السطر، وفي الواقع حتى هذا النمط ليس تامًا وخاليًا من الأخطاء -جرب fooboo مثلًا-، لكن نحتاج أن نشرح بعض العناصر الأخرى قبل أن نحسّنه ونعدل فيه. التعابير الجشعة يقال إن التعابير النمطية جشعة، أي أن دوال البحث والمطابقة ستطابق كل ما تستطيعه من السلسلة النصية، بدلًا من التوقف عند أول مطابقة تامة، وهذا لا يهم غالبًا، لكننا سنحصل على مطابقات أكثر من المطلوب عند جمع المحارف البديلة مع عوامل التكرار. لننظر في المثال التالي: إذا كان لدينا تعبير نمطي مثل a.*b الذي يقول إننا نريد إيجاد a متبوعًا بأي عدد من المحارف إلى أن نصل إلى حرف b، فستبحث دالة المطابقة من أول a إلى آخر b، مما يعني أنه إذا احتوت سلسلة البحث على أكثر من b فستُضمَّن جميعًا في الجزء *. من التعبير عدا آخر واحدة، وعليه: re.match('a.*b','abracadabra') فقد طابق MatchObject في هذا المثال كل abracadab وليس أول ab فقط، وسلوك المطابقة الجشع هذا هو أكثر الأخطاء التي يرتكبها المبرمج في بداية استخدامه للتعابير النمطية، ولمنع هذا السلوك الجشع نضيف '?' بعد محرف التكرار، كما يلي: re.match('a.*?b','abracadabra') مما سيطابق ab فقط. الشرطيات يتبقى لدينا الآن أن نجعل التعبير النمطي يبحث في عناصر اختيارية أو يختار نمطًا من بين عدة أنماط، وسننظر في كل منها على حدة. العناصر الاختيارية يمكن تحديد محرف ما ليكون اختياريًا باستخدام عدد صفر أو أكثر من محارف التكرار الوصفية: >>> re.match('computer?d?', 'computer') <re.MatchObject instance at 864890> هذا سيطابق compute وcomputer وcomputed، كما سيطابق computerd، لكننا لا نريد هذه الأخيرة، لذا سنضيق النطاق الذي نريده كما يلي: >>> re.match('compute[rd]$','computer') <re.MatchObject instance at 874390> وهذا سيختار computer وcomputed فقط، ويرفض computerd، وإذا أضفنا ? بعد هذا النطاق فسنسمح باختيار compute مع تجنب computerd أيضًا. التعابير الاختيارية بالإضافة إلى خيارات المطابقة من قائمة محارف السابقة الذكر، يمكن المطابقة بناءً على اختيار من تعابير فرعية، فقد ذكرنا سابقًا أننا نستطيع جمع تسلسلات من المحارف في أقواس، لكن الواقع أننا نستطيع جمع أي تعبير نمطي عشوائي بين أقواس ومعاملته مثل وحدة، وسنستخدم الصيغة (RE) أثناء شرح التركيب اللغوي هنا للإشارة إلى أي تجميع لتعابير نمطية، والحالة التي نريد دراستها هنا هي مطابقة تعبير نمطي يحتوي على (RE)xxxx أو (RE)yyyy حيث تكون xxxx وyyyy أنماطًا مختلفةً، وبناءً عليه فإذا أردنا مطابقة premature وpreventative فسنفعل هذا بواسطة محرف الاختيار الوصفي |: >>> regexp = 'pre(mature|ventative)' >>> re.match(regexp,'premature') <re.MatchObject instance at 864890> >>> re.match(regexp,'preventative') <re.MatchObject instance at 864890> >>> re.match(regexp,'prelude') نلاحظ أنه عند تعريف التعبير النمطي تعين علينا أن ندرج النص الكامل لكلا الخيارين داخل أقواس بدلًا من (e|v)، ولو لم نفعل لاقتصر الخيار على prematureentative وprematurventative فقط، أي كان الحرفان فقط هما اللذان سيمثلان الخيارات المتاحة، وليس المجموعات كلها. نستطيع الآن باستخدام هذه التقنية أن نعود إلى المثال أعلاه الذي أردنا فيه التقاط fo أو foo وتجنب التقاط fooo إضافةً إلى أي شيء يأتي بعدها، وقد تركناها مع تعبير نمطي يتكون من fo{1,2}[^o]*$، والمشكلة هنا أن التطابق سيفشل إذا احتوت السلسلة النصية التالية لـ fo أو foo على o، لكن يمكن الالتفاف على ذلك باستخدام عدة خيارات من التعبيرات، ونريد أن ينجح التطابق سواء كان النمط في نهاية السطر أو متبوعًا بأي حرف سوى o، وسيبدو ذلك كما يلي: fo{1,2}($|[^o]) والذي سيعطينا أخيرًا ما نريده، تجدر الإشارة إلى أنه يجب تنفيذ اختبارات كافية عند استخدام التعابير النمطية، لضمان عدم التقاط أي شيء غير مرغوب فيه، وأننا نلتقط كل ما نريد التقاطه. المزيد من الملاحظات حول التعابير النمطية تحتوي وحدة re على مزايا كثيرة لم نذكرها هنا، يجدر النظر فيها ودراستها من توثيق الوحدة نفسها، لكننا نريد تسليط الضوء على مجموعة من الرايات flags التي يمكن استخدامها عند تصريف التعبيرات مع دالة re.compile()، والتي تتحكم في أمور مثل مطابقة النمط في الأسطر المختلفة، أو تجاهله لحالة الأحرف، أو غير ذلك. ومن المهم استخدام أداة تختبر التعابير النمطية للتحقق من نتائجها، وتوجد أدوات عديدة منها على الويب، لكن نخص بالذكر منها أداة regex101، حيث نكتب فيها تعبيرًا نمطيًا وسلسلة اختبار، ثم نرى الأجزاء التي طابقها التعبير من السلسلة النصية، وهذه الأداة تحديدًا تعطينا وصفًا مفيدًا عما يفعله التعبير النمطي، وتسمح لنا باختيار أصناف فرعية للمطابَقات الناتجة، وغيرها من المزايا المفيدة. استخدام التعابير النمطية في بايثون رأينا في السطور السابقة شيئًا يسيرًا من التعابير النمطية، ونريد أن نطبق ذلك في بايثون، حيث نستطيع استخدامها أداة بحث قويةً جدًا في النصوص، إذ يمكن البحث عن صور كثيرة مختلفة لسلاسل نصية في عملية واحدة، بل يمكن البحث عن المحارف التي لا تُطبع مثل الأسطر الفارغة باستخدام بعض المحارف الوصفية المتاحة، كما يمكن استبدال هذه الأنماط باستخدام التوابع والدوال الخاصة بوحدة re، كما رأينا في دالة match() أعلاه، وفيما يلي بعض الدوال الأخرى المتاحة: الدالة - التابع التأثير (match(RE,string يعيد كائن مطابقة إذا طابق التعبير النمطي بداية السلسلة. (search(RE,string يعيد كائن مطابقة إذا وُجد تعبير نمطي في أي مكان في السلسلة النصية. (split(RE, string مثل string.split() لكن يستخدم تعبيرًا نمطيًا مثل فاصل. (sub(RE, replace, string تعيد سلسلةً نصيةً أُنتجت عن طريق استبدال لـ re في أول مطابقة للتعبير النمطي، وهذه الدالة لها مزايا أخرى إضافية، انظر توثيقها للمزيد. (findall(RE, string تبحث عن جميع مرات حدوث التعبير النمطي في سلسلة نصية، وتعيد سلسلةً من كائنات المطابقة. (compile(RE تنتج كائن تعبير نمطي يمكن إعادة استخدامه لعدة عمليات مع نفس التعبير النمطي، ويكون للكائن جميع التوابع أعلاه لكن مع re مضمَّنة، ويكون أكثر كفاءةً من النسخ الخاصة بالدالة. لا شك أن هذه القائمة لا تحتوي جميع توابع re ودوالها، كما أن التوابع التي ذكرناها في الجدول لها معامِلات اختيارية لتوسيع استخدامها، واخترناها لأنها أكثر العمليات استخدامًا، ومناسبةً لاحتياجاتنا. مثال عملي على التعابير النمطية لننشئ برنامجًا يبحث في ملف HTML عن وسم IMG ليس له قسم ALT، فإذا وجدنا واحدًا فسنضيف رسالةً إلى المالك ليكتب ملفات HTML أفضل في المستقبل. import re # لنسمح بصفر مسافة أو أكثر بين img أو IMG التقط # < و I img = '< *[iI][mM][gG] ' # alt أو ALT السماح بأي عدد من المحارف حتى before > alt = img + '.*[aA][lL][tT].*>' # افتح الملف واقرأه في قائمة filename = input('Enter a filename to search ') inf = open(filename,'r') lines = inf.readlines() # ALT بدون IMG إذا احتوى السطر على وسم # HTML فأضف رسالتنا كتعليق for index,line in enumerate(lines): if ( re.search(img,line) and not re.search(alt,line) ): lines[index] += '<!-- PROVIDE ALT TAGS ON IMAGES! -->\n' # والآن اكتب الملف المعدَّل. inf.close() outf = open(filename,'w') outf.writelines(lines) outf.close() لدينا ملاحظتان على الشيفرة أعلاه نريد الإشارة إليهما، الأولى أننا استخدمنا re.search بدلًا من re.match، لأن الأولى تبحث عن الأنماط في أي مكان داخل السلسلة النصية، بينما تبحث الثانية في بداية السلسلة فقط، أما الملاحظة الثانية فهي أننا وضعنا زوجًا خارجيًا من الأقواس حول الاختبارين، وهو أمر غير ضروري لكنه يسمح لنا بتقسيم الاختبار إلى سطرين، مما يجعله أسهل في القراءة خاصةً إذا كنا سندمج تعبيرات كثيرةً. وهذه الشيفرة ليست مثاليةً لأنها لا تأخذ في الحسبان الحالة التي يكون وسم img فيها مقسمًا على عدة أسطر، لكنها تكفي لشرح التقنية عمومًا، على أنه يُفضل تجنب هذا "التخريب" الذي قمنا به في ملف HTML، لكن الذي ينسى وسوم alt يستحق جزاءه. نأتي لأمر أخير، وهو حدود كفاءة التعابير النمطية، فلهياكل البيانات المعرَّفة بوضوح -مثل HTML- أدوات أخرى غير التعابير النمطية، تُعرف باسم المحلِّلات تكون أكثر كفاءةً وأسهل في الاستخدام دون أخطاء، وسنستخدم محلل HTML في جزئية لاحقة من هذه السلسلة، وتتجلى فائدة التعابير النمطية في عمليات البحث المعقدة في النصوص الحرة إذ تحل لنا مشاكل كثيرة، مع التأكيد مرةً أخرى على الاختبار المفصل لها، كما لا يجب استخدامها إلا عند الحاجة الضرورية إليها، أما إذا كنا نريد البحث عن سلسلة بسيطة فنستخدم التابع find، لتجنب مشاكل التعابير النمطية. وسنعود مرةً أخرى إلى التعابير النمطية في دراسة الحالة لعدّاد القواعد النحوية، لذا جرب استخدامها حتى ذلك الحين، وتفقد التوابع الأخرى الموجودة في وحدة re، فلم نشرح حتى الآن إلا قشور هذه الأدوات بالغة القوة في معالجة النصوص. التعابير النمطية في جافاسكربت تدعم جافاسكربت التعابير النمطية ضمنيًا وبقوة، بل إن عمليات البحث في السلاسل النصية التي استخدمناها من قبل ما هي إلا بحوث تعابير نمطية، فقد استخدمنا أبسط صورة لها "تسلسل بسيط من المحارف"، وتنطبق جميع القواعد التي ذكرناها في بايثون على جافاسكربت، عدا أن التعابير النمطية هنا تكون محاطةً بشرطة مائلة / بدلًا من علامات الاقتباس: <script type="text/javascript"> var str = "A lovely bunch of bananas"; document.write(str + "<BR>"); if (str.match(/^A/)) { document.write("Found string beginning with A<BR>"); } if (str.match(/b[au]/)) { document.write("Found substring with either ba or bu<BR>"); } if (!str.match(/zzz/)) { document.write("Didn't find substring zzz!<BR>"); } </script> ينجح التعبيران الأولان ويفشل الثالث، لذا حصلنا على الاختبار السلبي، لاحظ علامة التعجب في البداية. التعابير النمطية في VBScript لا تحتوي VBScript على دعم مضمّن للتعابير النمطية كما في جافاسكربت، لكن فيها كائن تعبير نمطي يمكن بدؤه واستخدامه للبحث وعمليات الاستبدال وغيرها، كما يمكن التحكم فيه لتجاهل حالة الأحرف وللبحث في جميع النسخ أو نسخة واحدة فقط: <script type="text/vbscript"> Dim regex, matches Set regex = New RegExp regex.Global = True regex.Pattern = "b[au]" Set matches = regex.Execute("A lovely bunch of bananas") If matches.Count > 0 Then MsgBox "Found " & matches.Count & " substrings" End If </script> نكون بهذا قد وصلنا إلى نهاية هذا المقال مكتفين بما ذكرناه فيه، لكن نعيد التأكيد على أن التعابير النمطية غنية بالتعقيدات الدقيقة التي لا يمكن تغطيتها في هذا المقال القصير، ويمكن الرجوع إلى المصادر الموجودة في الويب لمزيد من المعلومات عن استخدامها، إضافةً إلى كتاب أورايلي الذي أوردناه في بداية المقال. خاتمة بنهاية هذا المقال نود أن تكون قد تعلمت: التعابير النمطية هي أنماط نصية تستطيع تطوير قوة وكفاءة عمليات البحث النصية. يصعب التحكم بالتعابير النمطية، وقد تتسبب في زلات برمجية غريبة، لذا يجب التعامل معها بحرص. التعابير النمطية ليست الحل السهل لكل مشكلة، بل قد يكون الحل في منظور أكثر تعقيدًا، فإذا لم ينجح استخدام التعابير النمطية في حل مشكلة لثلاث محاولات متتالية، فيجب البحث عن حل آخر. ترجمة -بتصرف- للفصل السادس عشر: Regular Expressions من كتاب Learn To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: البرمجة كائنية التوجه المقال السابق: فضاءات الأسماء في البرمجة ما هي البرمجة ومتطلبات تعلمها؟ تعلم البرمجة التعابير النمطية (regexp/PCRE) في PHP1 نقطة