المسارات
/
R
R
/
التمارين
/
مستويات السجل
مستويات السجل

مستويات السجل

تمرين تعلّمي

مقدمة

خلفية

السلسلة النصية قطعة من النص توضع بين علامات الاقتباس. أي إصدار مدعوم حاليًا من R يرمّز السلاسل النصية بترميز UTF-8، لذا يمكن دعم معظم لغات العالم.

mystring <- "some text"
mystring
#> [1] "some text"
typeof(mystring)
#> [1] "character"

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

على الرغم من أن type هو character، فإن R لا تفرّق بين حرف واحد (يُسمى char في عدة لغات أخرى، ولكن ليس في R) وسلسلة نصية طويلة. كلاهما عنصر واحد، ويمكن وضعه بين علامتي اقتباس مفردتين ' ' أو مزدوجتين " " بالتبادل.

يوصي دليل الأسلوب باستخدام علامات الاقتباس المزدوجة، إلا عندما تريد استخدام علامات اقتباس مزدوجة داخل السلسلة النصية دون تهريبها.

str2 <- 'String with "quotes"'  # convenience format
str2
#> [1] "String with \"quotes\""    # standard format

وبالتالي فإن character vector هو متجه من السلاسل النصية، حيث تكون كل سلسلة نصية عنصرًا واحدًا.

s <- c("some", "strings")
s
#> [1] "some"    "strings"
length(s)
#> [1] 2
length(s[1])  # the number of vector elements, not the string length
#> [1] 1

nchar(s[1])  # the number of characters in the string "some"
#> [1] 4

في المثال أعلاه، length(s[1]) مكافئ لـ length("some"): عدد عناصر المتجه، وليس طول السلسلة النصية.

من الواضح أن التعامل مع سلسلة نصية فردية أمر ممكن، كما في حالة nchar() في المثال أعلاه، لكنه يحتاج إلى دوال معيّنة سنناقشها أدناه.

دوال السلاسل النصية

معظم الأمور ممكنة في R الأساسية، لكن كثيرًا من المبرمجين يرون أن الدعم المتاح للتلاعب بالسلاسل النصية محدود ومربك إلى حد كبير.

لحسن الحظ، هناك حزم tidyverse أكثر بديهية ومرونة واتساقًا مع نفسها.

R الأساسية

لا يزال هناك الكثير من الكود القديم الذي يستخدم دوال السلاسل النصية بالطراز القديم. وهذا يشمل معظم حلول المجتمع على Exercism.

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

لذلك، لا يزال من الجدير تعلّم بعض المعرفة بالأساليب القديمة.

nchar

تُرجع عدد الأحرف في سلسلة نصية.

nchar("string")
#> [1] 6

nchar("Hrōðgār") # a person in Beowulf, written in Old English
#> [1] 7

موضوع معنى "الحرف" (المعقّد!) خارج نطاقنا هنا. انتبه فقط إلى نقطتين في الأمثلة أعلاه:

  • على الرغم من أنها منفّذة داخليًا بلغة C، فإن السلاسل النصية في R لا تنتهي بـ \0 (وهو ما كان سيضيف 1 إلى الطول).
  • تُعالَج أحرف يونيكود متعددة البايتات كما تتوقع أو تأمل. تحتوي "Hrōðgār" على 7 أحرف (تُسمى أيضًا "رونات" أو "نقاط الكود")، لكنها تحتاج إلى 10 بايتات لتُخزَّن.
paste وpaste0

تدمجان عددًا اعتباطيًا من السلاسل النصية في سلسلة نصية واحدة.

ويمكن اختياريًا تحديد فاصل لـ paste: القيمة الافتراضية هي مسافة.

paste0(v) مكافئ لـ paste(v, sep = "").

paste("bits", "of", "a", "string")
#> [1] "bits of a string"
paste0("bits", "of", "a", "string")
#> [1] "bitsofastring"
sprintf

للحصول على تحكّم أدق في تجميع السلاسل النصية، اقتبست R دالة sprintf من C (ومن عدة لغات لاحقة: تسرد ويكيبيديا نحو 30 منها).

r <- 5.3
pi <- 3.14159
sprintf("A circle of radius %.1f has area %.2f", r, pi * r^2)
#> [1] "A circle of radius 5.3 has area 88.25"
trimws

يمكن إزالة المسافات البيضاء في البداية و/أو النهاية باستخدام trimws():

s <- "    messy string   "
trimws(s)
#> [1] "messy string"

هناك معامل which = "left" (أو "right") لتجنّب تقليم الطرفين.

substr

تعمل على سلسلة نصية واحدة وتُرجع سلسلة فرعية بين حدّين (شاملين للطرفين).

substr("Exercism", 5, 7)
#> [1] "cis"
strsplit

تقسّم سلسلة نصية إلى مصفوفة في R، بناءً على سلسلة نصية فاصلة. الفاصل مطلوب (بلا قيمة افتراضية)، لكن يمكن أن يكون سلسلة نصية فارغة.

strsplit("R, Python, Julia", ", ")
[[1]]
#> [1] "R"      "Python" "Julia" 

strsplit("Exercism", "")
[[1]]
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"

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

unlist(strsplit("Exercism", ""))
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"

Tidyverse

بأقصى درجات التسامح، يمكننا القول إن دوال السلاسل النصية بالطراز القديم ليست أفضل ما تقدّمه R (وهناك آراء أقل تسامحًا).

ولتحسين الوضع، ظلّت مكتبة stringr قيد التطوير منذ عام 2009، وهي الآن جزء أساسي من مجموعة Tidyverse.

استوردها إلى نطاقك باستخدام library(stringr) أو library(tidyverse).

من أبرز ميزاتها:

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

ومثل جميع حزم Tidyverse، تتمتع stringr بتوثيق جيد، يكتبه عادةً مؤلف الحزمة أو مؤلفوها.

استطراد: مقدمة سريعة عن الأنابيب

سنناقش استخدام الأنابيب |> لربط الدوال بمزيد من التفصيل في أجزاء أخرى من المنهج.

في الوقت الحالي، من المفيد أن تعرف أن:

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

يوضّح المثال أدناه الصياغة. وستُناقش كل دالة على حدة لاحقًا.

library(stringr)

"Monday-25-February" |> 
  str_split("-") |>     
  unlist() |>               # [1] "Monday"   "25"       "February"
  str_sub(1, 3) |>          # [1] "Mon" "25"  "Feb"
  str_to_upper() |>         # [1] "MON" "25"  "FEB"
  str_flatten(collapse = ", ")
#> [1] "MON, 25, FEB"
إدارة الأطوال

تُحصي str_length نقاط الكود (على غرار nchars).

وتتعامل دوال أخرى متنوعة مع المسافات البيضاء، بما في ذلك str_trim() وstr_squish(). وغالبًا ما تكون هذه مهمة تنظيف بالغة الأهمية في بداية أي مشروع لعلم البيانات.

# The first 3 kernels in JuPyteR notebooks:
str_length(c("Julia", "Python", "R"))           #> [1] 1 6 5
#> [1] 5 6 1
str_pad(c("Julia", "Python", "R"), 8, "right")  # add spaces if necessary
#> [1] "Julia   " "Python  " "R       "

str_trim("Julia    Python    R    ")   # remove leading & trailing whitespace
#> [1] "Julia    Python    R"
str_squish("Julia   Python  R    ")  # trim, collapse multiple spaces 
#> [1] "Julia Python R"
استخراج أجزاء من السلاسل النصية

تُرجع الدالة str_sub(string, start, end) السلسلة الفرعية من start إلى end (شاملًا الطرفين)، بينما يمكن لـ str_sub_all() العمل على عدة سلاسل نصية.

هناك مرونة كبيرة. تكون القيمة الافتراضية لـ start وend هي الحرف الأول والأخير على الترتيب. ويمكن أن تكونا متجهين من الفهارس. وعلى عكس فهرسة المتجهات، وهو أمر مريح، تُحسب القيم السالبة من نهاية السلسلة النصية، على طريقة Python.

s <- "abcdefgh"
str_sub(s, 2, 4)
#> [1] "bcd"
str_sub(s, 5)
#> [1] "efgh"
str_sub(s, -3, -2)
#> [1] "fg"
str_sub(s, c(1, 4), c(2, 5))
#> [1] "ab" "de"
str_sub(s, c(1, 4, 6), c(2, 5, -1))
#> [1] "ab"  "de"  "fgh"

s |> str_sub(2, 4) # these functions are designed for pipes
#> [1] "bcd"
دمج السلاسل النصية

تحوّل str_flatten متجهًا من الأحرف إلى سلسلة نصية واحدة. يُدرج الوسيط collapse بين كل عنصر وعنصر، وقيمته الافتراضية "".

c("R", "Julia", "Python") |> str_flatten()
#> [1] "RJuliaPython"
c("R", "Julia", "Python") |> str_flatten(collapse = " - ")
#> [1] "R - Julia - Python"

تحوّل str_c عدة متجهات أحرف إلى متجه أحرف واحد، مع إعادة التدوير عند الحاجة.

str_c(LETTERS[1:8], 1:8, sep = ":")
#> [1] "A:1" "B:2" "C:3" "D:4" "E:5" "F:6" "G:7" "H:8"

تضيف str_glue إقحام السلاسل النصية البسيط إلى R. تُفسَّر التعبيرات داخل الأقواس المعقوفة { } ويُستبدل بها تمثيلها النصي.

r <- 5.3
pi <- 3.14159
str_glue("A circle of radius {r} has area {pi * r^2}")
A circle of radius 5.3 has area 88.2472631
تقسيم السلاسل النصية

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

str_split_1 هي الأبسط، إذ تحوّل سلسلة نصية واحدة إلى متجه من القطع، مقسّمة عند نمط محدّد (لا يوجد نمط افتراضي).

s <- "R Julia Python"
str_split_1(s, " ")
#> [1] "R"      "Julia"  "Python"
تعديل السلاسل النصية

تميّز بعض اللغات (الأوروبية أساسًا) بين الأحرف الكبيرة والأحرف الصغيرة. وهناك مجموعة من دوال stringr للتحويل بينها، بطرق تناسب الإعدادات المحلية:

  • str_to_lower()
  • str_to_upper()
  • str_to_title() : الحرف الأول من كل كلمة إلى حرف كبير
  • str_to_sentence() : الحرف الأول من الجملة إلى حرف كبير
str_to_upper("elixir")    # defaults to locale = "en"
#> [1] "ELIXIR"
str_to_upper("ελληνικά")  # infers Greek
#> [1] "ΕΛΛΗΝΙΚΆ"

str_to_title("the cat sat on the mat")
#> [1] "The Cat Sat On The Mat"
str_to_sentence("the cat sat on the mat")
#> [1] "The cat sat on the mat"

لاستبدال سلسلة فرعية بناءً على مطابقة نمط، تغيّر str_replace() أول ظهور للنمط، وتغيّر str_replace_all() جميع مرات الظهور.

ولاستبدال سلسلة فرعية بناءً على فهرسة الأحرف، هناك صيغة إسناد للدالة str_sub().

 s <- "abcde"
str_sub(s, 3, 4) <- "yz"
s
#> [1] "abyze"

التعليمات

في هذا التمرين ستتعامل مع أسطر السجل.

كل سطر سجل هو سلسلة نصية بالتنسيق التالي: "[<LEVEL>]: <MESSAGE>".

هناك ثلاثة مستويات سجل مختلفة:

  • INFO
  • WARNING
  • ERROR

لديك ثلاث مهام، كل مهمة منها تأخذ سطر سجل وتطلب منك فعل شيء به.

لك مطلق الحرية في استخدام الدوال القديمة من base R أو مكتبة stringr، وكلاهما يمكن أن يقدّم حلولًا قصيرة وقابلة للتطبيق.

1. استخرج الرسالة من سطر السجل

نفّذ دالة message لتُرجع رسالة سطر السجل:

message("[ERROR]: Invalid operation")
#> "Invalid operation"

يجب إزالة أي مسافات بيضاء في البداية أو النهاية:

message("[WARNING]:  Disk almost full\r\n")
#> "Disk almost full"

2. استخرج مستوى السجل من سطر السجل

نفّذ دالة log_level لتُرجع مستوى السجل الخاص بسطر السجل، ويجب أن يكون بأحرف صغيرة:

log_level("[ERROR]: Invalid operation")
#> "error"

3. أعد تنسيق سطر السجل

نفّذ دالة reformat التي تعيد تنسيق سطر السجل، فتضع الرسالة أولًا ويليها مستوى السجل بين الأقواس الهلالية:

reformat("[INFO]: Operation completed")
#> "Operation completed (info)"
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
R Exercism

مستعد لبدء مستويات السجل؟

سجّل في Exercism لتتعلّم وتتقن R عبر 21 مفهومًا111 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.