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

التعامل مع السلاسل في لغة جو Go


هدى جبور

تُعَدّ السلسلة النصية تسلسلًا من محرف واحد -أي حرف أبجدي أو عدد أو رمز- أو أكثر ويمكن أن تكون ثابتًا constant أو متغيرًا variable، كما تتبع السلاسل النصية الترميز الموحد يونيكود Unicode (معيار يُمكّن الحواسيب من تمثيل النصوص المكتوبة بأغلب نظم الكتابة ومعالجتها، بصورة متناسقة).

تُعَدّ السلاسل النصية في جو غير قابلة للتغيير Immutable، وهو المصطلح المعاكس لمصطلح Mutable الذي يشير إلى أنواع البيانات التي يمكن التعديل على القيم التي تحتويها حتى بعد إنشاءها. أي أنه وبعد إنشاء نوع البيانات وتخزينه في الذاكرة، يمكن التعديل على بياناته.

تدخل النصوص في كل شيء، لذا فإن نوع البيانات الذي هو السلسلة النصية string مهم جدًا في كل لغات البرمجة، وستتعلم في هذا المقال كيفية إنشاء السلاسل وطباعتها وربطها وتكرارها وتخزينها في متغيرات.

صياغة السلاسل النصية String Literals

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

وستتعرف فيما يلي على بعض الطرق التي يمكنك من خلالها تمثيل السلاسل النصية بالصياغة المطلوبة في جو، ولكن يجب عليك في البداية فهم الفرق بين صياغة السلسلة النصية وقيمتها؛ فالسلسلة النصية مع صياغتها هي ما نراه في الشيفرة المصدرية لبرنامج الحاسوب بما في ذلك علامتَي الاقتباس مثلًا؛ أما قيمة السلسلة، فهي ما نراه عند التعامل مع السلسلة عند تشغيل البرنامج مثل استدعاء الدالة fmt.Println معها، ففي برنامج طباعة النص "Hello, World!‎" مثلًا، تكون صياغة السلسلة هي "Hello, World!‎" وقيمتها هي Hello, World!‎، أي بدون علامتَي الاقتباس. إذًا قيمة السلسلة هي ما تراه خرجًا على نافذة الطرفية عند تشغيل برنامج جو.

قد تحتاج في بعض الأحيان إلى تضمين علامتَي الاقتباس بحيث تظهر في قيمة السلسلة عندما تقتبس من مصدر مثلًا، ولكن بما أنّ صياغة السلسلة وقيمتها غير متكافئين، فستحتاج غالبًا لإضافة تنسيق محدد إلى السلسلة لضمان ظهور علامة الاقتباس في قيمة السلسلة كما هو متوقع.

علامات الاقتباس وتفسيرها

تتيح لغة جو Go استخدام علامات الاقتباس الخلفية ` أو علامات الاقتباس المزدوجة " لتعريف السلاسل النصية، فبالتالي عندما ترغب باستخدام علامات الاقتباس المزدوجة، فيمكنك تضمينها ضمن سلسلة تستخدِم علامات اقتباس خلفية والعكس بالعكس كما في المثال التالي:

`Sammy says, "Hello!"`

أو الحالة المعاكسة:

"Sammy likes the `fmt` package for formatting strings.."

يمكنك بهذه الطريقة الجمع بين علامات الاقتباس الخلفية والمزدوجة والتحكم في عرض علامات الاقتباس داخل السلسلة النصية، لكن تذكّر أنّ استخدام علامات الاقتباس الخلفية في جو سيؤدي إلى إنشاء سلسلة نصية أولية raw string literal واستخدام علامات الاقتباس المزدوجة سيؤدي إلى إنشاء سلسلة نصية مُفسّرة interpreted string literal.

محارف الهروب Escape Characters

يمكنك استخدام محارف خاصة داخل السلاسل النصية لها معنى خاص بالنسبة للغة جو مثل " ولكن ماذا لو أردنا استعمال علامة الاقتباس " نفسها ضمن سلسلة نصية؟ نلجأ هنا إلى مفهوم الهروب والذي يعني إخبار المُصرِّف أن لا يفسر المحرف التالي له بمعناه الخاص مثل تهريب علامة الاقتباس " والعكس أيضًا أي إعطاء معنى خاص مع محارف محددة إن وجدت ضمن السلسلة النصية مثل محرف السطر الجديد ‎\n، إذ تبدأ جميع محارف الهروب بمفتاح الشرطة المائلة للخلف \ يليها مباشرةً المحرف المراد تهريبه داخل السلسلة، ومن أبرز حالات استعمال محرف التهريب:

  • \: تهريب تفسير الشرطة المائلة \ بمعناها الخاص أي محرف التهريب نفسه.
  • "\: تهريب علامة اقتباس مزدوجة.
  • n\: إعطاء الحرف n معنى خاص وهو تفسيره إلى الانتقال إلى السطر التالي (أول حرف من كلمة new line أي سطر جديد) أي كأنك تضغط على حرف الإدخال enter.
  • t\: إعطاء الحرف t معنى خاص وهو مفتاح الجدولة Tab، أي تفسيره بمسافة بادئة أفقية.

سنستخدِم في المثال التالي محرف الهروب "\ لإضافة علامات الاقتباس:

fmt.Println("Sammy says, \"Hello!\"")

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

Sammy says, "Hello!"

إذًا باستخدام محرف الهروب "\ يمكنك استخدام علامات الاقتباس المزدوجة لإحاطة سلسلة تتضمن نصًا بين علامتَي اقتباس مزدوجتين، وسنستخدم الآن محرف هروب آخر وهو n\ للانتقال إلى السطر التالي:

fmt.Println("This string\nspans multiple\nlines.")

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

This string
spans multiple
lines.

يمكنك أيضًا استخدام عدة محارف هروب ضمن السلسلة في الوقت نفسه كما في المثال التالي:

fmt.Println("1.\tShark\n2.\tShrimp\n10.\tSquid")

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

1.      Shark
2.      Shrimp
10.     Squid

يساعدك محرف الهروب t\ في عرض البيانات المُجدولة بمحاذاة أفقية واحدة، إذ يستبدلها المُصرِّف بمسافة بادئة أفقية بطول ثابت مما يساعدك في جعل البيانات المعروضة قابلة للقراءة بوضوح.

تُستخدَم محارف الهروب لإضافة تنسيق إضافي إلى السلاسل التي قد تكون من الصعب أو المستحيل تحقيقها، إذ لن تتمكن بدون محارف الهروب من إنشاء سلسلة مثل Sammy says, "I like to use the fmt package"‎.

السلسلة النصية الأولية raw string literal

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

سننشئ هنا سلسلةً أوليةً باستخدام علامتَي الاقتباس الخلفية:

fmt.Println(`Sammy says,\"The balloon\'s color is red.\"`)

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

Sammy says,\"The balloon\'s color is red.\"

نستنتج أنّ استخدام سلسلة نصية أولية يؤدي إلى تجاهل علامات الاقتباس وأية محارف وتنسيقات خاصة يمكن للغة جو أن تفسرها بمعنى مختلف، وبالتالي يمكنك الاحتفاظ بالشرطة المائلة العكسية والمحارف الأخرى التي تُستخدم على أساس محارف هروب.

السلاسل النصية المفسرة

هي سلسلة نصية موضوعة بين علامتي اقتباس مزدوجتين "..". كل شيء موجود بداخل علامتي الاقتباس سيُعرض باستثناء الأسطر الجديدة (المُعبر عنها بالرمز n\) وعلامات الاقتباس المزدوجة. في حال أردت أن تظهر هذه الرموز أيضًا، يمكنك استخدام مفتاح الهروب (أو الإلغاء) / قبلها. مثال:

fmt.Println("Say \"hello\" to Go!")

الخرج:

Say "hello" to Go!

غالبًا ستستخدم السلاسل المُفسرة لأنها تتعامل مع المحارف الخاصة وتسمح بتخطيها أيضًا (تحكم أكبر).

طباعة السلاسل النصية على عدة أسطر

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

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

`
This string is on
multiple lines
within three single
quotes on either side.
`

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

This string is on
multiple lines
within three single
quotes on either side.

لاحظ أنّ هناك سطر بداية ونهاية فارغين، ولتجنب ذلك ضع السطر الأول فورًا بعد علامة الاقتباس الخلفي وفي السطر الأخير ضع علامة الاقتباس الخلفي مباشرةً بعد آخر كلمة.

`This string is on
multiple lines
within three single
quotes on either side.`

إذا كنت بحاجة إلى إنشاء سلسلة مفسرة متعددة الأسطر، فيمكنك إنجاز ذلك بعلامتَي اقتباس مزدوجة واستخدام العامِل +، ولكن ستحتاج إلى إدخال فواصل الأسطر من خلال محرف الهروب في الأماكن التي تريدها كما في المثال التالي:

"This string is on\n" +
"multiple lines\n" +
"within three single\n" +
"quotes on either side."

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

طباعة السلاسل

يمكنك طباعة السلاسل باستخدام حزمة fmt من مكتبة النظام ثم استدعاء الدالة ()Println منها:

fmt.Println("Let's print out this string.")

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

Let's print out this string.

يجب عليك استيراد حزم النظام عند استخدامها، وبالتالي سيكون البرنامج اللازم لطباعة السلسلة كما يلي:

package main

import "fmt"

func main() {
    fmt.Println("Let's print out this string.")
}

ربط السلاسل

يُقصَد بربط السلاسل Concatenation ضم أو وصل السلاسل معًا من طرف إلى طرف لإنشاء سلسلة جديدة، إذ يمكنك ربط السلاسل باستخدام العامِل +، وضَع في الحسبان أنه عند التعامل مع الأرقام سيكون العامل + عاملًا للجمع، ولكن عند استخدامه مع السلاسل فهو عامل ربط.

سنربط في المثال التالي السلسلة "Sammy" والسلسلة "Shark" لإنشاء سلسلة نصية جديدة، وسنطبع الناتج مباشرةً من خلال دالة الطباعة كما يلي:

fmt.Println("Sammy" + "Shark")

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

SammyShark

يمكنك إضافة مسافة فارغة للفصل بين الكلمتَين من خلال إضافتها بين علامتي الاقتباس بعد الكلمة الأولى كما يلي:

fmt.Println("Sammy " + "Shark")

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

Sammy Shark

لا يمكنك استخدام العامل + بين نوعين مختلفين من البيانات، فلا يمكنك مثلًا ربط السلاسل والأعداد الصحيحة معًا، وإذا حاولت ذلك:

fmt.Println("Sammy" + 27)

فسيظهر الخطأ التالي:

cannot convert "Sammy" (type untyped string) to type int
invalid operation: "Sammy" + 27 (mismatched types string and int)

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

عندما تربط سلسلتين فهذا يعني أنك ستُنشئ سلسلةً جديدةً يمكنك استخدامها في جميع أنحاء برنامجك.

تخزين السلاسل في المتغيرات

المتغيرات هي مفهوم برمجي هام يشير إلى القيم ونوع القيم التي تستخدمها في برنامجك. يحدد نوع المتغير (نوع البيانات) نوع القيم التي يمكنه تخزينها والعمليات التي يمكن إجراؤها عليه، إذ يمكنك التفكير فيها على أساس صندوق فارغ يمكنك ملؤه بقيمة أو ببيانات، كما تُعَدّ السلاسل النصية بيانات، لذا يمكنك استخدامها لملء متغير، كما يسهِّل استخدام المتغيرات لتخزين السلاسل العمل مع السلاسل في أي برنامج.

لتخزين سلسلة داخل متغير، ما عليك سوى إسناد السلسلة إلى متغير من النوع string، وسنخزّن هنا مثلًا سلسلةً داخل المتغير الذي اسميناه s، كما يمكنك استخدام أيّ اسم تراه مُعبّرًا، لكن يُفضل الأسماء القصيرة:

s := "Sammy likes declaring strings."

يمكنك الآن طباعة هذا المتغير الذي يُمثّل السلسلة السابقة:

fmt.Println(s)

سيكون الخرج:

Sammy likes declaring strings.

يُسهّل عليك استخدام المتغيرات مع السلاسل معالجة السلاسل والتعامل معها كثيرًا، فكل ما عليك فعله هو تخزينها في متغير مرةً واحدة لتتمكن من استخدام هذا المتغير الذي يحملها في أيّ مكان في برنامجك.

التعامل مع السلاسل النصية ومعالجتها

تحتوي حزمة strings في جو على العديد من الدوال المتاحة للعمل مع نوع بيانات السلسلة النصية string، إذ تمكّنك هذه الدوال من تعديل السلاسل والتعامل معها بسهولة، إذ تُعَدّ هذه الدوال إجراءات تتمثل بمجموعة من التعليمات البرمجية التي تُطبق على السلاسل لأهداف مختلفة. حزمة السلاسل في جو هي حزمة مدمجة (مُضمنة في الشيفرة المصدر) وبالتالي عند تثبيت جو تُثبّت معها، وبما أنها حزمة مُدمجة فهذا يعني أن كل الدوال التابعة لها مدمجة أيضًا ومتاحة للعمل مباشرةً، وستتعرف فيما يلي هذه الدوال وستتعلم كيفية استخدامها.

تبديل حالة الأحرف من صغير إلى كبير والعكس

تُستخدَم الدالتان strings.ToUpper و strings.ToLower للتبديل بين حالتَي الأحرف الكبيرة والصغيرة، حيث تحوّل الدالة الأولى كل محارف السلسلة الأولى المُعطاة إلى الحالة الكبيرة وتعيدها على أساس سلسلة جديدة وبالطبع إذا كان الحرف كبير أصلًا، فلن يتغير، في حين تحوّل الدالة الثانية المحارف إلى الحالة الصغيرة وتعيدها على أساس سلسلة جديدة.

سنحوّل في المثال التالي كل محارف السلسلة "Sammy Shark" إلى حالتها الكبيرة:

ss := "Sammy Shark"
fmt.Println(strings.ToUpper(ss))

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

SAMMY SHARK

يمكنك أيضًا تحويلها إلى الحالة الصغيرة:

fmt.Println(strings.ToLower(ss))

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

sammy shark

بما أنك تستخدم دوال السلاسل، فلابد أن ستستورد الحزمة أولًا، وإلا فلن يتعرّف المُصرِّف على تلك الدوال:

package main

import (
    "fmt"
    "strings"
)

func main() {
    ss := "Sammy Shark"
    fmt.Println(strings.ToUpper(ss))
    fmt.Println(strings.ToLower(ss))
}

تفيد الدالتان strings.ToUpper و strings.ToLower كثيرًا في حالة مقارنة وتقييم السلاسل، لأنه يجعل حالة المحارف بحالة متسقة، فإذا قارنت مثلًا بين كلمتَي Sammy و sammy، فستكون النتيجة أنهما غير متماثلتان لأن جو حساسة لحالة الأحرف سواءً كان ذلك بالنسبة للقيم أو المتغيرات، لكن إذا طبقت الدالة strings.ToLower على الكلمة الأولى قبل المقارنة، فسيكون الناتج أنهما متماثلتان، ومن هنا تأتي أهميتهما.

دوال البحث في السلاسل

تحتوي حزمة السلاسل النصية في جو على العديد من الدوال التي تمكّنك من إنجاز عمليات البحث في السلاسل مثل البحث عن تسلسل محدد من المحارف داخل سلسلة ما، ومن أشهر هذه الدوال:

  • strings.HasPrefix تبحث في السلسلة من بدايتها.
  • strings.HasSuffix تبحث في السلسلة من نهايتها.
  • strings.Contains تبحث في أيّ مكان في السلسلة.
  • strings.Count تعيد عدد المرات التي ظهرت بها السلسلة ضمن السلسلة المعطاة.

تسمح لك الدالة الأولى والثانية بالبحث عن محرف أو سلسلة من المحارف المحددة في بداية أو نهاية السلسلة، أي اختبار فيما إذا كانت تنتهي أو تبدأ بمجموعة من المحارف، فلاختبار فيما إذا كانت السلسلة "Sammy Shark" تبدأ بكلمة Sammy وتنتهي بكلمة Shark مثلًا، سنكتب ما يلي:

ss := "Sammy Shark"
fmt.Println(strings.HasPrefix(ss, "Sammy"))
fmt.Println(strings.HasSuffix(ss, "Shark"))

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

true
true

يمكنك استخدام الدالة strings.Contains مثلًا لاختبار احتوائها على السلسلة "Sh":

fmt.Println(strings.Contains(ss, "Sh"))

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

true

يمكنك أيضًا حساب عدد مرات ظهور المحرف S في السلسلة Sammy Shark:

fmt.Println(strings.Count(ss, "S"))

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

2

سنجرب الآن حساب عدد مرات ظهور الحرف s بالحالة الصغيرة:

fmt.Println(strings.Count(ss, "s"))

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

0

ملاحظة: تذكّر ما أشرنا إليه سابقًا بخصوص حساسية جو لحالة الأحرف، فهذا سيُفسّر نتيجة الخرجَين السابقَين.

تحديد طول السلسلة

تُستخدَم الدالة len لحساب عدد المحارف الموجودة ضمن سلسلة نصية ما -أي طولها-، وهذه الدالة مفيدة في الكثير من الحالات مثل معرفة طول السلسلة أو قص السلاسل الأطول من طول محدد أو إذا لإجبار المستخدِم على إدخال طول محدد لكلمة المرور، وفي المثال التالي سنحسب طول سلسلة محددة:

import (
    "fmt"
    "strings"
)

func main() {
        openSource := "Sammy contributes to open source."
        fmt.Println(len(openSource))
}

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

33

في المثال أعلاه أسندنا السلسلة "Sammy contributes to open source.‎" إلى المتغير openSource ثم مررنا المتغير openSource إلى الدالة len لحساب طولها ووضعناها ضمن الدالة fmt.Println لطباعة النتيجة مباشرةً، ويجب أن تضع في ذهنك أنّ الدالة len ستحسب طول السلسلة مع احتساب أي شيء ضمنها مثل الرموز والأرقام والفراغات …إلخ.

دوال معالجة السلاسل النصية وتعديلها

توجد دوال إضافية للتعامل مع السلاسل مثل strings.Join و strings.Split و strings.ReplaceAll، إذ تستخدَم الدالة strings.Join لربط شريحة من السلاسل مع بعضها مع إمكانية فصلها بفاصل محدد كما في المثال التالي:

fmt.Println(strings.Join([]string{"sharks", "crustaceans", "plankton"}, ","))

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

sharks,crustaceans,plankton

كان الفاصل هنا هو فاصلة ","، كما يمكنك مثلًا إضافة فراغ بعد الفاصلة أيضًا كما يلي:

strings.Join([]string{"sharks", "crustaceans", "plankton"}, ", ")

يمكنك استخدام الدالة strings.Split أيضًا لتقسيم السلاسل اعتمادًا على فاصل محدد كما في المثال التالي:

balloon := "Sammy has a balloon."
s := strings.Split(balloon, " ")
fmt.Println(s)

سيكون الخرج شريحةً من السلاسل كما يلي:

[Sammy has a balloon]

قد يكون من الصعب تحديد محتوى هذه الشريحة بمجرد النظر إليه باستخدام الدالة strings.Println، لذا يمكنك استخدام الدالة fmt.Printf مع الرمز q% لطباعة السلاسل مع علامتَي الاقتباس كما يلي:

fmt.Printf("%q", s)

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

["Sammy" "has" "a" "balloon."]

توجد دالة أخرى مشابهة للدالة السابقة هي strings.Fields، لكن هذه الدالة تتجاهل أيّة فراغات في السلسلة وبالتالي لا تقسم إلى الحقول الفعلية:

data := "  username password     email  date"
fields := strings.Fields(data)
fmt.Printf("%q", fields)

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

["username" "password" "email" "date"]

تستخدَم الدالة strings.ReplaceAll لاستبدال محرف أو عدة محارف في السلسلة بمحرف جديد أو أكثر، إذ سنمرر لهذه الدالة السلسلة المطلوب تعديلها على أساس وسيط أول، ففي المثال التالي سنمرر المتغير balloon الذي يحمل القيمة Sammy has a balloon ثم سنمرر لها السلسلة المطلوب استبدالها وهي has ثم السلسة البديلة وهي had كما يلي:

fmt.Println(strings.ReplaceAll(balloon, "has", "had"))

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

Sammy had a balloon.

سيكون لديك تحكم كبير في السلاسل من خلال الدوال السابقة.

الخاتمة

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

ترجمة -وبتصرف- للمقال An Introduction to Working with Strings in Go ومقال How To Format Strings in Go ومقال An Introduction to the Strings Package in Go لصاحبها Gopher Guides.

اقرأ أيضًا


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

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

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



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

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

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

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   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.


×
×
  • أضف...