السلسلة النصية قطعة من النص توضع بين علامات الاقتباس. أي إصدار مدعوم حاليًا من 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 أكثر بديهية ومرونة واتساقًا مع نفسها.
لا يزال هناك الكثير من الكود القديم الذي يستخدم دوال السلاسل النصية بالطراز القديم. وهذا يشمل معظم حلول المجتمع على Exercism.
بالإضافة إلى ذلك، قد يكون من المفيد في المهام الصغيرة استخدام دوال مدمجة بدلًا من استيراد مكتبة كبيرة. يميل القائمون على مسار R إلى اتباع هذا الأسلوب عند كتابة حلول نموذجية للتحقق من صحة التمارين.
لذلك، لا يزال من الجدير تعلّم بعض المعرفة بالأساليب القديمة.
ncharتُرجع عدد الأحرف في سلسلة نصية.
nchar("string")
#> [1] 6
nchar("Hrōðgār") # a person in Beowulf, written in Old English
#> [1] 7
موضوع معنى "الحرف" (المعقّد!) خارج نطاقنا هنا. انتبه فقط إلى نقطتين في الأمثلة أعلاه:
\0 (وهو ما كان سيضيف 1 إلى الطول).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"
بأقصى درجات التسامح، يمكننا القول إن دوال السلاسل النصية بالطراز القديم ليست أفضل ما تقدّمه R (وهناك آراء أقل تسامحًا).
ولتحسين الوضع، ظلّت مكتبة stringr قيد التطوير منذ عام 2009، وهي الآن جزء أساسي من مجموعة Tidyverse.
استوردها إلى نطاقك باستخدام library(stringr) أو library(tidyverse).
من أبرز ميزاتها:
str_ وتحاول توضيح الغرض منها.ومثل جميع حزم Tidyverse، تتمتع stringr بتوثيق جيد، يكتبه عادةً مؤلف الحزمة أو مؤلفوها.
سنناقش استخدام الأنابيب |> لربط الدوال بمزيد من التفصيل في أجزاء أخرى من المنهج.
في الوقت الحالي، من المفيد أن تعرف أن:
يوضّح المثال أدناه الصياغة. وستُناقش كل دالة على حدة لاحقًا.
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>".
هناك ثلاثة مستويات سجل مختلفة:
INFOWARNINGERRORلديك ثلاث مهام، كل مهمة منها تأخذ سطر سجل وتطلب منك فعل شيء به.
لك مطلق الحرية في استخدام الدوال القديمة من base R أو مكتبة stringr، وكلاهما يمكن أن يقدّم حلولًا قصيرة وقابلة للتطبيق.
نفّذ دالة message لتُرجع رسالة سطر السجل:
message("[ERROR]: Invalid operation")
#> "Invalid operation"
يجب إزالة أي مسافات بيضاء في البداية أو النهاية:
message("[WARNING]: Disk almost full\r\n")
#> "Disk almost full"
نفّذ دالة log_level لتُرجع مستوى السجل الخاص بسطر السجل، ويجب أن يكون بأحرف صغيرة:
log_level("[ERROR]: Invalid operation")
#> "error"
نفّذ دالة reformat التي تعيد تنسيق سطر السجل، فتضع الرسالة أولًا ويليها مستوى السجل بين الأقواس الهلالية:
reformat("[INFO]: Operation completed")
#> "Operation completed (info)"
سجّل في Exercism لتتعلّم وتتقن R عبر 21 مفهومًا111 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.