اذهب إلى المحتوى

توابع السلاسل النصية في لغة روبي


Hassan Hedr

تحتوي السلاسل النصية في لغة روبي على العديد من التوابع ضمنها والتي تسهل العديد من العمليات الشائعة على السلاسل النصية سنتعرف عليها في هذا المقال، والتي تفيد مثلًا في تحديد طول السلسلة النصية أو تقسيمها واستخراج أجزاء منها، أو إضافة وإزالة المسافات البيضاء whitespace والأحرف الأخرى منها، أو تغيير حالة الأحرف فيها، أو البحث عن نص معين فيها واستبداله بآخر، لينتج عن استخدام تلك التوابع مزايا قوية يمكن الاستفادة منها لحل العديد من المشاكل.

تحديد طول سلسلة نصية

تحتوي السلاسل النصية على التابع length والذي يُعيد عدد الأحرف في السلسلة النصية، فمثلًا يمكن الاستفادة من ذلك التابع لتحديد الحد الأدنى أو الأقصى لطول كلمة المرور في نظام ما والعديد من الاستخدامات، والمثال التالي يوضح طول سلسلة نصية مُخزنة ضمن متغير ويطبع النتيجة:

open_source = "Sammy contributes to open source."
print open_source.length

ليكون الخرج على النحو التالي:

33

يجب التأكيد على أن كل المحارف ضمن السلسلة النصية بما في ذلك الحروف والأرقام والمسافات والرموز مأخوذة بالحسبان ضمن طول السلسلة النصية، ولمعرفة ما إذا كانت السلسلة النصية فارغة يمكن مقارنة طولها والتأكد بأنه يساوي الصفر 0، أو يمكن استخدام التابع المخصص لذلك وهو ?empty على النحو التالي:

name = ""
name.empty? # true

name = "Sammy"
name.empty? # false

name = " "
name.empty? # false

سنتعرف في الفقرة التالية على طريقة الوصول إلى المحارف ضمن السلسلة النصية.

الوصول إلى المحارف ضمن السلسلة النصية

توفر لغة روبي التابع slice، الذي يفيد في استخراج جزء من السلسلة النصية. يُشار لكل محرف ضمن السلسلة النصية برقم الفهرس لها وهو رقم يبدأ ترتيبه من الصفر 0، تمامًا كما هو الحال بالنسبة للمصفوفات arrays في روبي، فمثلًا رقم الفهرس للمحارف في السلسلة النصية Sammy هو:

4 3 2 1 0
y m m a S

يسمح التابع slice بالوصول إلى محرف واحد أو مجال من المحارف، فعند تمرير رقم صحيح واحد غليه سيُعيد المحرف الموجود في رقم الفهرس المحدد، وعند تمرير رقمين صحيحين مفصولين بفاصلة سيُعيد هذا التابع جميع المحارف بدءًا من رقم الفهرس الأول وحتى رقم الفهرس الثاني، ويمكن تمرير نطاق من الفهارس مثلًا من واحد إلى أربعة 4..1 لاستخراج الحروف الموجودة ضمن هذا النطاق:

"Sammy".slice(0) # "s"
"Sammy".slice(1,2) # "am"
"Sammy".slice(1..4) # "ammy"

ويمكن استخدام الصيغة [] والتي هي مرادف للتابع slice ليصبح شكل التعامل مع السلاسل النصية مشابه للمصفوفات:

"Sammy"[0] # "s"
"Sammy"[1,2] # "am"
"Sammy"[1..4] # "ammy"

يمكن الوصول إلى المحارف في نهاية السلسلة النصية باستخدام رقم فهرس سالب، فمثلًا الفهرس 1- يعيد المحرف الأخير من السلسلة النصية، والفهرس 2- يعيد المحرف ما قبل الأخير وهكذا، ويمكن تحويل سلسلة نصية إلى مصفوفة تحتوي على المحارف المكونة لها باستخدام التابع chars على النحو التالي:

"sammy".chars # ["S", "a", "m", "m", "y"]

يمكن استخدام هذه الطريقة للتعديل على محارف السلسلة النصية، وسنتعرف في الفقرة التالية على طريقة تغيير حالة الأحرف ضمن السلسلة النصية.

تعديل حالة الأحرف

يمكن استخدام التابع upcase لتحويل جميع الحروف الأجنبية في السلسلة النصية إلى أحرف كبيرة، والتابع downcase لتحويل جميع الحروف الأجنبية في السلسلة النصية إلى أحرف صغيرة، وتبقى الحروف بغير اللغة الإنجليزية كما هي دون تغيير. سنعدّل في المثال التالي السلسلة النصية "Sammy Shark" إلى حروف كبيرة:

name = "Sammy Shark"
print name.upcase
SAMMY SHARK

ليكون الخرج على النحو التالي:

SAMMY SHARK

ولنختبر تحويلها إلى أحرف صغيرة:

print name.downcase

سيكون الخرج هنا:

sammy shark

يسهّل استخدام التابعين upcase و downcase لمقارنة السلاسل النصية مع بعضها عن طريق توحيد حالة الأحرف قبل المقارنة، فمثلًا عند إدخال اسم مستخدم في برنامج ما من قِبل المستخدم بأحرف كبيرة، فيمكن تحويل القيمة المُدخلة إلى حروف صغيرة ثم مقارنتها القيم الموجودة ضمن النظام بأحرف صغيرة. توفر روبي أيضًا التابع capitalize، الذي يعيد نسخةً جديدةً من السلسلة النصية مع تحويل الحرف الأول منها إلى حرف كبير:

"sammy".capitalize # "Sammy"

وتوفر روبي أيضًا التابع swapcase والذي يعيد نسخةً جديدةً من السلسلة النصية مع تبديل حالة كل الأحرف فيها:

text = "Sammy"
print text.swapcase

وسيكون الخرح في هذه الحالة:

sAMMY

تعيد التوابع downcase و upcase و capitalize و swapcase نسخةً جديدةً من السلسلة النصية وتترك السلسلة الأصلية دون تغيير، ويتوضح ذلك عند التعديل على قيمة سلسلة نصية مُخزنة ضمن متغير ما، فتبقى القيمة ضمن المتغير كما هي دومًا دون تغيير في حال لم نسنِد القيمة الجديدة مجددًا إلى المتغير:

text = "sammy"
text.capitalize

print "Hello, #{text}!"

ويكون الخرج على النحو التالي:

Hello, sammy!

على الرغم من استخدامنا للتابع capitalize على المتغير text في المثال السابق، وبما أننا لم نخزن القيمة المُعادة من capitalize مجددًا داخل المتغير text، فقيمة المتغير text لم تتغير، ولتغييرها يمكن إعادة كتابة الشيفرة السابقة بالشكل التالي لحل هذه المشكلة:

text = "sammy"
text = text.capitalize

print "Hello, #{text}!"

ويكون الخرح:

Hello, Sammy!

يمكن استخدام التوابع !downcase و !upcase و !capitalize و !swapcase (لاحظ انتهاء أسمائها بالمحرف !) للتعديل على قيمة السلسلة النصية الأصلية بدلًا من إنشاء سلسلة جديدة:

text = "sammy"
text = text.capitalize!

print "Hello, #{text}!"

ويجب الانتباه عند التعديل على قيمة السلسلة النصية الأصلية؛ فقد تعدّل قيمة سلسلة نصية في مكان ما ضمن البرنامج دون الانتباه إليه ما يؤدي لمشاكل، وسنتعرف في الفقرة التالية على طريقة إضافة وإزالة المسافات البيضاء من السلاسل النصية.

إضافة وإزالة المسافات البيضاء الفارغة

يمكن إضافة المسافات قبل أو بعد أو على كلا طرفي السلسلة النصية لتعديل تنسيقها قبل طباعتها مثلًا، وقد نحتاج أحيانًا لإزالة الأحرف غير الضرورية من بداية أو نهاية السلاسل النصية مثل المسافات الزائدة أو المحارف الخاصة. نبدأ بالتعرف على التابع center، الذي نمرر له طول السلسلة النصية الناتجة التي نريدها وسيضمن أنها بالطول المحدد، وذلك بإضافة مسافات بيضاء حول السلسلة نصية التي يُعالجها على النحو التالي:

"Sammy",center(21) # " Sammy "

ويمكننا استبدال المسافات البيضاء بنص معين نريد إضافته بتمريره لذلك التابع مثل وسيط ثانِ على النحو التالي:

" [Sammy] ".center(21, "<>") # "<><><> [Sammy] <><><>"

يضيف التابعان ljust و rjust مسافات بيضاء أو أحرف معينة إلى الجهة اليسرى أو اليمنى من السلسلة النصية ويعملان بالطريقة نفسها التي يعمل بها التابع center:

"Sammy".ljust(20) # "Sammy "
"Sammy".rjust(20) # " Sammy"
"Sammy".rjust(20, "!") # "!!!!!!!!!!!!!!!Sammy"

يمكن استخدام التابع rstrip لإزالة المسافات الزائدة في بداية السلسلة النصية، كما يمكن استخدام التابع lstrip لإزالة المسافات الزائدة في نهاية السلسلة النصية، أما التابع strip فيزيل المسافات الزائدة في كلا الجهتين (البداية والنهاية) من السلسلة النصية:

" Sammy".rstrip # "Sammy"
"Sammy ".lstrip # "Sammy"
" Sammy ".strip # "Sammy"

يمكن أيضًا استخدام التوابع !center و !ljust و !rjust و !lstrip و !rstrip و !strip لتعديل قيمة السلسلة النصية الأصلية، وفي بعض الأحيان قد نحتاج لإزالة الأحرف من نهاية السلسلة النصية لذلك يمكن استخدام التابع chop لإزالة المحرف الأخير من السلسلة النصية:

"Sammy".chop # "Samm"

قد نستفيد من ذلك لإزالة محرف السطر الجديد n\ مثلًا من نهاية سلسلة نصية ما:

"This string has a newline\n".chop

يترك التابع chop السلسلة النصية الأصلية دون تعديل ويعيد قيمة سلسلة نصية جديدة بدون المحرف الأخير، بينما يعدل التابع !chop السلسلة النصية الأصلية بدلًا من إنشاء سلسلة جديدة، ويمكن استخدام التابع chomp لإزالة عدة محارف من نهاية السلسلة النصية على النحو التالي:

"Sammy".chomp("my") # "Sam"

وفي حال لم نحدد السلسلة النصية التي نريد إزالتها من النهاية فسيزيل التابع chomp محرف السطر الجديد n\ فقط:

"This string has a newline\n".chomp # "This string has a newline

وفي حال لم تحتوي السلسلة النصية على محرف السطر الجديد n\ فسيعيد التابع chomp السلسلة النصية الأصلية كما هي دون تعديل:

"Sammy".chomp # "Sammy"

استخدام التابع chomp أسهل لإزالة محارف السطر الجديد n\ من نهاية السلسلة النصية من التابع chop والذي يزيل دائمًا الحرف الأخير مهما كان نوعه، كما توفر لغة روبي التابع !chomp، الذي يعدل قيمة السلسلة النصية الأصلية ويعيد السلسلة النصية المعدلة إذا أزال محارف من نهاية السلسلة، ولكن وعلى عكس التابع chomp فسيعيد التابع !chomp القيمة nil إذا لم يُعدل على السلسلة النصية:

string = "Hello\n"
string.chomp! # "Hello"

string = "Hello"
string.chomp! # nil

سنتعرف في الفقرة التالية على طريقة البحث ضمن السلاسل النصية.

البحث عن المحارف والنصوص

نحتاج أحيانًا لتحديد ما إذا كانت السلسلة النصية تحتوي على نص معين أم لا، لهذا الغرض توفر روبي التابع ?include، الذي يتحقق مما إذا كانت السلسلة النصية تحتوي على سلسلة نصية أخرى، ويعيد القيمة المنطقية true إذا كانت السلسلة النصية تحتوي على السلسلة النصية الأخرى، أو القيمة false في حال لم تحتويها:

"Sammy".include?("a") # true
"Sammy".include?("b") # false

يعيد التابع index رقم الفهرس لمكان محرف أو سلسلة نصية ما، أو يعيد القيمة nil في حال عدم العثور على المحرف أو السلسلة النصية الجزئية ضمنها:

"Sammy".index("a") # 1
"Sammy".index("mm") # 2
"Sammy".index("Fish") # nil

يبحث التابع index عن أول تواجد للمحرف أو السلسلة النصية المطلوبة فقط ويعيد رقم الفهرس له. لنوضح ذلك في المثال التالي على سلسلة نصية طويلة:

text = "Sammy has a balloon"
text.index("a") # 1

تحتوي السلسلة النصية "Sammy has a balloon" على أربعة حروف "a"، ولكن التابع index يعيد فقط موقع أول ظهور لذلك الحرف، ويجب أخذ ذلك بالحسبان عند البحث ضمن السلاسل النصية، ولتحديد كل ظهور للحرف "a" ضمن الجملة السابقة يمكن تحويل السلسلة النصية إلى مصفوفة من الأحرف المكونة لها ثم الاستعانة بتوابع المصفوفة للبحث بين تلك الحروف عن كل مكان لذلك الحرف وتحديد رقم الفهرس له مثلًا على النحو التالي:

text = "Sammy has a balloon"
indices = text.chars
.each_with_index
.select{|char, index| char == "a" }
.map{|pair| pair.last}

print indices
[1, 7, 10, 13]

ليكون الخرج على النحو التالي:

[1, 7, 10, 13]

يعيد التابع each_with_index مصفوفة ثنائية الأبعاد يحتوي كل عنصر منها على الحرف ومكانه ضمن السلسلة النصية، ونختار ضمن التابع select العناصر التي تحتوي على الحرفa، ثم نحول تلك العناصر باستخدام التابع map إلى مصفوفة تحتوي على رقم الفهرس لكل تواجد للحرف a، ويمكن التحقق مما إذا كانت السلسلة النصية تبدأ بحرف أو سلسلة نصية معينة باستخدام التابع ?start_with كما يلي:

text = "Sammy has a balloon"
text.start_with?("s") # true
text.start_with?("Sammy has" # true

يقبل التابع ?start_with سلسلةً نصيةً واحدةً أو أكثر مثل وسطاء له، ويعيد true إذا تطابق أي من تلك السلاسل النصية مع بداية السلسلة الأصلية:

text = "Sammy has a balloon"
text.start_with?("Sammy the Shark", "Sammy") # true

لم يُعثر في هذا المثال على السلسلة النصية "Sammy the Shark"، ولكن عُثر على السلسلة النصية "Sammy"، لذا أرجع التابع القيمة true، وبالمقابل يمكن استخدام التابع ?end_with للتحقق مما إذا كانت السلسلة النصية تنتهي بسلسلة نصية معينة، إذ يعمل هذا التابع بنفس طريقة عمل التابع ?start_with:

text = "Sammy has a balloon"
text.end_with?("balloon") # true
text.end_with?("boomerang") # false
text.end_with?("boomerang", "balloon") # true

بعد أن تعرفنا على طرق البحث ضمن النصوص، سنتعرف في الفقرة التالية على طريقة استبدال أجزاء معينة من السلسلة النصية.

استبدال أجزاء من النص في السلاسل النصية

يمكن البحث عن سلسلة نصية واستبدالها بأخرى باستخدام خاصية البحث والاستبدال المتوفرة عادةً في محررات النصوص التي نستخدمها، ويمكن تنفيذ هذه الميزة في لغة روبي باستخدام التوابع sub و gsub، إذ يبدل التابع sub جزءًا من النص بجزء آخر. سنغيّر في المثال التالي الجزء "has" إلى "had" في الجملة التالية:

balloon = "Sammy has a balloon"
print balloon.sub("has","had")

ليعيد التابع قيمة النص بعد التبديل:

Sammy had a balloon.

يستبدل التابع sub أول ورود للنص المطابق بالنص الجديد فقط. لتوضيح ذلك سنستخدم الجملة التالية المعدّلة التي تحتوي على ورودين للكلمة "has":

balloon = "Sammy has a balloon. The balloon has a ribbon"
print balloon.sub("has","had")

وسيكون الخرج على النحو التالي:

Sammy had a balloon. The balloon has a ribbon

نلاحظ تبديل أول ظهور فقط، ولتبديل جميع الأماكن التي ترد فيها السلسلة النصية يمكن استخدام التابع gsub الذي يبدل على مستوى النص بأكمله:

balloon = "Sammy has a balloon. The balloon has a ribbon"
print balloon.gsub("has","had")
Sammy had a balloon. The balloon had a ribbon

ويكون الخرج:

Sammy had a balloon. The balloon had a ribbon

تعيد التوابع sub و gsub سلسلةً نصيةً جديدةً دون تعديل السلسلة الأصلية، ويمكن توضيح ذلك بتغيير الكلمة "balloon" إلى "boomerang" في السلسلة النصية التالية:

text = "Sammy has a balloon"
text.gsub("ballooon", "boomerang")
print text
Sammy has a balloon

التي تعطي الخرج التالي:

Sammy has a balloon

نلاحظ بقاء النص كما هو على الرغم من إمكانية الاستبدال، وذلك لأننا لم نخزن نتيجة التابع gsub في المتغير مجددًا، وللحصول على النتيجة التي نريدها يمكننا تعديل الشيفرة كما يلي:

text = "Sammy has a balloon"
text = text.sub("ballooon", "boomerang")
print text

أو يمكن استخدام التابع !sub بدلًا من التابع subوالذي يعدل على السلسلة الأصلية بدلًا من إعادة سلسلة جديدة. سنستخدم في المثال التالي التابع !sub لتغيير الجملة "red balloon" إلى "blue boomerang":

text = "Sammy has a red balloon"
text.sub!("red", "blue")
text.sub!("balloon", "boomerang")
print text

ليكون الخرج على النحو التالي:

Sammy has a balloon

يمكن استخدام التابع !gsub لاستبدال كل ورود للنص المحدد والتعديل على قيمة السلسلة النصية الأصلية، ويمكن تمرير التعابير النمطية Regular Expressions -أو اختصارًا regex- للتوابع sub و gsub للبحث عن نمط معين، ففي المثال التالي سنبدل جميع الحروف الصوتية ضمن النص بالرمز @:

"Sammy has a red balloon".gsub(/[aeiou]/, "@")

وسيكون الخرج على النحو التالي:

"S@mmy h@s @ r@d b@ll@@n"

ويمكن تمرير جدول Hash بدلًا من سلسلة نصية ثابتة لتحديد كيفية استبدال كل جزء من النص الوارد بصورةٍ مختلفة، ففي المثال التالي سنبدّل جميع حروف "a" إلى المحرف "@" وجميع الحروف "o" إلى الرقم صفر:

"Sammy has a red balloon".gsub(/[aeiou]/, {"a" => "@", "o" => "0"})
# "S@mmy h@s @ rd b@ll00n"

نلاحظ أن ذلك يمنحنا إمكانية إجراء عمليات تبديل معقدة على النصوص والذي يفيدنا في حل بعض المشاكل المعقدة.

الخاتمة

تعرفنا في هذا المقال على العديد من التوابع التي تسمح لنا بالتعامل مع السلاسل النصية باستخدام توابع مبينة مسبقًا لنوع البيانات الخاص بالسلاسل النصية، ومنها ما كان يترك السلسلة الأصلية دون تعديل ومنها من يعدّل عليها.

يعتمد اختيار التوابع التي سنستخدمها على احتياجاتنا، إذ تمنح لغة روبي المبرمجين المرونة لاختيار التوابع التي تفيدهم في العمل مع البيانات الخاصة بهم، وينصح باستخدام التوابع التي لا تعدل على القيمة الأصلية لأنها أسهل في تطوير البرامج وتجنب الأخطاء.

لمزيد من التفصيل، ارجع إلى صفحة النوع String في موسوعة حسوب.

ترجمة -وبتصرف- للمقال How To Work with String Methods in Ruby لصاحبه Brian Hogan.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...